GGGravityImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by Bier on October 17, 1985 3:16:06 pm PDT
Contents: Procedures which take a test point and map it to a point on a nearby set of objects.
DIRECTORY
GGCircles,
GGLines,
GGGravity,
GGModelTypes,
GGInterfaceTypes,
GGObjects,
GGRefresh,
GGShapes,
GGVector,
Imager,
Real,
RealFns;
GGGravityImpl: CEDAR PROGRAM
IMPORTS GGCircles, GGLines, GGObjects, GGRefresh, GGShapes, GGVector, Imager, RealFns
EXPORTS GGGravity =
BEGIN
Angle: TYPE = GGModelTypes.Angle;
BoundBox: TYPE = GGModelTypes.BoundBox;
Camera: TYPE = GGModelTypes.Camera;
Circle: TYPE = GGModelTypes.Circle;
Edge: TYPE = GGModelTypes.Edge;
FeatureData: TYPE = REF FeatureDataObj;
FeatureDataObj: TYPE = GGGravity.FeatureDataObj;
GargoyleData: TYPE = GGInterfaceTypes.GargoyleData;
JointGenerator: TYPE = GGObjects.JointGenerator;
Line: TYPE = GGModelTypes.Line;
ObjectBag: TYPE = REF ObjectBagObj;
ObjectBagObj: TYPE = GGGravity.ObjectBagObj;
Segment: TYPE = GGModelTypes.Segment;
SegmentGenerator: TYPE = GGObjects.SegmentGenerator;
Sequence: TYPE = GGModelTypes.Sequence;
SymmetryGroup: TYPE = GGGravity.SymmetryGroup;
Traj: TYPE = GGModelTypes.Traj;
Point: TYPE = GGModelTypes.Point;
Vector: TYPE = GGModelTypes.Vector;
Map: PUBLIC PROC [testPoint: Point, criticalR: REAL, environ: ObjectBag, gargoyleData: GargoyleData] RETURNS [resultPoint: Point, feature: FeatureData] = {
Calls one of the procedures below, depending on the current gravity type.
SELECT gargoyleData.hitTest.gravityType FROM
strictDistance =>
[resultPoint, feature] ← StrictDistance[testPoint, criticalR, environ];
innerCircle =>
[resultPoint, feature] ← InnerCircle[testPoint, criticalR, gargoyleData.hitTest.innerR, environ];
sectors =>
[resultPoint, feature] ← Sector[testPoint, criticalR, environ];
none => {
resultPoint ← testPoint;
feature ← NIL;
};
ENDCASE => ERROR;
};
Snapping to Nearby Objects
NotYetImplemented: PUBLIC ERROR = CODE;
NearestSegment: PROC [testPoint: Point, seq: Sequence, tolerance: REAL] RETURNS [bestDist: REAL, bestSeg: NAT, bestPoint: Point, success: BOOL] = {
thisDist2, bestDist2: REAL;
thisPoint: Point;
segGen: SegmentGenerator;
thisSuccess: BOOL;
next: GGObjects.SegAndIndex;
success ← FALSE;
segGen ← GGObjects.SegmentsInSequence[seq];
next ← GGObjects.NextSegmentAndIndex[segGen];
IF next.seg = NIL THEN { -- The sequence is a single joint
bestDist ← 99999.0; -- magic number meaning no segment
bestSeg ← 999; -- magic number for debugging
bestPoint ← [-1.0, -1.0];
RETURN;
};
[bestPoint, thisSuccess] ← next.seg.class.closestPoint[next.seg, testPoint, tolerance];
IF NOT thisSuccess THEN {
bestDist2 ← 99999.0;
bestSeg ← 999;
bestPoint ← [-1.0, -1.0];
}
ELSE {
bestDist2 ← GGVector.DistanceSquared[bestPoint, testPoint];
bestSeg ← 0;
success ← TRUE;
};
FOR next ← GGObjects.NextSegmentAndIndex[segGen], GGObjects.NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO
[thisPoint, thisSuccess] ← next.seg.class.closestPoint[next.seg, testPoint, tolerance];
IF NOT thisSuccess THEN {
thisDist2 ← 99999.0;
thisPoint ← [-1.0, -1.0];
}
ELSE {
thisDist2 ← GGVector.DistanceSquared[thisPoint, testPoint];
success ← TRUE;
};
IF thisDist2 < bestDist2 THEN {
bestDist2 ← thisDist2;
bestSeg ← next.index;
bestPoint ← thisPoint;
};
ENDLOOP;
bestDist ← RealFns.SqRt[bestDist2];
};
NearestJoint: PROC [testPoint: Point, seq: Sequence] RETURNS [bestDist: REAL, bestJoint: NAT, bestPoint: Point] = {
Finds the nearest joint of traj to testPoint (and its distance from testPoint).
thisPoint: Point;
thisDist2, bestDist2: REAL;
index: INT;
jointGen: JointGenerator;
jointGen ← GGObjects.JointsInSequence[seq];
index ← GGObjects.NextJoint[jointGen];
bestPoint ← GGObjects.FetchJointPos[seq.traj, index];
bestDist2 ← GGVector.DistanceSquared[bestPoint, testPoint];
bestJoint ← index;
FOR index ← GGObjects.NextJoint[jointGen], GGObjects.NextJoint[jointGen] UNTIL index = -1 DO
thisPoint ← GGObjects.FetchJointPos[seq.traj, index];
thisDist2 ← GGVector.DistanceSquared[thisPoint, testPoint];
IF thisDist2 < bestDist2 THEN {
bestDist2 ← thisDist2;
bestJoint ← index;
bestPoint ← thisPoint;
};
ENDLOOP;
bestDist ← RealFns.SqRt[bestDist2];
};
EmptyBag: PROC [objectBag: ObjectBag] RETURNS [BOOL] = {
RETURN[
objectBag.seqs = NIL AND
objectBag.slopeLines = NIL AND
objectBag.symmetryLines = NIL AND
objectBag.radiiCircles = NIL AND
objectBag.distanceLines = NIL AND
objectBag.vectors = NIL AND
objectBag.intersectionPoints = NIL];
};
UpdateBestCurve: PROC [thisCurve, bestCurve: GoodCurve] = {
bestCurve.dist ← thisCurve.dist;
bestCurve.segNum ← 999; -- magic number for debugging
bestCurve.point ← thisCurve.point;
bestCurve.featureData ← thisCurve.featureData;
};
UpdateBestPoint: PROC [thisPoint, bestPoint: GoodPoint] = {
bestPoint.dist ← thisPoint.dist;
bestPoint.point ← thisPoint.point;
bestPoint.joint ← 999; -- magic number for debugging
bestPoint.featureData ← thisPoint.featureData;
};
BestPointAndCurve: PROC [objectBag: ObjectBag, testPoint: Point, tolerance: REAL] RETURNS [bestPoint: GoodPoint, bestCurve: GoodCurve] = {
epsilon: REAL = 1.0e-3;
thisPoint: GoodPoint;
thisCurve: GoodCurve;
featureData: FeatureData;
success: BOOL;
thisCurve ← NEW[GoodCurveObj];
bestCurve ← NEW[GoodCurveObj];
thisPoint ← NEW[GoodPointObj];
bestPoint ← NEW[GoodPointObj];
bestCurve.dist ← 99999.0; -- magic numbers for debugging
bestPoint.dist ← 99999.0; -- magic numbers for debugging
FOR slopeLines: LIST OF FeatureData ← objectBag.slopeLines, slopeLines.rest UNTIL slopeLines = NIL DO
featureData ← slopeLines.first;
thisCurve.dist ← GGLines.LineDistance[testPoint, featureData.line];
thisCurve.point ← GGLines.PointProjectedOntoLine[testPoint, featureData.line];
thisCurve.featureData ← featureData;
IF thisCurve.dist < bestCurve.dist THEN UpdateBestCurve[thisCurve, bestCurve];
ENDLOOP;
FOR dLines: LIST OF FeatureData ← objectBag.distanceLines, dLines.rest UNTIL dLines = NIL DO
featureData ← dLines.first;
thisCurve.dist ← GGLines.LineDistance[testPoint, featureData.line];
thisCurve.point ← GGLines.PointProjectedOntoLine[testPoint, featureData.line];
thisCurve.featureData ← featureData;
IF thisCurve.dist < bestCurve.dist THEN UpdateBestCurve[thisCurve, bestCurve];
ENDLOOP;
FOR iPoints: LIST OF FeatureData ← objectBag.intersectionPoints, iPoints.rest UNTIL iPoints = NIL DO
featureData ← iPoints.first;
thisPoint.dist ← GGVector.Distance[featureData.point, testPoint];
thisPoint.point ← featureData.point;
thisPoint.featureData ← featureData;
IF thisPoint.dist < bestPoint.dist THEN UpdateBestPoint[thisPoint, bestPoint];
ENDLOOP;
FOR circles: LIST OF FeatureData ← objectBag.radiiCircles, circles.rest UNTIL circles = NIL DO
featureData ← circles.first;
thisCurve.dist ← GGCircles.CircleDistance[testPoint, featureData.circle];
thisCurve.point ← GGCircles.PointProjectedOntoCircle[testPoint, featureData.circle];
thisCurve.featureData ← featureData;
IF thisCurve.dist < bestCurve.dist THEN UpdateBestCurve[thisCurve, bestCurve];
ENDLOOP;
FOR trajs: LIST OF FeatureData ← objectBag.seqs, trajs.rest UNTIL trajs = NIL DO
featureData ← trajs.first;
[thisCurve.dist, thisCurve.segNum, thisCurve.point, success] ← NearestSegment[testPoint, featureData.tseq, tolerance];
IF success THEN {
IF thisCurve.dist - epsilon <= bestCurve.dist THEN { -- so segments are preferred to slopelines
bestCurve.dist ← thisCurve.dist;
bestCurve.segNum ← thisCurve.segNum;
bestCurve.point ← thisCurve.point;
bestCurve.featureData ← featureData;
};
};
[thisPoint.dist, thisPoint.joint, thisPoint.point] ← NearestJoint[testPoint, featureData.tseq];
IF thisPoint.dist - epsilon <= bestPoint.dist THEN {-- joints are preferred to intersection Points
bestPoint.dist ← thisPoint.dist;
bestPoint.point ← thisPoint.point;
bestPoint.joint ← thisPoint.joint;
bestPoint.featureData ← featureData;
};
ENDLOOP;
};
StrictDistance: PUBLIC PROC [testPoint: Point, criticalR: REAL, environ: ObjectBag] RETURNS [resultPoint: Point, feature: FeatureData] = {
Here we find both the nearest point and the nearest line. The winning object is simply the closest.
bestCurve: GoodCurve;
bestPoint: GoodPoint;
IF EmptyBag[environ] THEN {
resultPoint ← testPoint;
feature ← NIL;
RETURN;
};
[bestPoint, bestCurve] ← BestPointAndCurve[environ, testPoint, criticalR];
Pick the closer of the curve and the point.
IF bestPoint.dist = 99999.0 THEN ERROR;
IF bestCurve.dist = 99999.0 THEN ERROR;
IF bestPoint.dist < criticalR AND bestPoint.dist <= bestCurve.dist THEN { -- use the best point
feature ← bestPoint.featureData;
ExtractResultFromPoint[bestPoint, feature];
resultPoint ← bestPoint.point;
}
ELSE IF bestCurve.dist < criticalR THEN {
feature ← bestCurve.featureData;
ExtractResultFromCurve[bestCurve, feature];
resultPoint ← bestCurve.point;
}
ELSE {
feature ← NIL;
resultPoint ← testPoint;
};
}; -- StrictDistance
GoodCurve: TYPE = REF GoodCurveObj;
GoodCurveObj: TYPE = RECORD [
dist: REAL, -- the distance from point to testPoint
segNum: NAT, -- the best segment of this curve (if it is a trajectory)
point: Point, -- the best point on this curve
featureData: FeatureData -- this curve
];
GoodPoint: TYPE = REF GoodPointObj;
GoodPointObj: TYPE = RECORD [
dist: REAL,
point: Point,
joint: NAT, -- the joint of the trajectory mentioned in FeatureData (if this is a joint)
featureData: FeatureData -- this point
];
ExtractResultFromCurve: PROC [curve: GoodCurve, feature: FeatureData] = {
SELECT curve.featureData.type FROM
sequence => {
feature.segNum ← curve.segNum;
feature.resultType ← segment;
};
slopeLine => feature.resultType ← slopeLine;
radiiCircle => feature.resultType ← radiiCircle;
distanceLine => feature.resultType ← distanceLine;
ENDCASE => ERROR NotYetImplemented;
};
ExtractResultFromPoint: PROC [goodPoint: GoodPoint, feature: FeatureData] = {
SELECT goodPoint.featureData.type FROM
sequence => {
feature.jointNum ← goodPoint.joint;
feature.resultType ← joint;
};
intersectionPoint => {
feature.resultType ← intersectionPoint;
};
ENDCASE => ERROR NotYetImplemented;
};
InnerCircle: PUBLIC PROC [testPoint: Point, criticalR: REAL, innerR: REAL, environ: ObjectBag] RETURNS [resultPoint: Point, feature: FeatureData] = {
Here we find both the nearest point and the nearest line. Within innerR, points get preference.
bestCurve: GoodCurve;
bestPoint: GoodPoint;
IF EmptyBag[environ] THEN {
resultPoint ← testPoint;
feature ← NIL;
RETURN;
};
[bestPoint, bestCurve] ← BestPointAndCurve[environ, testPoint, criticalR];
Look at the closest point first. If it is within innerR, use it. Otherwise, pick the closer of the curve and the point.
IF bestPoint.dist = 99999.0 THEN ERROR;
IF bestCurve.dist = 99999.0 THEN ERROR;
IF bestPoint.dist < innerR OR (bestPoint.dist < criticalR AND bestPoint.dist <= bestCurve.dist) THEN { -- use the best point
feature ← bestPoint.featureData;
ExtractResultFromPoint[bestPoint, feature];
resultPoint ← bestPoint.point;
}
ELSE IF bestCurve.dist < criticalR THEN {
feature ← bestCurve.featureData;
ExtractResultFromCurve[bestCurve, feature];
resultPoint ← bestCurve.point;
}
ELSE {
feature ← NIL;
resultPoint ← testPoint;
};
}; -- InnerCircle
Sector: PUBLIC PROC [testPoint: Point, criticalR: REAL, environ: ObjectBag] RETURNS [resultPoint: Point, feature: FeatureData] = {};
Building the Object Bag
CreateObjectBag: PUBLIC PROC [] RETURNS [objectBag: ObjectBag] = {
objectBag ← NEW[ObjectBagObj ← [
seqs: NIL,
slopeLines: NIL,
symmetryLines: NIL,
radiiCircles: NIL,
distanceLines: NIL,
vectors: NIL,
intersectionPoints: NIL
]];
};
AddFeature: PRIVATE PROC [featureData: FeatureData, objectBag: ObjectBag] = {
iPoint: Point;
parallel: BOOL;
points: ARRAY[1..2] OF Point;
hitCount: NAT;
SELECT featureData.type FROM
sequence => {
IF NOT featureData.tseq.all AND featureData.tseq.parts = NIL THEN ERROR; -- empty sequence
objectBag.seqs ← CONS[featureData, objectBag.seqs];
};
distanceLine => objectBag.distanceLines ← CONS[featureData, objectBag.distanceLines];
slopeLine => objectBag.slopeLines ← CONS[featureData, objectBag.slopeLines];
symmetryLine => objectBag.symmetryLines ← CONS[featureData, objectBag.symmetryLines];
radiiCircle => objectBag.radiiCircles ← CONS[featureData, objectBag.radiiCircles];
intersectionPoint => objectBag.intersectionPoints ← CONS[featureData, objectBag.intersectionPoints];
ENDCASE => ERROR;
Now for the N2 part.
First we find slopeLine x slopeLine intersections.
IF featureData.type = slopeLine THEN {
FOR lineList: LIST OF FeatureData ← objectBag.slopeLines.rest, lineList.rest UNTIL lineList = NIL DO
[iPoint, parallel] ← GGLines.LineMeetsLine[lineList.first.line, featureData.line];
IF NOT parallel THEN {
AddIntersectionPointFeature[iPoint, featureData, lineList.first, objectBag];
};
ENDLOOP;
FOR circleList: LIST OF FeatureData ← objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO
[points, hitCount] ← GGCircles.LineMeetsCircle[featureData.line, circleList.first.circle];
FOR i: NAT IN [1..hitCount] DO
AddIntersectionPointFeature[points[i], featureData, circleList.first, objectBag];
ENDLOOP;
ENDLOOP;
FOR dlineList: LIST OF FeatureData ← objectBag.distanceLines, dlineList.rest UNTIL dlineList = NIL DO
[iPoint, parallel] ← GGLines.LineMeetsLine[dlineList.first.line, featureData.line];
IF NOT parallel THEN {
AddIntersectionPointFeature[iPoint, featureData, dlineList.first, objectBag];
};
ENDLOOP;
};
IF featureData.type = radiiCircle THEN {
FOR lineList: LIST OF FeatureData ← objectBag.slopeLines, lineList.rest UNTIL lineList = NIL DO
[points, hitCount] ← GGCircles.LineMeetsCircle[lineList.first.line, featureData.circle];
FOR i: NAT IN [1..hitCount] DO
AddIntersectionPointFeature[points[i], lineList.first, featureData, objectBag];
ENDLOOP;
ENDLOOP;
FOR circleList: LIST OF FeatureData ← objectBag.radiiCircles.rest, circleList.rest UNTIL circleList = NIL DO
[points, hitCount] ← GGCircles.CircleMeetsCircle[circleList.first.circle, featureData.circle];
FOR i: NAT IN [1..hitCount] DO
AddIntersectionPointFeature[points[i], circleList.first, featureData, objectBag];
ENDLOOP;
ENDLOOP;
FOR dlineList: LIST OF FeatureData ← objectBag.distanceLines, dlineList.rest UNTIL dlineList = NIL DO
[points, hitCount] ← GGCircles.LineMeetsCircle[dlineList.first.line, featureData.circle];
FOR i: NAT IN [1..hitCount] DO
AddIntersectionPointFeature[points[i], dlineList.first, featureData, objectBag];
ENDLOOP;
ENDLOOP;
};
IF featureData.type = distanceLine THEN {
FOR lineList: LIST OF FeatureData ← objectBag.slopeLines, lineList.rest UNTIL lineList = NIL DO
[iPoint, parallel] ← GGLines.LineMeetsLine[lineList.first.line, featureData.line];
IF NOT parallel THEN {
AddIntersectionPointFeature[iPoint, featureData, lineList.first, objectBag];
};
ENDLOOP;
FOR circleList: LIST OF FeatureData ← objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO
[points, hitCount] ← GGCircles.LineMeetsCircle[featureData.line, circleList.first.circle];
FOR i: NAT IN [1..hitCount] DO
AddIntersectionPointFeature[points[i], featureData, circleList.first, objectBag];
ENDLOOP;
ENDLOOP;
FOR dlineList: LIST OF FeatureData ← objectBag.distanceLines.rest, dlineList.rest UNTIL dlineList = NIL DO
[iPoint, parallel] ← GGLines.LineMeetsLine[dlineList.first.line, featureData.line];
IF NOT parallel THEN {
AddIntersectionPointFeature[iPoint, featureData, dlineList.first, objectBag];
};
ENDLOOP;
};
};
Joint Firing Rules: SlopeLine, Vector, Circle, Vertex
SameCircle: PRIVATE PROC [point: Point, radius: REAL, list: LIST OF FeatureData] RETURNS [coincident: FeatureData] = {
epsilon: REAL = 1.0e-5;
FOR l: LIST OF FeatureData ← list, l.rest UNTIL l = NIL DO
IF l.first.circle.origin = point AND l.first.circle.radius = radius THEN RETURN[l.first];
ENDLOOP;
RETURN[NIL];
};
LineThru: PRIVATE PROC [point: Point, degrees: REAL, list: LIST OF FeatureData] RETURNS [coincident: FeatureData] = {
epsilon: REAL = 1.0e-5;
FOR l: LIST OF FeatureData ← list, l.rest UNTIL l = NIL DO
IF l.first.degrees = degrees AND
GGLines.LineDistance[point, l.first.line] < epsilon THEN RETURN[l.first];
ENDLOOP;
RETURN[NIL];
};
JointAddSlopeLine: PUBLIC PROC [degrees: REAL, direction: Vector, point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = {
The angle (degrees) and direction vector are the global information. [point, jointNum, traj] describes the joint. lineList is used to avoid redundant lines.
For now, each slope line only remembers one of the joints which it passes thru.
line: Line;
featureData, coincident: FeatureData;
coincident ← LineThru[point, degrees, objectBag.slopeLines];
IF coincident # NIL THEN {
coincident.triggerPoints ← CONS[point, coincident.triggerPoints];
}
ELSE {
line ← GGLines.LineFromPointAndVector[point, direction];
featureData ← NEW[FeatureDataObj];
featureData.type ← slopeLine;
featureData.line ← line;
featureData.degrees ← degrees;
featureData.triggerPoints ← CONS[point, NIL];
featureData.jointNum ← jointNum;
featureData.traj ← traj;
AddFeature[featureData, objectBag];
};
};
JointAddVector: PUBLIC PROC [vector: Vector, point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = {
vector is global. [point, jointNum, traj] describes the joint.
Not yet implemented.
};
JointAddCircle: PUBLIC PROC [radius: REAL, point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = {
radius is global. [point, jointNum, traj] describes the joint.
Each circle remembers all of the joints at its center.
circle: Circle;
featureData, coincident: FeatureData;
coincident ← SameCircle[point, radius, objectBag.radiiCircles];
IF coincident # NIL THEN {
coincident.triggerPoints ← CONS[point, coincident.triggerPoints];
}
ELSE {
circle ← GGCircles.CircleFromPointAndRadius[point, radius];
featureData ← NEW[FeatureDataObj];
featureData.type ← radiiCircle;
featureData.circle ← circle;
featureData.triggerPoints ← CONS[point, NIL];
featureData.jointNum ← jointNum;
featureData.traj ← traj;
AddFeature[featureData, objectBag];
};
};
JointAddPoint: PUBLIC PROC [point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = {
For efficiency, this is a Noop. In fact, some sequence of the trajectory will be placed in the objectBag all at once.
};
Segment Firing Rules: FourAngleLines, ColinearLine, Segment
SegmentAddTwoAngleLines: PUBLIC PROC [degrees: REAL, p1, p2: Point, segNum, traj: Traj, objectBag: ObjectBag] = {
degrees is global. [p1, p2, segNum, traj] describes the segment.
Not yet implemented.
};
SegmentAddDistanceLines: PUBLIC PROC [distance: REAL, segNum: NAT, traj: Traj, objectBag: ObjectBag] = {
No global information is needed. [p1, p2, segNum, traj] describes the segment.
line, leftLine, rightLine: Line;
featureData: FeatureData;
seg: Segment ← GGObjects.FetchSegment[traj, segNum];
line ← GGLines.LineFromPoints[seg.lo, seg.hi];
leftLine ← GGLines.LineLeftOfLine[line, distance];
featureData ← NEW[FeatureDataObj];
featureData.type ← distanceLine;
featureData.line ← leftLine;
featureData.segNum ← segNum;
featureData.traj ← traj;
AddFeature[featureData, objectBag];
IF ABS[distance] > 0.0 THEN {
rightLine ← GGLines.LineRightOfLine[line, distance];
featureData ← NEW[FeatureDataObj];
featureData.type ← distanceLine;
featureData.line ← rightLine;
featureData.segNum ← segNum;
featureData.traj ← traj;
AddFeature[featureData, objectBag];
};
};
SegmentAddEdge: PUBLIC PROC [point: Point, jointNum: NAT, traj: Traj, objectBag: ObjectBag] = {
For efficiency, this is a Noop. In fact, some sequence of the trajectory will be placed in the objectBag all at once. See AddTrajectory below.
};
AddTrajectory: PUBLIC PROC [traj: Traj, objectBag: ObjectBag] = {
This serves double duty as a set of SegmentAddEdge and VertexAddPoint calls.
featureData: FeatureData;
seq: Sequence ← GGObjects.CreateCompleteSequence[traj];
featureData ← NEW[FeatureDataObj];
featureData.type ← sequence;
featureData.tseq ← seq;
AddFeature[featureData, objectBag];
};
AddSequence: PUBLIC PROC [seq: Sequence, objectBag: ObjectBag] = {
This serves double duty as a set of SegmentAddEdge and VertexAddPoint calls.
featureData: FeatureData;
featureData ← NEW[FeatureDataObj];
featureData.type ← sequence;
featureData.tseq ← seq;
AddFeature[featureData, objectBag];
};
Symmetry Firing Rules: SymmetryAddLines, SymmetryAddPoints
SymmetryAddLines: PUBLIC PROC [group: SymmetryGroup, entity: REF ANY, objectBag: ObjectBag] = {
[group, entity] describes the group and the entity to which it belongs.
Not Yet Implemented.
};
SymmetryAddPoints: PUBLIC PROC [group: SymmetryGroup, entity: REF ANY, objectBag: ObjectBag] = {
[group, entity] describes the group and the entity to which it belongs.
Not Yet Implemented.
};
Coordinate Frame Firing Rules: AddPoint AddXLine AddYLine:
CoordFrameAddPoint: PUBLIC PROC [point: Point, objectBag: ObjectBag] = {
For now, only the global coordinate frame is considered.
Not Yet Implemented.
};
CoordFrameAddXLine: PUBLIC PROC [xVal: REAL, objectBag: ObjectBag] = {
For now, only the global coordinate frame is considered. Add the line x = xVal.
Not Yet Implemented.
};
CoordFrameAddYLine: PUBLIC PROC [yVal: REAL, objectBag: ObjectBag] = {
For now, only the global coordinate frame is considered. Add the line y = yVal.
Not Yet Implemented.
};
Second level Features: (See AddFeature)
AddIntersectionPointFeature: PUBLIC PROC [point: Point, feature1, feature2: FeatureData, objectBag: ObjectBag] = {
featureData: FeatureData;
featureData ← NEW[FeatureDataObj];
featureData.type ← intersectionPoint;
featureData.line ← NIL;
featureData.line1Feature ← feature1;
featureData.line2Feature ← feature2;
featureData.degrees ← 999.0;
featureData.seg ← NIL;
featureData.point ← point;
AddFeature[featureData, objectBag];
};
FlushObjectBag: PUBLIC PROC [objectBag: ObjectBag] = {
ERROR NotYetImplemented;
};
Drawing Object Bags
AdjustVisibilityPoint: PUBLIC PROC [testPoint: Point, tolerance: REAL, objectBag: ObjectBag] = {
Make visible all objects which pass within tolerance of testPoint, and make all others invisible.
dist: REAL;
feature: FeatureData;
success: BOOL;
FOR slopeLineList: LIST OF FeatureData ← objectBag.slopeLines, slopeLineList.rest UNTIL slopeLineList = NIL DO
feature ← slopeLineList.first;
dist ← GGLines.LineDistance[testPoint, feature.line];
IF dist < tolerance THEN feature.visible ← TRUE
ELSE feature.visible ← FALSE;
ENDLOOP;
FOR seqList: LIST OF FeatureData ← objectBag.seqs, seqList.rest UNTIL seqList = NIL DO
feature ← seqList.first;
[dist, ----, ----, success] ← NearestSegment[testPoint, feature.tseq, tolerance];
IF success AND dist < tolerance THEN feature.visible ← TRUE
ELSE feature.visible ← FALSE;
ENDLOOP;
FOR circleList: LIST OF FeatureData ← objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO
feature ← circleList.first;
dist ← GGCircles.CircleDistance[testPoint, feature.circle];
IF dist < tolerance THEN feature.visible ← TRUE
ELSE feature.visible ← FALSE;
ENDLOOP;
};
AdjustVisibilityBox: PUBLIC PROC [box: BoundBox, tolerance: REAL, objectBag: ObjectBag] = {};
DrawObjectBag: PUBLIC PROC [dc: Imager.Context, objectBag: ObjectBag, camera: Camera, gargoyleData: GargoyleData] = {
Draws all objects which have been marked "visible" by AdjustVisibilityPoint or AdjustVisibilityBox.
feature: FeatureData;
Imager.SetStrokeWidth[dc, 1.0];
Imager.SetColor[dc, Imager.MakeGray[0.6]];
FOR slopeLineList: LIST OF FeatureData ← objectBag.slopeLines, slopeLineList.rest UNTIL slopeLineList = NIL DO
feature ← slopeLineList.first;
IF feature.visible THEN GGShapes.DrawLine[dc, feature.line];
ENDLOOP;
FOR seqList: LIST OF FeatureData ← objectBag.seqs, seqList.rest UNTIL seqList = NIL DO
feature ← seqList.first;
IF feature.visible THEN GGRefresh.DrawSequence[dc, feature.tseq, gargoyleData];
ENDLOOP;
FOR circleList: LIST OF FeatureData ← objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO
feature ← circleList.first;
IF feature.visible THEN GGShapes.DrawCircle[dc, feature.circle];
ENDLOOP;
FOR dLineList: LIST OF FeatureData ← objectBag.distanceLines, dLineList.rest UNTIL dLineList = NIL DO
feature ← dLineList.first;
IF feature.visible THEN GGShapes.DrawLine[dc, feature.line];
ENDLOOP;
};
DrawObjectBagRegardless: PUBLIC PROC [dc: Imager.Context, objectBag: ObjectBag, camera: Camera, gargoyleData: GargoyleData] = {
Draws all objects in the object bag regardless of how they have been marked.
feature: FeatureData;
IF objectBag = NIL THEN RETURN;
Imager.SetStrokeWidth[dc, 1.0];
Imager.SetColor[dc, Imager.MakeGray[0.6]];
FOR slopeLineList: LIST OF FeatureData ← objectBag.slopeLines, slopeLineList.rest UNTIL slopeLineList = NIL DO
feature ← slopeLineList.first;
GGShapes.DrawLine[dc, feature.line];
ENDLOOP;
FOR seqList: LIST OF FeatureData ← objectBag.seqs, seqList.rest UNTIL seqList = NIL DO
feature ← seqList.first;
GGRefresh.DrawSequence[dc, feature.tseq, gargoyleData];
ENDLOOP;
FOR circleList: LIST OF FeatureData ← objectBag.radiiCircles, circleList.rest UNTIL circleList = NIL DO
feature ← circleList.first;
GGShapes.DrawCircle[dc, feature.circle];
ENDLOOP;
FOR dLineList: LIST OF FeatureData ← objectBag.distanceLines, dLineList.rest UNTIL dLineList = NIL DO
feature ← dLineList.first;
GGShapes.DrawLine[dc, feature.line];
ENDLOOP;
};
END.