<> <> <> <> <> <> <<>> DIRECTORY Feedback, GGBasicTypes, GGBoundBox, GGDescribe, GGModelTypes, GGSegmentTypes, GGSelect, GGSequence, GGTraj, GGUtility, Imager, Rope; GGSequenceImpl: CEDAR PROGRAM IMPORTS Feedback, GGBoundBox, GGDescribe, GGSelect, GGSequence, GGTraj, GGUtility EXPORTS GGSequence = BEGIN BitMatrix: TYPE = REF BitMatrixObj; BitMatrixObj: TYPE = GGBasicTypes.BitMatrixObj; BitVector: TYPE = REF BitVectorObj; BitVectorObj: TYPE = GGBasicTypes.BitVectorObj; BoundBox: TYPE = GGBasicTypes.BoundBox; Color: TYPE = Imager.Color; ControlPointGenerator: TYPE = REF ControlPointGeneratorObj; ControlPointGeneratorObj: TYPE = GGModelTypes.ControlPointGeneratorObj; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = REF JointGeneratorObj; JointGeneratorObj: TYPE = GGModelTypes.JointGeneratorObj; Point: TYPE = GGBasicTypes.Point; PointAndDone: TYPE = GGModelTypes.PointAndDone; SegAndIndex: TYPE = GGSequence.SegAndIndex; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = REF SegmentGeneratorObj; SegmentGeneratorObj: TYPE = GGModelTypes.SegmentGeneratorObj; SelectionClass: TYPE = GGSegmentTypes.SelectionClass; Sequence: TYPE = REF SequenceObj; SequenceGenerator: TYPE = REF SequenceGeneratorObj; SequenceGeneratorObj: TYPE = GGModelTypes.SequenceGeneratorObj; SequenceObj: TYPE = GGModelTypes.SequenceObj; SequenceOfReal: TYPE = GGBasicTypes.SequenceOfReal; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; StrokeEnd: TYPE = Imager.StrokeEnd; Traj: TYPE = GGModelTypes.Traj; TrajEnd: TYPE = GGModelTypes.TrajEnd; TrajPartType: TYPE = GGModelTypes.TrajPartType; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem; <> CreateFromSegments: PUBLIC PROC [traj: Traj, startSeg, endSeg: NAT] RETURNS [seq: Sequence] = { < endSeg is allowed, in which case the segment sequence wraps around.>> <> <> segCount, temp: NAT; IF startSeg >= traj.segCount OR endSeg >= traj.segCount THEN ERROR; IF startSeg = endSeg THEN {seq _ CreateFromSegment[traj, startSeg]; RETURN}; IF traj.role = open THEN { IF startSeg > endSeg THEN {temp _ startSeg; startSeg _ endSeg; endSeg _ temp}; segCount _ endSeg - startSeg + 1; } ELSE { IF startSeg = (endSeg + 1) MOD traj.segCount THEN {seq _ CreateComplete[traj]; RETURN}; segCount _ ((endSeg - startSeg + traj.segCount) MOD traj.segCount) + 1; }; seq _ NEW[SequenceObj _ [ traj: traj, boundBox: GGBoundBox.CopyBoundBox[traj.boundBox], segments: NewBitVector[traj.segCount], joints: NewBitVector[GGTraj.HiJoint[traj] + 1], controlPoints: NewBitMatrix[traj], segCount: segCount, controlPointCount: 0, -- will be updated by FillInControlPoints jointCount: 0 -- will be updated by FillInJoints ]]; IF startSeg < endSeg THEN { FOR i: NAT IN [startSeg..endSeg] DO seq.segments[i] _ TRUE; ENDLOOP; FillInJoints[seq]; FillInControlPoints[seq]; } ELSE { FOR i: NAT IN [startSeg..traj.segCount-1] DO seq.segments[i] _ TRUE; ENDLOOP; FOR i: NAT IN [0..endSeg] DO seq.segments[i] _ TRUE; ENDLOOP; FillInJoints[seq]; FillInControlPoints[seq]; }; }; CreateJointToJoint: PUBLIC PROC [traj: Traj, startJoint, endJoint: NAT] RETURNS [seq: Sequence] = { <> temp, hiJoint: NAT; hiJoint _ GGTraj.HiJoint[traj]; IF traj.role = open AND startJoint = 0 AND endJoint = hiJoint THEN { seq _ CreateComplete[traj]; RETURN}; IF traj.role = open OR startJoint < endJoint THEN { IF startJoint > endJoint THEN {temp _ startJoint; startJoint _ endJoint; endJoint _ temp}; IF startJoint < 0 OR endJoint > hiJoint THEN ERROR; seq _ NEW[SequenceObj _ [ traj: traj, boundBox: GGBoundBox.CopyBoundBox[traj.boundBox], segments: NewBitVector[traj.segCount], joints: NewBitVector[hiJoint+1], controlPoints: NewBitMatrix[traj], segCount: endJoint - startJoint, controlPointCount: 0, -- initialized by FillInControlPoints jointCount: endJoint - startJoint + 1 ]]; FOR i: NAT IN [startJoint..endJoint-1] DO seq.segments[i] _ TRUE; seq.joints[i] _ TRUE; ENDLOOP; seq.joints[endJoint] _ TRUE; } ELSE { IF startJoint = endJoint THEN {seq _ CreateFromJoint[traj, startJoint]; RETURN}; <> seq _ NEW[SequenceObj _ [ traj: traj, boundBox: GGBoundBox.CopyBoundBox[traj.boundBox], segments: NewBitVector[traj.segCount], joints: NewBitVector[hiJoint+1], controlPoints: NewBitMatrix[traj], segCount: traj.segCount - startJoint + endJoint, controlPointCount: 0, jointCount: traj.segCount - startJoint + endJoint + 1 ]]; FOR i: NAT IN [startJoint..traj.segCount-1] DO seq.segments[i] _ TRUE; seq.joints[i] _ TRUE; ENDLOOP; FOR i: NAT IN [0..endJoint-1] DO seq.segments[i] _ TRUE; seq.joints[i] _ TRUE; ENDLOOP; seq.joints[endJoint] _ TRUE; }; FillInControlPoints[seq]; -- after all is said and done }; CreateEmpty: PUBLIC PROC [traj: Traj] RETURNS [seq: Sequence] = { seq _ NEW[SequenceObj _ [ traj: traj, boundBox: GGBoundBox.NullBoundBox[], segments: NewBitVector[traj.segCount], joints: NewBitVector[GGTraj.HiJoint[traj]+1], controlPoints: NewBitMatrix[traj], segCount: 0, controlPointCount: 0, jointCount: 0 ]]; }; CreateComplete: PUBLIC PROC [traj: Traj] RETURNS [seq: Sequence] = { <> jointCount: NAT _ GGTraj.HiJoint[traj] + 1; seq _ NEW[SequenceObj _ [ traj: traj, boundBox: IF traj.boundBox = NIL THEN GGBoundBox.NullBoundBox[] ELSE GGBoundBox.CopyBoundBox[traj.boundBox], segments: NewBitVector[traj.segCount], joints: NewBitVector[jointCount], controlPoints: NewBitMatrix[traj], segCount: traj.segCount, controlPointCount: 0, -- set by FillInControlPoints jointCount: jointCount ]]; FOR i: NAT IN [0..GGTraj.HiSegment[traj]] DO seq.segments[i] _ TRUE; seq.joints[i] _ TRUE; ENDLOOP; seq.joints[jointCount-1] _ TRUE; -- will be redundant for open trajectories FillInControlPoints[seq]; -- after all is said and done }; CreateFromJoint: PUBLIC PROC [traj: Traj, jointNum: NAT] RETURNS [seq: Sequence] = { seq _ CreateEmpty[traj]; seq.joints[jointNum] _ TRUE; seq.jointCount _ 1; }; CreateFromSegment: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [seq: Sequence] = { seq _ CreateEmpty[traj]; seq.segments[segNum] _ TRUE; seq.segCount _ 1; FillInJoints[seq]; FillInControlPoints[seq]; -- after all is said and done }; CreateSimpleFromSegment: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [seq: Sequence] = { seq _ CreateEmpty[traj]; seq.segments[segNum] _ TRUE; seq.segCount _ 1; }; CreateFromControlPoint: PUBLIC PROC [traj: Traj, segNum: NAT, controlPointNum: NAT] RETURNS [seq: Sequence] = { seq _ CreateEmpty[traj]; seq.controlPoints[segNum][controlPointNum] _ TRUE; seq.controlPointCount _ 1; }; Copy: PUBLIC PROC [seq: Sequence] RETURNS [copy: Sequence] = { hiSegment: NAT; IF IsObsolete[seq] THEN ERROR; hiSegment _ GGTraj.HiSegment[seq.traj]; copy _ NEW[SequenceObj _ [ traj: seq.traj, boundBox: GGBoundBox.CopyBoundBox[seq.boundBox], segments: NewBitVector[seq.traj.segCount], joints: NewBitVector[GGTraj.HiJoint[seq.traj]+1], controlPoints: NewBitMatrix[seq.traj], segCount: seq.segCount, controlPointCount: seq.controlPointCount, jointCount: seq.jointCount ]]; FOR i: NAT IN [0..hiSegment] DO cpCount: NAT _ seq.controlPoints[i].len; copy.segments[i] _ seq.segments[i]; copy.joints[i] _ seq.joints[i]; FOR j: NAT IN [0..cpCount) DO copy.controlPoints[i][j] _ seq.controlPoints[i][j]; ENDLOOP; ENDLOOP; IF seq.traj.role = open THEN copy.joints[hiSegment + 1] _ seq.joints[hiSegment + 1]; }; <<>> <> <<>> ComputeBoundBox: PUBLIC PROC [seq: Sequence] RETURNS [box: BoundBox] = { UpdateBoundBox[seq]; box _ seq.boundBox; }; UpdateBoundBox: PUBLIC PROC [seq: Sequence] = { halfJointSize: REAL = GGModelTypes.halfJointSize + 1; <> <> <> <> <> traj: Traj _ seq.traj; box: BoundBox _ seq.boundBox; box.null _ TRUE; <> IF seq.jointCount#0 THEN { -- ForAllJointsInTraj IF traj.role = open THEN { -- ForAllJointsInOpenTraj IF seq.joints[0] AND NOT seq.segments[0] THEN UpdateBySquare[box, GGTraj.FetchJointPos[traj, 0], halfJointSize]; -- boundary case for joint 0 FOR i: NAT IN [1..traj.segCount-1] DO -- loop for inner joints IF seq.joints[i] AND NOT seq.segments[i] AND NOT seq.segments[i-1] THEN UpdateBySquare[box, GGTraj.FetchJointPos[traj, i], halfJointSize]; ENDLOOP; IF seq.joints[traj.segCount] AND NOT seq.segments[traj.segCount-1] THEN UpdateBySquare[box, GGTraj.FetchJointPos[traj, traj.segCount], halfJointSize]; -- boundary case for last joint } ELSE { -- ForAllJointsInClosedTraj FOR i: NAT IN [0..seq.traj.segCount-1] DO IF seq.joints[i] AND NOT seq.segments[i] AND NOT seq.segments[(i -1 + seq.traj.segCount) MOD seq.traj.segCount] THEN UpdateBySquare[box, GGTraj.FetchJointPos[traj, i], halfJointSize]; ENDLOOP; }; }; <> IF seq.controlPointCount#0 THEN { -- if some control point is in the sequence then ... FOR i: NAT IN [0..seq.traj.segCount) DO -- for each segment in the traj IF NOT seq.segments[i] AND SomeSegCPInSeq[i, seq] THEN { -- if this segment is not already in the sequence and any control point of this segment is selected then ... seg: Segment _ GGTraj.FetchSegment[traj, i]; -- get the segment cpCount: NAT _ seq.controlPoints[i].len; FOR j: NAT IN [0..cpCount) DO -- for all control points in the segment IF seq.controlPoints[i][j] THEN { -- if this cp is in the sequence point: Point _ seg.class.controlPointGet[seg, j]; UpdateBySquare[box, point, halfJointSize]; -- update the bounding box with the control point }; ENDLOOP; }; ENDLOOP; }; <> IF seq.segCount#0 THEN { -- if some segment is in the sequence FOR s: NAT IN [0..seq.traj.segCount-1] DO -- for each segment in the traj IF seq.segments[s] THEN { -- if this segment is in the sequence seg: Segment _ GGTraj.FetchSegment[traj, s]; -- get the segment GGBoundBox.EnlargeByBox[bBox: box, by: seg.class.boundBox[seg]]; -- update the bounding box with the segment }; ENDLOOP; }; }; ComputeTightBox: PUBLIC PROC [seq: Sequence] RETURNS [box: BoundBox] = { halfJointSize: REAL = GGModelTypes.halfJointSize + 1; <> <> traj: Traj _ seq.traj; box _ GGBoundBox.NullBoundBox[]; <> IF seq.segCount#0 THEN { FOR s: NAT IN [0..seq.traj.segCount-1] DO -- for each segment in the traj IF seq.segments[s] THEN { -- if this segment is in the sequence seg: Segment _ GGTraj.FetchSegment[traj, s]; GGBoundBox.EnlargeByBox[bBox: box, by: seg.class.tightBox[seg]]; }; ENDLOOP; }; seq.boundBox _ box; -- and, finally, store the new result }; <<>> <> <<>> Describe: PUBLIC PROC [seq: Sequence] RETURNS [rope: Rope.ROPE] = { segNum, cpNum: NAT; segCount: NAT _ seq.segCount; jointCount: NAT _ seq.jointCount; cpCount: NAT _ seq.controlPointCount; SELECT TRUE FROM segCount=1 => { -- single segment selected. Describe it segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; rope _ GGDescribe.DescribeSegment[seq.traj, GGSequence.NextSegmentAndIndex[segGen].index]; }; segCount=0 AND cpCount=1 => { -- single CP selected. Describe it cpGen: ControlPointGenerator _ GGSequence.ControlPointsInSequence[seq]; [segNum, cpNum] _ GGSequence.NextSegNumAndCPNum[cpGen]; rope _ GGDescribe.DescribeControlPoint[seq.traj, segNum, cpNum]; }; segCount=0 AND cpCount=0 AND jointCount=1 => { -- single joint selected. Describe it jointGen: JointGenerator _ GGSequence.JointsInSequence[seq]; rope _ GGDescribe.DescribeJoint[seq.traj, GGSequence.NextJoint[jointGen]]; }; ENDCASE => rope _ GGDescribe.DescribeSequence[seq]; }; <> CopyInto: PUBLIC PROC [to: Sequence, from: Sequence] = { hiSegment: NAT; IF IsObsolete[from] THEN ERROR; hiSegment _ GGTraj.HiSegment[from.traj]; to.traj _ from.traj; to.boundBox _ NIL; FOR i: NAT IN [0..GGTraj.HiSegment[from.traj]] DO cpCount: NAT _ from.controlPoints[i].len; to.segments[i] _ from.segments[i]; FOR j: NAT IN [0..cpCount) DO to.controlPoints[i][j] _ from.controlPoints[i][j]; -- KAP. April 4, 1986 ENDLOOP; ENDLOOP; FOR i: NAT IN [0..GGTraj.HiJoint[from.traj]] DO to.joints[i] _ from.joints[i]; ENDLOOP; to.segCount _ from.segCount; to.controlPointCount _ from.controlPointCount; to.jointCount _ from.jointCount; }; FillInJoints: PUBLIC PROC [seq: Sequence] = { <> jointCount: NAT _ 0; IF IsObsolete[seq] THEN ERROR; IF seq.segCount=0 THEN RETURN; -- can't do anything. seq may have a single joint or CP <> IF seq.traj.role = open THEN { FOR i: NAT IN [0..seq.traj.segCount-1] DO IF seq.segments[i] THEN {seq.joints[i] _ TRUE; seq.joints[i+1] _ TRUE}; ENDLOOP; } ELSE { FOR i: NAT IN [0..seq.traj.segCount-1] DO IF seq.segments[i] THEN {seq.joints[i] _ TRUE; seq.joints[(i+1) MOD seq.traj.segCount] _ TRUE;}; ENDLOOP; }; FOR i: NAT IN [0..GGTraj.HiJoint[seq.traj]] DO IF seq.joints[i] THEN jointCount _ jointCount + 1; ENDLOOP; seq.jointCount _ jointCount; }; FillInControlPoints: PUBLIC PROC [seq: Sequence] = { -- a sequence with segs and joints filled in. IF there are segments then fill in all the control points for each segment in the sequence, and calculate the new control point count. segGen: SegmentGenerator; next: SegAndIndex; cpCount: NAT; <> IF seq.segCount=0 THEN RETURN; -- can't do anything. seq may have a single joint or CP. seq.controlPointCount _ 0; segGen _ SegmentsInSequence[seq]; FOR next _ NextSegmentAndIndex[segGen], NextSegmentAndIndex[segGen] UNTIL next.seg=NIL DO IF NOT seq.segments[next.index] THEN ERROR; -- seq must have this seg, by definition cpCount _ next.seg.class.controlPointCount[next.seg]; -- number of cps in this segment FOR j: NAT IN [0..cpCount) DO -- fill them all in seq.controlPoints[next.index][j] _ TRUE; seq.controlPointCount _ seq.controlPointCount + 1; ENDLOOP; ENDLOOP; }; TrimSelectedParts: PUBLIC PROC [seq: Sequence, selectedList: LIST OF SliceDescriptor] = { <> selSeq: Sequence; selSeq _ GGSelect.FindSequenceInList[seq.traj, selectedList]; IF selSeq = NIL THEN RETURN; -- no selected parts, so nothing to trim FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO FOR j: NAT IN [0..seq.controlPoints[i].len) DO IF selSeq.controlPoints[i][j] AND seq.controlPoints[i][j] THEN { seq.controlPoints[i][j] _ FALSE; seq.controlPointCount _ seq.controlPointCount - 1; }; ENDLOOP; IF selSeq.segments[i] AND seq.segments[i] THEN { seq.segments[i] _ FALSE; seq.segCount _ seq.segCount - 1; }; ENDLOOP; FOR i: NAT IN [0..GGTraj.HiJoint[seq.traj]] DO IF selSeq.joints[i] AND seq.joints[i] THEN { seq.joints[i] _ FALSE; seq.jointCount _ seq.jointCount -1; }; ENDLOOP; }; TrimSelectedControlPointSegments: PUBLIC PROC [seq: Sequence, selectedList: LIST OF SliceDescriptor] = { <> SomeSelectedCP: PROC [i: NAT] RETURNS [BOOL] = { FOR j: NAT IN [0..selSeq.controlPoints[i].len) DO IF selSeq.controlPoints[i][j] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; selSeq: Sequence; selSeq _ GGSelect.FindSequenceInList[seq.traj, selectedList]; IF selSeq = NIL THEN RETURN; -- no CPs selected, so nothing to trim FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF seq.segments[i] AND SomeSelectedCP[i] THEN { seq.segments[i] _ FALSE; seq.segCount _ seq.segCount - 1; }; ENDLOOP; }; AddNonSelectedControlPointSegments: PUBLIC PROC [seq: Sequence, selected: Sequence] = { <> SomeSelectedCP: PROC [i: NAT] RETURNS [BOOL] = { FOR j: NAT IN [0..selected.controlPoints[i].len) DO IF selected.controlPoints[i][j] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; IF selected = NIL THEN RETURN; -- no CPs selected, so nothing to add FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF NOT seq.segments[i] AND NOT selected.segments[i] AND SomeSelectedCP[i] THEN { seq.segments[i] _ TRUE; seq.segCount _ seq.segCount + 1; }; ENDLOOP; }; AddNonSelectedJointSegments: PUBLIC PROC [seq: Sequence, selected: Sequence] = { <> SomeSelectedJoint: PROC [i: NAT] RETURNS [BOOL] = { RETURN[ selected.joints[i] OR selected.joints[GGTraj.FollowingJoint[seq.traj, i]] ]; }; IF selected = NIL THEN RETURN; -- no joints selected, so nothing to add FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF NOT seq.segments[i] AND NOT selected.segments[i] AND SomeSelectedJoint[i] THEN { seq.segments[i] _ TRUE; seq.segCount _ seq.segCount + 1; }; ENDLOOP; }; TrimSelectedJointSegments: PUBLIC PROC [seq: Sequence, selectedList: LIST OF SliceDescriptor] = { <> SomeSelectedJoint: PROC [i: NAT] RETURNS [BOOL] = { RETURN[ selSeq.joints[i] OR selSeq.joints[GGTraj.FollowingJoint[seq.traj, i]] ]; }; selSeq: Sequence; selSeq _ GGSelect.FindSequenceInList[seq.traj, selectedList]; IF selSeq = NIL THEN RETURN; -- no joints selected, so nothing to trim FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF seq.segments[i] AND SomeSelectedJoint[i] THEN { seq.segments[i] _ FALSE; seq.segCount _ seq.segCount - 1; }; ENDLOOP; }; TrimDanglingSegments: PUBLIC PROC [seq: Sequence] = { <> runGen: SequenceGenerator; runCount: NAT; haveTrimmed: BOOL; firstSegNum, firstJointNum, lastSegNum, lastJointNum: INT; IF IsComplete[seq] THEN RETURN; -- nothing is dangling if all joints are included [runGen, runCount] _ RunsInSequence[seq]; FOR run: Sequence _ NextSequence[runGen], NextSequence[runGen] UNTIL run = NIL DO haveTrimmed _ FALSE; firstSegNum _ FirstSegNum[run]; firstJointNum _ FirstJointNum[run]; lastSegNum _ LastSegNum[run, firstSegNum]; lastJointNum _ LastJointNum[run, firstJointNum]; IF firstJointNum = -1 THEN { <> IF firstSegNum = -1 THEN ERROR; -- there must be something in the run IF NOT seq.segments[firstSegNum] THEN ERROR; seq.segments[firstSegNum] _ FALSE; seq.segCount _ seq.segCount - 1; LOOP; }; IF lastJointNum = -1 THEN ERROR; -- if there was a first joint, there must be a last one (it is equal to the first joint if there is only one). IF firstSegNum = -1 THEN LOOP; -- there are no segments so there is nothing to trim IF lastSegNum = -1 THEN ERROR; -- if there was a first segment, there must be a last. <> IF firstJointNum # firstSegNum THEN { IF NOT seq.segments[lastSegNum] THEN ERROR; seq.segments[firstSegNum] _ FALSE; seq.segCount _ seq.segCount - 1; haveTrimmed _ TRUE; }; IF ((seq.traj.role = open AND lastSegNum + 1 # lastJointNum) OR (seq.traj.role # open AND ((lastSegNum + 1) MOD seq.traj.segCount) # lastJointNum)) AND (NOT haveTrimmed OR lastSegNum # firstSegNum) THEN { IF NOT seq.segments[lastSegNum] THEN ERROR; seq.segments[lastSegNum] _ FALSE; seq.segCount _ seq.segCount - 1; }; ENDLOOP; }; TrimControlPointSegments: PUBLIC PROC [seq: Sequence, controlPointOn: BOOL] = { <> SomeIncludedCP: PROC [i: NAT] RETURNS [BOOL] = { FOR j: NAT IN [0..seq.controlPoints[i].len) DO IF seq.controlPoints[i][j] = controlPointOn THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; IF IsObsolete[seq] THEN ERROR; FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF seq.segments[i] AND SomeIncludedCP[i] THEN { seq.segments[i] _ FALSE; seq.segCount _ seq.segCount - 1; }; ENDLOOP; }; TrimJointSegments: PUBLIC PROC [seq: Sequence, jointOn: BOOL] = { <> SomeSelectedJoint: PROC [i: NAT] RETURNS [BOOL] = { RETURN[ seq.joints[i] = jointOn OR seq.joints[GGTraj.FollowingJoint[seq.traj, i]] = jointOn ]; }; FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF seq.segments[i] AND SomeSelectedJoint[i] THEN { seq.segments[i] _ FALSE; seq.segCount _ seq.segCount - 1; }; ENDLOOP; }; DDifference: PUBLIC PROC [mutable, negative: Sequence] = { <> hiJoint: NAT; IF IsObsolete[mutable] OR IsObsolete[negative] THEN ERROR; IF mutable.traj # negative.traj THEN ERROR; FOR i: NAT IN [0..GGTraj.HiSegment[mutable.traj]] DO cpCount: NAT _ mutable.controlPoints[i].len; mutable.segments[i] _ mutable.segments[i] AND NOT negative.segments[i]; FOR j: NAT IN [0..cpCount) DO mutable.controlPoints[i][j] _ mutable.controlPoints[i][j] AND NOT negative.controlPoints[i][j]; ENDLOOP; mutable.joints[i] _ mutable.joints[i] AND NOT negative.joints[i]; ENDLOOP; hiJoint _ GGTraj.HiJoint[mutable.traj]; mutable.joints[hiJoint] _ mutable.joints[hiJoint] AND NOT negative.joints[hiJoint]; mutable.segCount _ CountSegments[mutable]; mutable.jointCount _ CountJoints[mutable]; mutable.controlPointCount _ CountControlPoints[mutable]; }; <<>> <> NewBitMatrix: PROC [traj: Traj] RETURNS [bitMatrix: BitMatrix] = { j: NAT _ 0; segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; bitMatrix _ NEW[BitMatrixObj[traj.segCount]]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO bitMatrix[j] _ NewBitVector[seg.class.controlPointCount[seg]]; j _ j+1; ENDLOOP; }; NewBitVector: PROC [length: NAT] RETURNS [bitVec: BitVector] = { bitVec _ NEW[BitVectorObj[length]]; SetAllBits[bitVec, FALSE]; }; <<>> SetAllBits: PROC [bitVec: BitVector, bool: BOOL] = { FOR i: NAT IN [0..bitVec.len) DO bitVec[i] _ bool; ENDLOOP; }; SomeSegCPInSeq: PROC [segNum: NAT, seq: Sequence] RETURNS [BOOL] = { cpCount: NAT _ seq.controlPoints[segNum].len; FOR j: NAT IN [0..cpCount) DO IF seq.controlPoints[segNum][j] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; UpdateBySquare: PROC [bBox: BoundBox, p: Point, halfSquareSide: REAL] ~ { -- updates the accumulating bBox by a joint or CP pHalf: REAL _ halfSquareSide + 1; loX, loY, hiX, hiY: REAL; IF bBox.infinite THEN RETURN; loX _ p.x-pHalf; loY _ p.y-pHalf; hiX _ p.x+pHalf; hiY _ p.y+pHalf; IF bBox.null THEN { bBox.loX _ loX; bBox.hiX _ hiX; bBox.loY _ loY; bBox.hiY _ hiY; bBox.null _ FALSE; RETURN; }; IF loX < bBox.loX THEN bBox.loX _ loX; IF hiX > bBox.hiX THEN bBox.hiX _ hiX; IF loY < bBox.loY THEN bBox.loY _ loY; IF hiY > bBox.hiY THEN bBox.hiY _ hiY; }; <> <<>> Union: PUBLIC PROC [a, b: Sequence] RETURNS [union: Sequence] = { hiJoint: NAT; IF IsObsolete[a] OR IsObsolete[b] THEN ERROR; IF a.traj # b.traj THEN ERROR; union _ CreateEmpty[a.traj]; FOR i: NAT IN [0..GGTraj.HiSegment[a.traj]] DO cpCount: NAT _ a.controlPoints[i].len; union.segments[i] _ a.segments[i] OR b.segments[i]; FOR j: NAT IN [0..cpCount) DO union.controlPoints[i][j] _ a.controlPoints[i][j] OR b.controlPoints[i][j]; ENDLOOP; union.joints[i] _ a.joints[i] OR b.joints[i]; ENDLOOP; hiJoint _ GGTraj.HiJoint[a.traj]; union.joints[hiJoint] _ a.joints[hiJoint] OR b.joints[hiJoint]; union.segCount _ CountSegments[union]; union.jointCount _ CountJoints[union]; union.controlPointCount _ CountControlPoints[union]; }; Intersection: PUBLIC PROC [a, b: Sequence] RETURNS [intersection: Sequence] = { hiJoint: NAT; IF IsObsolete[a] OR IsObsolete[b] THEN ERROR; IF a.traj # b.traj THEN ERROR; intersection _ CreateEmpty[a.traj]; FOR i: NAT IN [0..GGTraj.HiSegment[a.traj]] DO cpCount: NAT _ a.controlPoints[i].len; intersection.segments[i] _ a.segments[i] AND b.segments[i]; FOR j: NAT IN [0..cpCount) DO intersection.controlPoints[i][j]_ a.controlPoints[i][j] AND b.controlPoints[i][j]; ENDLOOP; intersection.joints[i] _ a.joints[i] AND b.joints[i]; ENDLOOP; hiJoint _ GGTraj.HiJoint[a.traj]; intersection.joints[hiJoint] _ a.joints[hiJoint] AND b.joints[hiJoint]; intersection.segCount _ CountSegments[intersection]; intersection.jointCount _ CountJoints[intersection]; intersection.controlPointCount _ CountControlPoints[intersection]; }; Difference: PUBLIC PROC [a, b: Sequence] RETURNS [aMinusB: Sequence] = { hiJoint: NAT; IF IsObsolete[a] OR IsObsolete[b] THEN ERROR; IF a.traj # b.traj THEN ERROR; aMinusB _ CreateEmpty[a.traj]; FOR i: NAT IN [0..GGTraj.HiSegment[a.traj]] DO cpCount: NAT _ a.controlPoints[i].len; aMinusB.segments[i] _ a.segments[i] AND NOT b.segments[i]; FOR j: NAT IN [0..cpCount) DO aMinusB.controlPoints[i][j] _ a.controlPoints[i][j] AND NOT b.controlPoints[i][j]; ENDLOOP; aMinusB.joints[i] _ a.joints[i] AND NOT b.joints[i]; ENDLOOP; hiJoint _ GGTraj.HiJoint[a.traj]; aMinusB.joints[hiJoint] _ a.joints[hiJoint] AND NOT b.joints[hiJoint]; aMinusB.segCount _ CountSegments[aMinusB]; aMinusB.jointCount _ CountJoints[aMinusB]; aMinusB.controlPointCount _ CountControlPoints[aMinusB]; }; TrajMovingParts: PUBLIC PROC [seq: Sequence] RETURNS [background, overlay, rubber, drag: Sequence] = { <> <> <> <> background _ NIL; drag _ Copy[seq]; rubber _ FindRubberFromSelected[seq]; overlay _ CreateComplete[seq.traj]; DDifference[overlay, drag]; DDifference[overlay, rubber]; }; FindRubberFromSelected: PROC [seq: Sequence] RETURNS [rubber: Sequence] = { rubber _ CreateEmpty[seq.traj]; AddNonSelectedControlPointSegments[rubber, seq]; AddNonSelectedJointSegments[rubber, seq]; }; Augment: PUBLIC PROC [seq: Sequence, trajEnd: TrajEnd, extend: BOOL] RETURNS [bigger: Sequence] = { <> IF seq.traj.role = hole OR seq.traj.role = fence THEN { bigger _ AugmentClosed[seq, extend]; RETURN; }; <> bigger _ CreateEmpty[seq.traj]; bigger.segCount _ seq.segCount; bigger.controlPointCount _ seq.controlPointCount; bigger.jointCount _ seq.jointCount; IF trajEnd = hi THEN { FOR i: NAT IN [0..seq.segments.len) DO cpCount: NAT _ seq.controlPoints[i].len; bigger.segments[i] _ seq.segments[i]; bigger.joints[i] _ seq.joints[i]; FOR j: NAT IN [0..cpCount) DO bigger.controlPoints[i][j] _ seq.controlPoints[i][j]; ENDLOOP; ENDLOOP; <> IF seq.joints[seq.joints.len - 1] THEN { -- final joint included ?? bigger.joints[seq.joints.len - 1] _ TRUE; -- yes, so include it in bigger IF extend THEN { bigger.segments[seq.segments.len] _ TRUE; bigger.joints[seq.joints.len] _ TRUE; SetAllBits[bigger.controlPoints[seq.segments.len], TRUE]; bigger.segCount _ bigger.segCount + 1; bigger.jointCount _ bigger.jointCount + 1; bigger.controlPointCount _ bigger.controlPointCount + bigger.controlPoints[seq.segments.len].len }; }; } ELSE { FOR i: NAT IN [0..seq.segments.len) DO cpCount: NAT _ seq.controlPoints[i].len; bigger.segments[i+1] _ seq.segments[i]; bigger.joints[i+2] _ seq.joints[i+1]; FOR j: NAT IN [0..cpCount) DO bigger.controlPoints[i+1][j] _ seq.controlPoints[i][j]; ENDLOOP; ENDLOOP; <> IF seq.joints[0] THEN { -- first joint included ?? bigger.joints[1] _ TRUE; -- yes, so include it in bigger IF extend THEN { bigger.segments[0] _ TRUE; bigger.joints[0] _ TRUE; SetAllBits[bigger.controlPoints[0], TRUE]; bigger.segCount _ bigger.segCount + 1; bigger.jointCount _ bigger.jointCount + 1; bigger.controlPointCount _ bigger.controlPointCount + bigger.controlPoints[0].len }; }; }; }; AugmentClosed: PUBLIC PROC [seq: Sequence, extend: BOOL] RETURNS [bigger: Sequence] = { <> bigger _ NEW[SequenceObj _ [ traj: seq.traj, boundBox: GGBoundBox.NullBoundBox[], segments: NewBitVector[seq.segments.len+1], joints: NewBitVector[seq.joints.len], controlPoints: NewBitMatrix[seq.traj], -- new BitMatrix one segment bigger segCount: seq.segCount, controlPointCount: seq.controlPointCount, jointCount: seq.jointCount ]]; FOR i: NAT IN [0..seq.segments.len) DO cpCount: NAT _ seq.controlPoints[i].len; bigger.segments[i] _ seq.segments[i]; bigger.joints[i] _ seq.joints[i]; FOR j: NAT IN [0..cpCount) DO bigger.controlPoints[i][j] _ seq.controlPoints[i][j]; -- KAP. April 4, 1986 ENDLOOP; ENDLOOP; IF seq.joints[seq.joints.len - 1] THEN { -- final joint included ?? bigger.joints[seq.joints.len - 1] _ TRUE; -- yes, so include it in bigger <> IF extend THEN { bigger.segments[seq.segments.len] _ TRUE; SetAllBits[bigger.controlPoints[seq.segments.len], TRUE]; bigger.segCount _ bigger.segCount + 1; bigger.controlPointCount _ bigger.controlPointCount + bigger.controlPoints[seq.segments.len].len; }; }; }; AugmentParts: PUBLIC PROC [seq: Sequence, selectClass: SelectionClass] = { <> IF selectClass = normal THEN { FillInJoints[seq]; FillInControlPoints[seq]; } ELSE { FillInControlPoints[seq]; }; }; <<>> <<>> <<>> <> IsObsolete: PUBLIC PROC [seq: Sequence] RETURNS [BOOL] = { <> j: NAT _ 0; segGen: SegmentGenerator; IF seq.segments.len # seq.traj.segCount THEN RETURN[TRUE]; IF seq.joints.len # (GGTraj.HiJoint[seq.traj] + 1) THEN RETURN[TRUE]; segGen _ SegmentsInTraj[seq.traj]; FOR nextSeg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL nextSeg=NIL DO IF nextSeg.class.controlPointCount[nextSeg]#seq.controlPoints[j].len THEN RETURN[TRUE]; j _ j+1; ENDLOOP; RETURN[FALSE]; }; IsEmpty: PUBLIC PROC [seq: Sequence] RETURNS [BOOL] = { RETURN[seq.jointCount = 0 AND seq.segCount = 0 AND seq.controlPointCount = 0]; }; ControlPointsOnly: PUBLIC PROC [seq: Sequence] RETURNS [BOOL] = { RETURN[seq.jointCount = 0 AND seq.segCount = 0]; }; IsComplete: PUBLIC PROC [seq: Sequence] RETURNS [BOOL] = { RETURN[seq.segCount = seq.traj.segCount AND (seq.jointCount = GGTraj.HiJoint[seq.traj] + 1)]; }; Overlap: PUBLIC PROC [seq1, seq2: Sequence] RETURNS [BOOL] = { IF IsObsolete[seq1] OR IsObsolete[seq2] THEN ERROR; IF seq1.traj # seq2.traj THEN ERROR; <> FOR i: NAT IN [0..GGTraj.HiSegment[seq1.traj]] DO IF seq1.segments[i] AND seq2.segments[i] THEN RETURN[TRUE]; ENDLOOP; <> FOR i: NAT IN [0..GGTraj.HiJoint[seq1.traj]] DO IF seq1.joints[i] AND seq2.joints[i] THEN RETURN[TRUE]; ENDLOOP; FOR i: NAT IN [0..GGTraj.HiSegment[seq1.traj]] DO cpCount: NAT _ seq1.controlPoints[i].len; FOR j: NAT IN [0..cpCount) DO IF seq1.controlPoints[i][j] AND seq2.controlPoints[i][j] THEN RETURN[TRUE]; ENDLOOP; ENDLOOP; RETURN[FALSE]; }; CountSegments: PROC [seq: Sequence] RETURNS [segCount: NAT] = { segCount _ 0; FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF seq.segments[i] THEN segCount _ segCount + 1; ENDLOOP; }; CountJoints: PROC [seq: Sequence] RETURNS [jointCount: NAT] = { jointCount _ 0; FOR i: NAT IN [0..GGTraj.HiJoint[seq.traj]] DO IF seq.joints[i] THEN jointCount _ jointCount + 1; ENDLOOP; }; CountControlPoints: PROC [seq: Sequence] RETURNS [count: NAT _ 0] = { FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO cpCount: NAT _ seq.controlPoints[i].len; FOR j: NAT IN [0..cpCount) DO IF seq.controlPoints[i][j] THEN count _ count + 1; ENDLOOP; ENDLOOP; }; ContainsSegment: PUBLIC PROC [seq: Sequence, segNum: NAT] RETURNS [BOOL] = { RETURN[seq.segments[segNum]]; }; ContainsSomeSegment: PUBLIC PROC [seq: Sequence] RETURNS [BOOL] = { RETURN[seq.segCount > 0]; }; ContainsSegmentParts: PUBLIC PROC [seq: Sequence, segNum: NAT] RETURNS [BOOL] = { <> RETURN [seq#NIL AND (seq.segments[segNum] OR NOT GGUtility.AllFalse[seq.controlPoints[segNum]] OR seq.joints[segNum] OR seq.joints[IF seq.traj.role=open THEN segNum+1 ELSE (segNum+1) MOD seq.traj.segCount]) ]; }; FirstSegment: PROC [seq: Sequence] RETURNS [index: NAT] ~ { hiSeg: NAT _ GGTraj.HiSegment[seq.traj]; IF IsObsolete[seq] THEN ERROR; IF seq.traj.role = open THEN { FOR i: NAT IN [0..hiSeg] DO IF seq.segments[i] THEN GOTO Found; REPEAT Found => index _ i; FINISHED => SIGNAL Problem[msg: "the first run begins with a segment."]; ENDLOOP; } ELSE { FOR i: NAT IN [0..hiSeg] DO IF NOT seq.segments[(i - 1 + seq.traj.segCount) MOD seq.traj.segCount] AND seq.joints[i] THEN GOTO Found; IF NOT seq.joints[i] AND seq.segments[i] THEN GOTO Found; REPEAT Found => index _ i; FINISHED => SIGNAL Problem[msg: "there is no break in the sequence."]; ENDLOOP; }; }; FirstSegNum: PUBLIC PROC [run: Sequence] RETURNS [INT] = { <> IF run.segCount = 0 THEN RETURN[-1]; IF GGSequence.IsComplete[run] THEN RETURN[0]; --DJK, to make work with complete, closed sequences RETURN[FirstTransitionInRun[run]]; }; LastSegNum: PUBLIC PROC [run: Sequence, firstSegNum: INT] RETURNS [lastNum: INT] = { <> IF firstSegNum = -1 THEN RETURN[-1]; IF run.traj.role = open THEN lastNum _ firstSegNum + run.segCount - 1 ELSE lastNum _ (firstSegNum + run.segCount - 1 + run.traj.segCount) MOD run.traj.segCount; }; ContainsJoint: PUBLIC PROC [seq: Sequence, jointNum: NAT] RETURNS [BOOL] = { RETURN[seq.joints[jointNum]]; }; FirstJointNum: PUBLIC PROC [run: Sequence] RETURNS [INT] = { <> firstSeg, nextJoint: NAT; IF run.jointCount = 0 THEN RETURN[-1]; firstSeg _ FirstTransitionInRun[run]; IF run.joints[firstSeg] THEN RETURN[firstSeg] ELSE { IF run.traj.role = open THEN { IF run.joints[firstSeg + 1] THEN RETURN[firstSeg + 1] ELSE ERROR Problem[msg: "Broken invariant."]; } ELSE { nextJoint _ GGTraj.FollowingJoint[run.traj, firstSeg]; IF run.joints[nextJoint] THEN RETURN[nextJoint] ELSE ERROR Problem[msg: "Broken invariant."]; }; }; }; LastJointNum: PUBLIC PROC [run: Sequence, firstJointNum: INT] RETURNS [lastNum: INT] = { IF firstJointNum = -1 THEN RETURN[-1]; IF run.traj.role = open THEN lastNum _ firstJointNum + run.jointCount - 1 ELSE lastNum _ (firstJointNum + run.jointCount - 1 + run.traj.segCount) MOD run.traj.segCount; }; LastSegAndJoint: PUBLIC PROC [traj: Traj, trajEnd: TrajEnd] RETURNS [segAndJoint: Sequence] = { segAndJoint _ CreateEmpty[traj]; IF traj.role = open THEN { segAndJoint.jointCount _ 1; segAndJoint.segCount _ 1; IF trajEnd = lo THEN { segAndJoint.segments[0] _ TRUE; segAndJoint.joints[0] _ TRUE; } ELSE { hiSeg: NAT _ GGTraj.HiSegment[traj]; segAndJoint.segments[hiSeg] _ TRUE; segAndJoint.joints[hiSeg+1] _ TRUE; }; } ELSE ERROR; }; UnpackOnePointSequence: PUBLIC PROC [seq: Sequence] RETURNS [isACP: BOOL, segNum, cpNum, jointNum: NAT] = { <> seg: Segment; FOR i: NAT IN [0..GGTraj.HiJoint[seq.traj]] DO IF seq.joints[i] THEN { isACP _ FALSE; segNum _ 999; cpNum _ 999; jointNum _ i; RETURN; } ENDLOOP; FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO seg _ GGTraj.FetchSegment[seq.traj, i]; FOR j: NAT IN [0..seg.class.controlPointCount[seg] - 1] DO IF seq.controlPoints[i][j] THEN { isACP _ TRUE; segNum _ i; cpNum _ j; jointNum _ 999; RETURN; } ENDLOOP; ENDLOOP; ERROR; }; UnpackOneSegmentSequence: PUBLIC PROC [seq: Sequence] RETURNS [segNum: NAT] = { FOR i: NAT IN [0..GGTraj.HiSegment[seq.traj]] DO IF seq.segments[i] THEN { segNum _ i; RETURN; } ENDLOOP; ERROR; }; UnpackSimpleSequence: PUBLIC PROC [seq: Sequence] RETURNS [success: BOOL, partType: TrajPartType _ none, traj: Traj, joint: Joint _ NIL, jointNum: NAT _ 999, cp: Point _ [0,0], cpNum: NAT _ 999, seg: Segment _ NIL, segNum: NAT _ 999] = { jointFound, cpFound, segFound: BOOL _ FALSE; <> traj _ seq.traj; FOR i: NAT IN [0..GGTraj.HiJoint[traj]] DO IF seq.joints[i] THEN { IF jointFound THEN {success _ FALSE; RETURN}; jointNum _ i; joint _ GGTraj.FetchJoint[traj, i]; jointFound _ TRUE; partType _ joint; } ENDLOOP; FOR i: NAT IN [0..GGTraj.HiSegment[traj]] DO thisSeg: Segment _ GGTraj.FetchSegment[traj, i]; FOR j: NAT IN [0..thisSeg.class.controlPointCount[thisSeg]) DO IF seq.controlPoints[i][j] THEN { IF cpFound THEN {success _ FALSE; RETURN}; segNum _ i; seg _ thisSeg; cpNum _ j; cp _ thisSeg.class.controlPointGet[thisSeg, cpNum]; cpFound _ TRUE; partType _ controlPoint; } ENDLOOP; ENDLOOP; IF jointFound AND cpFound THEN {success _ FALSE; RETURN}; FOR i: NAT IN [0..GGTraj.HiSegment[traj]] DO IF seq.segments[i] THEN { IF segFound THEN {success _ FALSE; RETURN}; segNum _ i; seg _ GGTraj.FetchSegment[traj, i]; segFound _ TRUE; partType _ segment; } ENDLOOP; IF (jointFound AND segFound) OR (cpFound AND segFound) THEN {success _ FALSE; RETURN}; IF NOT jointFound AND NOT cpFound AND NOT segFound THEN ERROR; success _ TRUE; }; <<>> <> <<>> RunsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [seqGen: SequenceGenerator, runCount: NAT] = { <> IF IsObsolete[seq] THEN ERROR; IF seq.traj.role = open THEN [seqGen, runCount] _ RunsInSequenceOpen[seq] ELSE [seqGen, runCount] _ RunsInSequenceClosed[seq]; }; RunsInSequenceOpen: PROC [seq: Sequence] RETURNS [seqGen: SequenceGenerator, runCount: NAT] = { in: BOOL _ FALSE; thisSeq: Sequence; hiSeg: NAT _ GGTraj.HiSegment[seq.traj]; hiJoint: NAT _ hiSeg + 1; seqGen _ NEW[SequenceGeneratorObj _ [NIL]]; runCount _ 0; IF IsEmpty[seq] THEN RETURN; FOR i: NAT IN [0..hiSeg] DO [in, seqGen.list, thisSeq, runCount] _ ConsiderJoint[in, seqGen.list, seq, thisSeq, runCount, i]; [in, seqGen.list, thisSeq, runCount] _ ConsiderSegment[in, seqGen.list, seq, thisSeq, runCount, i]; ENDLOOP; [in, seqGen.list, thisSeq, runCount] _ ConsiderJoint[in, seqGen.list, seq, thisSeq, runCount, hiJoint]; IF in THEN seqGen.list _ AppendToList[seqGen.list, CONS[thisSeq, NIL]]; }; RunsInSequenceClosed: PROC [seq: Sequence] RETURNS [seqGen: SequenceGenerator, runCount: NAT] = { <> in: BOOL _ FALSE; thisSeq: Sequence; start: NAT; natGen: NATGenerator; seqGen _ NEW[SequenceGeneratorObj _ [NIL]]; runCount _ 0; IF ControlPointsOnly[seq] THEN RETURN; start _ FirstTransitionInRun[seq]; in _ FALSE; natGen _ NATsInInterval[start, seq.traj.segCount, seq.traj.segCount]; FOR i: INT _ NextNAT[natGen], NextNAT[natGen] UNTIL i = -1 DO [in, seqGen.list, thisSeq, runCount] _ ConsiderJoint[in, seqGen.list, seq, thisSeq, runCount, i]; [in, seqGen.list, thisSeq, runCount] _ ConsiderSegment[in, seqGen.list, seq, thisSeq, runCount, i]; ENDLOOP; IF in THEN seqGen.list _ AppendToList[seqGen.list, CONS[thisSeq, NIL]]; }; NextSequence: PUBLIC PROC [seqGen: SequenceGenerator] RETURNS [seq: Sequence] = { IF seqGen.list = NIL THEN RETURN[NIL]; seq _ seqGen.list.first; seqGen.list _ seqGen.list.rest; }; FirstTransitionInRun: PROC [seq: Sequence] RETURNS [transitionNum: NAT] = { < joint 2 returns 2. joint 1 -> segment (2) returns 2. Hence, if the first run has any segments at all, transitionNum will be the number of the first segment.>> hiSeg: NAT _ GGTraj.HiSegment[seq.traj]; IF seq.traj.role = open THEN { FOR i: NAT IN [0..hiSeg] DO IF seq.joints[i] THEN RETURN[i]; IF seq.segments[i] THEN RETURN[i]; ENDLOOP; IF seq.joints[hiSeg+1] THEN RETURN[hiSeg+1]; SIGNAL Problem[msg: "there is no break in the sequence."]; } ELSE { FOR i: NAT IN [0..hiSeg] DO IF NOT seq.segments[(i -1 + seq.traj.segCount) MOD seq.traj.segCount] AND seq.joints[i] THEN GOTO FoundStart; IF NOT seq.joints[i] AND seq.segments[i] THEN GOTO FoundStart; REPEAT FoundStart => transitionNum _ i; FINISHED => SIGNAL Problem[msg: "there is no break in the sequence."]; ENDLOOP; }; }; AppendToList: PROC [list1, list2: LIST OF Sequence] RETURNS [result: LIST OF Sequence] = { pos: LIST OF Sequence; newCell: LIST OF Sequence; <> IF list1 = NIL THEN RETURN[list2]; result _ CONS[list1.first, NIL]; pos _ result; FOR l: LIST OF Sequence _ list1.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; pos.rest _ list2; }; ConsiderJoint: PROC [in: BOOL, list: LIST OF Sequence, seq: Sequence, thisSeq: Sequence, runCount: NAT, i: NAT] RETURNS [newIn: BOOL, newList: LIST OF Sequence, newThisSeq: Sequence, newCount: NAT] = { newIn _ in; newList _ list; newThisSeq _ thisSeq; newCount _ runCount; SELECT TRUE FROM NOT seq.joints[i] AND NOT in => {}; NOT seq.joints[i] AND in => { newIn _ FALSE; newList _ AppendToList[list, CONS[thisSeq, NIL]]; newThisSeq _ NIL}; seq.joints[i] AND NOT in => { newIn _ TRUE; newThisSeq _ CreateEmpty[seq.traj]; <> newCount _ newCount + 1; newThisSeq.joints[i] _ TRUE; newThisSeq.jointCount _ newThisSeq.jointCount + 1; }; seq.joints[i] AND in => { newThisSeq.joints[i] _ TRUE; newThisSeq.jointCount _ newThisSeq.jointCount + 1; }; ENDCASE => ERROR; }; ConsiderSegment: PROC [in: BOOL, list: LIST OF Sequence, seq: Sequence, thisSeq: Sequence, runCount: NAT, i: NAT] RETURNS [newIn: BOOL, newList: LIST OF Sequence, newThisSeq: Sequence, newCount: NAT] = { newIn _ in; newList _ list; newThisSeq _ thisSeq; newCount _ runCount; SELECT TRUE FROM NOT seq.segments[i] AND NOT in => {}; NOT seq.segments[i] AND in => { newIn _ FALSE; newList _ AppendToList[list, CONS[thisSeq, NIL]]; newThisSeq _ NIL}; seq.segments[i] AND NOT in => { newIn _ TRUE; newThisSeq _ CreateEmpty[seq.traj]; newCount _ newCount + 1; newThisSeq.segments[i] _ TRUE; newThisSeq.segCount _ newThisSeq.segCount + 1; ControlPointsTrue[newThisSeq, i]; }; seq.segments[i] AND in => { newThisSeq.segments[i] _ TRUE; newThisSeq.segCount _ newThisSeq.segCount + 1; ControlPointsTrue[newThisSeq, i]; }; ENDCASE => ERROR; }; ControlPointsTrue: PROC [seq: Sequence, segNum: NAT] = { seg: Segment _ GGTraj.FetchSegment[seq.traj, segNum]; cpCount: NAT _ seg.class.controlPointCount[seg]; FOR i: NAT IN [0..cpCount-1] DO IF NOT seq.controlPoints[segNum][i] THEN { seq.controlPoints[segNum][i] _ TRUE; seq.controlPointCount _ seq.controlPointCount + 1; }; ENDLOOP; }; NATGenerator: TYPE = REF NATGeneratorObj; NATGeneratorObj: TYPE = RECORD [ toGo: NAT, next: NAT, mod: NAT ]; NATsInInterval: PROC [start, length, mod: NAT] RETURNS [natGen: NATGenerator] = { natGen _ NEW[NATGeneratorObj _ [ toGo: length, next: start, mod: mod]]; }; NextNAT: PROC [natGen: NATGenerator] RETURNS [nextNAT: INT] = { IF natGen.toGo = 0 THEN RETURN[-1]; natGen.toGo _ natGen.toGo - 1; nextNAT _ natGen.next; natGen.next _ (natGen.next + 1) MOD natGen.mod; }; SegmentsInTraj: PUBLIC PROC [traj: Traj] RETURNS [segGen: SegmentGenerator] = { <> segGen _ NEW[SegmentGeneratorObj _ [ traj: traj, toGo: traj.segCount, index: 0, seq: NIL, completeSeq: TRUE ]]; }; SegmentsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [segGen: SegmentGenerator] = { <> IF IsComplete[seq] THEN RETURN[SegmentsInTraj[seq.traj]]; segGen _ NEW[SegmentGeneratorObj _ [ traj: seq.traj, toGo: seq.segCount, index: 0, seq: seq, -- should we copy it? Bier January 27, 1986 5:37:01 pm PST completeSeq: FALSE ]]; }; OrderedSegmentsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [segGen: SegmentGenerator] = { <> <> IF IsObsolete[seq] THEN ERROR; IF IsComplete[seq] THEN RETURN[SegmentsInTraj[seq.traj]]; segGen _ NEW[SegmentGeneratorObj _ [ traj: seq.traj, toGo: seq.segCount, index: IF seq.segCount=0 THEN 0 ELSE FirstSegment[seq], -- KAP December 22, 1986 seq: seq, -- should we copy it? Bier January 27, 1986 completeSeq: FALSE ]]; }; NextSegment: PUBLIC PROC [segGen: SegmentGenerator] RETURNS [next: Segment] = { <> <> <<1) When this procedure is called, seq.segments[segGen.index] has not yet been looked at OR segGen.toGo = 0.>> <<2) touched < segCount OR segGen.toGo = 0.>> seq: Sequence _ segGen.seq; segCount: NAT _ GGTraj.HiSegment[segGen.traj] + 1; IF segGen.toGo = 0 THEN RETURN[NIL]; IF NOT segGen.completeSeq THEN { -- If we are stepping through a complete traj, seq = NIL UNTIL seq.segments[segGen.index] DO segGen.index _ (segGen.index + 1) MOD segCount; segGen.touched _ segGen.touched + 1; IF segGen.touched >= segCount THEN SIGNAL Problem[msg: "Broken invariant"]; ENDLOOP; }; <<3) At this point in the procedure, seq.segments[segGen.index] is TRUE.>> <<4) At this point, touched < segCount.>> next _ GGTraj.FetchSegment[segGen.traj, segGen.index]; segGen.index _ (segGen.index + 1) MOD segCount; segGen.touched _ segGen.touched + 1; segGen.toGo _ segGen.toGo - 1; }; NextSegmentAndIndex: PUBLIC PROC [segGen: SegmentGenerator] RETURNS [next: SegAndIndex] = { <> <> <<1) When this procedure is called, seq.segments[segGen.index] has not yet been looked at OR segGen.toGo = 0.>> <<2) touched < segCount OR segGen.toGo = 0.>> seq: Sequence _ segGen.seq; segCount: NAT _ GGTraj.HiSegment[segGen.traj] + 1; IF segGen.toGo = 0 THEN RETURN[[NIL, 999]]; IF NOT segGen.completeSeq THEN { -- If we are stepping through a complete traj, seq = NIL UNTIL seq.segments[segGen.index] DO segGen.index _ (segGen.index + 1) MOD segCount; segGen.touched _ segGen.touched + 1; IF segGen.touched >= segCount THEN SIGNAL Problem[msg: "Broken invariant"]; ENDLOOP; }; <<3) At this point in the procedure, seq.segments[segGen.index] is TRUE.>> <<4) At this point, touched < segCount.>> next.seg _ GGTraj.FetchSegment[segGen.traj, segGen.index]; next.index _ segGen.index; segGen.index _ (segGen.index + 1) MOD segCount; segGen.touched _ segGen.touched + 1; segGen.toGo _ segGen.toGo - 1; }; ControlPointsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [cpGen: ControlPointGenerator] = { <> IF IsObsolete[seq] THEN ERROR; cpGen _ NEW[ControlPointGeneratorObj _ [ toGo: seq.controlPointCount, segIndex: 0, cpIndex: 0, seq: seq ]]; }; NextControlPoint: PUBLIC PROC [cpGen: ControlPointGenerator] RETURNS [next: PointAndDone] = { seq: Sequence _ cpGen.seq; seg: Segment; segIndex: NAT _ cpGen.segIndex; cpIndex: NAT _ cpGen.cpIndex; hiSeg: NAT _ GGTraj.HiSegment[cpGen.seq.traj]; IF cpGen.toGo = 0 THEN RETURN[[[0,0], TRUE]]; FOR i: NAT IN [segIndex..hiSeg] DO FOR j: NAT IN [cpIndex..seq.controlPoints[i].len) DO IF seq.controlPoints[i][j] THEN { segIndex _ i; cpIndex _ j; GOTO Found; }; ENDLOOP; cpIndex _ 0; REPEAT Found => { seg _ GGTraj.FetchSegment[cpGen.seq.traj, segIndex]; next.point _ seg.class.controlPointGet[seg, cpIndex]; next.done _ FALSE; }; FINISHED => ERROR; ENDLOOP; cpGen.segIndex _ segIndex; cpGen.cpIndex _ cpIndex + 1; cpGen.toGo _ cpGen.toGo - 1; }; NextSegNumAndCPNum: PUBLIC PROC [cpGen: ControlPointGenerator] RETURNS [segNum, cpNum: NAT, done: BOOL] = { seq: Sequence _ cpGen.seq; segIndex: NAT _ cpGen.segIndex; cpIndex: NAT _ cpGen.cpIndex; hiSeg: NAT _ GGTraj.HiSegment[cpGen.seq.traj]; IF cpGen.toGo = 0 THEN RETURN[0, 0, TRUE]; FOR i: NAT IN [segIndex..hiSeg] DO FOR j: NAT IN [cpIndex..seq.controlPoints[i].len) DO IF seq.controlPoints[i][j] THEN { segIndex _ i; cpIndex _ j; GOTO Found; }; ENDLOOP; cpIndex _ 0; REPEAT Found => { segNum _ segIndex; cpNum _ cpIndex; done _ FALSE; }; FINISHED => ERROR; ENDLOOP; cpGen.segIndex _ segIndex; cpGen.cpIndex _ cpIndex + 1; cpGen.toGo _ cpGen.toGo - 1; }; JointsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [jointGen: JointGenerator] = { <> <> jointGen _ NEW[JointGeneratorObj _ [ -- this allocate is expensive too. traj: seq.traj, toGo: seq.jointCount, index: 0, seq: seq, completeSeq: FALSE -- I'll use this for optimization later, Bier March 10, 1986 5:03:42 pm PST <> ]]; }; JointsInTraj: PUBLIC PROC [traj: Traj] RETURNS [jointGen: JointGenerator] = { jointGen _ NEW[JointGeneratorObj _ [ traj: traj, toGo: GGTraj.HiJoint[traj] + 1, index: 0, seq: NIL, completeSeq: TRUE ]]; }; NextJoint: PUBLIC PROC [jointGen: JointGenerator] RETURNS [next: INT] = { seq: Sequence; index: NAT _ jointGen.index; IF jointGen.toGo = 0 THEN RETURN[-1]; IF jointGen.completeSeq THEN { next _ index; } ELSE { hiJoint: NAT _ GGTraj.HiJoint[jointGen.traj]; seq _ jointGen.seq; UNTIL seq.joints[index] OR index > hiJoint DO index _ index + 1; ENDLOOP; IF index > hiJoint THEN ERROR; next _ index; }; jointGen.index _ index + 1; jointGen.toGo _ jointGen.toGo - 1; }; SetStrokeWidth: PUBLIC PROC [seq: Sequence, strokeWidth: REAL] = { segGen: SegmentGenerator; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO seg.class.setStrokeWidth[seg, strokeWidth]; ENDLOOP; GGTraj.UpdateBoundBox[seq.traj]; }; GetStrokeWidth: PUBLIC PROC [seq: Sequence] RETURNS [strokeWidth: REAL _ 1.0] = { segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; seg: Segment _ GGSequence.NextSegment[segGen]; strokeWidth _ IF seg#NIL THEN seg.strokeWidth ELSE -1.0; <> }; SetStrokeEnd: PUBLIC PROC [seq: Sequence, strokeEnd: StrokeEnd] = { segGen: SegmentGenerator; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO seg.strokeEnd _ strokeEnd; ENDLOOP; }; GetStrokeEnd: PUBLIC PROC [seq: Sequence] RETURNS [strokeEnd: StrokeEnd] = { segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; seg: Segment _ GGSequence.NextSegment[segGen]; strokeEnd _ IF seg#NIL THEN seg.strokeEnd ELSE round; <> }; SetStrokeColor: PUBLIC PROC [seq: Sequence, color: Color] = { segGen: SegmentGenerator; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO seg.color _ color; ENDLOOP; }; GetStrokeColor: PUBLIC PROC [seq: Sequence] RETURNS [color: Imager.Color] = { segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; seg: Segment _ GGSequence.NextSegment[segGen]; IF seg#NIL THEN color _ seg.color; }; SetStrokeDashed: PUBLIC PROC [seq: Sequence, dashed: BOOL, pattern: SequenceOfReal _ NIL, offset: REAL _ 0.0, length: REAL _ -1.0] = { segGen: SegmentGenerator; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO seg.dashed _ dashed; seg.pattern _ pattern; seg.offset _ offset; seg.length _ length; ENDLOOP; }; GetStrokeDashed: PUBLIC PROC [seq: Sequence] RETURNS [dashed: BOOL, pattern: SequenceOfReal, offset, length: REAL] = { segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; seg: Segment _ GGSequence.NextSegment[segGen]; IF seg#NIL THEN { dashed _ seg.dashed; pattern _ seg.pattern; offset _ seg.offset; length _ seg.length; } ELSE RETURN[FALSE, NIL, 0.0, 0.0]; }; END.