<> <> <> <> <> <<>> DIRECTORY GGBoundBox, GGError, GGObjects, GGModelTypes, GGSegment, GGTransform, GGUtility, GGVector, Imager, ImagerPath, ImagerTransformation, Rope, Rosary; GGObjectsImpl: CEDAR PROGRAM IMPORTS GGBoundBox, GGError, GGObjects, GGSegment, GGTransform, GGUtility, GGVector, Imager, ImagerTransformation, Rosary EXPORTS GGObjects = BEGIN BoundBox: TYPE = GGModelTypes.BoundBox; BoundBoxGenerator: TYPE = REF BoundBoxGeneratorObj; BoundBoxGeneratorObj: TYPE = GGModelTypes.BoundBoxGeneratorObj; Camera: TYPE = GGModelTypes.Camera; Cluster: TYPE = GGModelTypes.Cluster; EntityGenerator: TYPE = REF EntityGeneratorObj; EntityGeneratorObj: TYPE = GGModelTypes.EntityGeneratorObj; JointGenerator: TYPE = REF JointGeneratorObj; JointGeneratorObj: TYPE = GGModelTypes.JointGeneratorObj; JointPair: TYPE = GGModelTypes.JointPair; Outline: TYPE = REF OutlineObj; OutlineObj: TYPE = GGModelTypes.OutlineObj; Point: TYPE = GGModelTypes.Point; Scene: TYPE = REF SceneObj; SceneObj: TYPE = GGModelTypes.SceneObj; SegmentGenerator: TYPE = REF SegmentGeneratorObj; SegmentGeneratorObj: TYPE = GGModelTypes.SegmentGeneratorObj; SequenceGenerator: TYPE = REF SequenceGeneratorObj; SequenceGeneratorObj: TYPE = GGModelTypes.SequenceGeneratorObj; Sequence: TYPE = REF SequenceObj; SequenceObj: TYPE = GGModelTypes.SequenceObj; TrajGenerator: TYPE = REF TrajGeneratorObj; TrajGeneratorObj: TYPE = GGModelTypes.TrajGeneratorObj; Vector: TYPE = GGModelTypes.Vector; Traj: TYPE = REF TrajObj; TrajObj: TYPE = GGModelTypes.TrajObj; TrajEnd: TYPE = GGModelTypes.TrajEnd; -- {lo, hi}; Joint: TYPE = REF JointObj; JointObj: TYPE = GGModelTypes.JointObj; CurveType: TYPE = {line, bezier, conic}; Segment: TYPE = REF SegmentObj; SegmentObj: TYPE = GGModelTypes.SegmentObj; <<>> <> CreateTraj: PUBLIC PROC [point: Point] RETURNS [traj: Traj] = { firstJoint: Joint _ NEW[JointObj _ [point: point]]; bBox: BoundBox _ GGBoundBox.CreateBoundBox[point[1], point[2], point[1], point[2]]; traj _ NEW[TrajObj _ [open, 0, NIL, Rosary.FromItem[firstJoint], NIL, NIL, bBox, FALSE]]; }; OutlineFromTraj: PUBLIC PROC [traj: Traj, lineEnds: Imager.StrokeEnd _ square, fillColor: Imager.Color _ Imager.black] RETURNS [outline: Outline] = { boundBox: BoundBox _ GGBoundBox.CopyBoundBox[traj.boundBox]; outline _ NEW[OutlineObj _ [ fillColor: fillColor, lineEnds: lineEnds, children: LIST[traj], parent: NIL, boundBox: boundBox]]; traj.outline _ outline; }; SetLineEnds: PUBLIC PROC [outline: Outline, lineEnds: Imager.StrokeEnd] = { outline.lineEnds _ lineEnds; }; SetFillColor: PUBLIC PROC [outline: Outline, fillColor: Imager.Color] = { outline.fillColor _ fillColor; }; AddSegment: PUBLIC PROC [traj: Traj, trajEnd: TrajEnd, seg: Segment, segEnd: TrajEnd] RETURNS [success: BOOL] = { diff: Vector; loJoint, hiJoint: Joint; <> IF traj.role = fence OR traj.role = hole THEN { GGError.Append["Can't AddSegment to a closed trajectory. Ignored.", oneLiner]; GGError.Blink[]; RETURN[FALSE]; }; success _ TRUE; IF traj.segCount = 0 THEN { -- this is the first segment traj.segCount _ 1; traj.segments _ Rosary.FromItem[seg]; loJoint _ NEW[JointObj _ [point: seg.lo]]; hiJoint _ NEW[JointObj _ [point: seg.hi]]; traj.joints _ Rosary.FromList[LIST[loJoint, hiJoint]]; traj.boundBox _ GGBoundBox.CopyBoundBox[seg.boundBox]; } ELSE { IF trajEnd = segEnd THEN GGSegment.ReverseSegment[seg]; IF trajEnd = lo THEN { diff _ GGVector.Sub[FetchJointPos[traj, 0], seg.hi]; TranslateSegment[seg, diff]; loJoint _ NEW[JointObj _ [point: seg.lo]]; traj.joints _ Rosary.Concat[Rosary.FromItem[loJoint], traj.joints]; traj.segments _ Rosary.Concat[Rosary.FromItem[seg], traj.segments]; traj.segCount _ traj.segCount + 1; GGBoundBox.EnlargeBoundBox[traj.boundBox, seg.boundBox]; } ELSE { diff _ GGVector.Sub[FetchJointPos[traj, traj.segCount], seg.lo]; TranslateSegment[seg, diff]; hiJoint _ NEW[JointObj _ [point: seg.hi]]; traj.joints _ Rosary.Concat[traj.joints, Rosary.FromItem[hiJoint]]; traj.segments _ Rosary.Concat[traj.segments, Rosary.FromItem[seg]]; traj.segCount _ traj.segCount + 1; GGBoundBox.EnlargeBoundBox[traj.boundBox, seg.boundBox]; } } }; NotYetImplemented: PUBLIC SIGNAL = CODE; CloseWithSegment: PUBLIC PROC [traj: Traj, seg: Segment, segEnd: TrajEnd] = { <> diff: Vector; IF traj.segCount = 0 THEN ERROR NotYetImplemented; -- a single closed segment. <> IF segEnd = hi THEN GGSegment.ReverseSegment[seg]; diff _ GGVector.Sub[LastJointPos[traj], seg.lo]; seg.lo _ GGVector.Add[seg.lo, diff]; seg.hi _ GGVector.Add[seg.hi, diff]; traj.segments _ Rosary.Concat[traj.segments, Rosary.FromItem[seg]]; traj.segCount _ traj.segCount + 1; traj.role _ fence; GGBoundBox.EnlargeBoundBox[traj.boundBox, seg.boundBox]; }; <<>> <> <> <> <> <<>> <> <> <<>> ExtractTraj: PUBLIC PROC [original: Traj, start: INT, len: INT] RETURNS [piece: Traj] = { <> originalSegments: Rosary.ROSARY _ original.segments; desiredSegments: Rosary.Segment _ [originalSegments, start, len]; extractedSegments: Rosary.ROSARY; originalJoints: Rosary.ROSARY _ original.joints; desiredJoints: Rosary.Segment _ [originalJoints, start, len]; extractedJoints: Rosary.ROSARY; CopyEachSegment: PROC[q: PROC[item: Rosary.Item, repeat: INT _ 1]] = { CopySegmentAndBuild: PROC [item: Rosary.Item] RETURNS [quit: BOOLEAN _ FALSE] = { copy, oldSeg: Segment; oldSeg _ NARROW[item]; copy _ GGSegment.CopySegment[oldSeg]; q[copy, 1]; }; [] _ Rosary.Map[desiredSegments, CopySegmentAndBuild]; }; CopyEachJoint: PROC[q: PROC[item: Rosary.Item, repeat: INT _ 1]] = { CopyJointAndBuild: PROC [item: Rosary.Item] RETURNS [quit: BOOLEAN _ FALSE] = { copy, oldJoint: Joint; oldJoint _ NARROW[item]; copy _ CopyJointSelectedFalse[oldJoint]; q[copy, 1]; }; [] _ Rosary.Map[desiredJoints, CopyJointAndBuild]; }; extractedSegments _ Rosary.FromProcProc[CopyEachSegment]; extractedJoints _ Rosary.FromProcProc[CopyEachJoint]; piece _ NEW[TrajObj _ [fence, len, extractedSegments, extractedJoints, NIL, NIL, NIL, original.visibleJoints, original.strokeJoint ]]; <> piece.boundBox _ GGBoundBox.BoundBoxOfTraj[piece]; }; CopyTraj: PUBLIC PROC [original: Traj] RETURNS [copy: Traj] = { <> originalSegments: Rosary.ROSARY _ original.segments; desiredSegments: Rosary.Segment _ [originalSegments, 0, HiSegment[original]]; extractedSegments: Rosary.ROSARY; originalJoints: Rosary.ROSARY _ original.joints; desiredJoints: Rosary.Segment _ [originalJoints, 0, HiJoint[original]]; extractedJoints: Rosary.ROSARY; CopyEachSegment: PROC[q: PROC[item: Rosary.Item, repeat: INT _ 1]] = { CopySegmentAndBuild: PROC [item: Rosary.Item] RETURNS [quit: BOOLEAN _ FALSE] = { copy, oldSeg: Segment; oldSeg _ NARROW[item]; copy _ GGSegment.CopySegment[oldSeg]; q[copy, 1]; }; [] _ Rosary.Map[desiredSegments, CopySegmentAndBuild]; }; CopyEachJoint: PROC[q: PROC[item: Rosary.Item, repeat: INT _ 1]] = { CopyJointAndBuild: PROC [item: Rosary.Item] RETURNS [quit: BOOLEAN _ FALSE] = { copy, oldJoint: Joint; oldJoint _ NARROW[item]; copy _ CopyJointSelectedFalse[oldJoint]; q[copy, 1]; }; [] _ Rosary.Map[desiredJoints, CopyJointAndBuild]; }; extractedSegments _ Rosary.FromProcProc[CopyEachSegment]; extractedJoints _ Rosary.FromProcProc[CopyEachJoint]; copy _ NEW[TrajObj _ [original.role, original.segCount, extractedSegments, extractedJoints, NIL, NIL, NIL, original.visibleJoints, original.strokeJoint ]]; <> copy.boundBox _ GGBoundBox.BoundBoxOfTraj[original]; }; <> <<>> <> <> <> CreateScene: PUBLIC PROC [] RETURNS [scene: Scene] = { scene _ NEW[SceneObj _ [entities: NIL]]; }; AddOutline: PUBLIC PROC [scene: Scene, outline: Outline, priority: INT _ -1] = { <> <> scene.entities _ CONS[outline, scene.entities]; }; <> <> <<};>> <<>> DeleteOutline: PUBLIC PROC [scene: Scene, outline: Outline] = { scene.entities _ GGUtility.DeleteEntityFromList[outline, scene.entities]; }; <<>> <> TopLevelEntities: PUBLIC PROC [scene: Scene] RETURNS [entityGenerator: EntityGenerator] = { <> list: LIST OF REF ANY _ scene.entities; entityGenerator _ NEW[EntityGeneratorObj _ [ list: list ]]; }; EntitiesInCluster: PUBLIC PROC [cluster: Cluster] RETURNS [entityGenerator: EntityGenerator] = { <> list: LIST OF REF ANY _ cluster.children; entityGenerator _ NEW[EntityGeneratorObj _ [ list: list ]]; }; NextEntity: PUBLIC PROC [g: EntityGenerator] RETURNS [next: REF ANY] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; TrajsInScene: PUBLIC PROC [scene: Scene] RETURNS [trajGen: TrajGenerator] = { <> list: LIST OF Traj _ ListTrajsInScene[scene]; trajGen _ NEW[TrajGeneratorObj _ [ list: list ]]; }; TrajsInOutline: PUBLIC PROC [outline: Outline] RETURNS [trajGen: TrajGenerator] = { <> list: LIST OF Traj _ outline.children; trajGen _ NEW[TrajGeneratorObj _ [ list: list ]]; }; HasHoles: PUBLIC PROC [outline: Outline] RETURNS [BOOL] = { RETURN[outline.children.rest # NIL]; }; HolesOfOutline: PUBLIC PROC [outline: Outline] RETURNS [trajGen: TrajGenerator] = { <> list: LIST OF Traj _ outline.children.rest; trajGen _ NEW[TrajGeneratorObj _ [ list: list ]]; }; FenceOfOutline: PUBLIC PROC [outline: Outline] RETURNS [fence: Traj] = { <> fence _ outline.children.first; }; NextTraj: PUBLIC PROC [g: TrajGenerator] RETURNS [next: Traj] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; SegmentsInTraj: PUBLIC PROC [traj: Traj] RETURNS [segGen: SegmentGenerator] = { segGen _ NEW[SegmentGeneratorObj _ [ traj: traj, toGo: traj.segCount, index: 0, nextParts: NIL ]]; }; SegmentsInJointPair: PUBLIC PROC [traj: Traj, start: NAT, end: INT] RETURNS [segGen: SegmentGenerator] = { toGo: NAT; IF start > HiJoint[traj] OR end > HiJoint[traj] OR end < -1 THEN ERROR; IF traj.role = open THEN { IF end < start THEN toGo _ 0 ELSE toGo _ end - start; } ELSE { IF start = end THEN toGo _ 0 ELSE IF start < end THEN toGo _ end - start ELSE toGo _ traj.segCount - start + end; }; segGen _ NEW[SegmentGeneratorObj _ [ traj: traj, toGo: toGo, index: start, nextParts: NIL ]]; }; SegmentsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [segGen: SegmentGenerator] = { start, end: NAT; IF seq.parts = NIL THEN ERROR; IF seq.all THEN RETURN[SegmentsInTraj[seq.traj]]; start _ seq.parts.first.start; end _ seq.parts.first.end; segGen _ SegmentsInJointPair[seq.traj, start, end]; segGen.nextParts _ seq.parts.rest; }; InMODRegion: PUBLIC PROC [test: NAT, start, end, mod: NAT] RETURNS [BOOL] = { IF start = end THEN RETURN [test = start]; IF start < end THEN RETURN [test IN [start..end]]; RETURN [test IN [start..mod) OR test IN [0..end]]; }; PreviousSegment: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [prev: Segment] = { IF traj.role = open THEN { IF segNum = 0 THEN RETURN[NIL] ELSE prev _ FetchSegment[traj, segNum - 1]; } ELSE { prev _ FetchSegment[traj, (segNum-1+traj.segCount) MOD traj.segCount]; }; }; PreviousSegmentNum: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [prevNum: NAT] = { IF traj.role = open THEN { IF segNum = 0 THEN ERROR ELSE prevNum _ segNum - 1; } ELSE { prevNum _ (segNum-1+traj.segCount) MOD traj.segCount; }; }; FollowingSegmentNum: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [followNum: NAT] = { IF traj.role = open THEN { IF segNum = HiSegment[traj] THEN ERROR ELSE followNum _ segNum + 1; } ELSE { followNum _ (segNum+1) MOD traj.segCount; }; }; NextSegment: PUBLIC PROC [segGen: SegmentGenerator] RETURNS [next: Segment] = { start, end: NAT; toGo: NAT; UNTIL segGen.toGo > 0 DO IF segGen.nextParts = NIL THEN RETURN[NIL]; start _ segGen.nextParts.first.start; end _ segGen.nextParts.first.end; segGen.nextParts _ segGen.nextParts.rest; IF segGen.traj.role = open THEN { IF end < start THEN toGo _ 0 ELSE toGo _ end - start; } ELSE { IF start = end THEN toGo _ 0 ELSE IF start < end THEN toGo _ end - start ELSE toGo _ segGen.traj.segCount - end + start - 2; }; segGen.toGo _ toGo; segGen.index _ start; ENDLOOP; next _ FetchSegment[segGen.traj, segGen.index]; segGen.toGo _ segGen.toGo - 1; IF segGen.traj.role = open THEN { segGen.index _ segGen.index + 1; } ELSE { segGen.index _ (segGen.index + 1) MOD segGen.traj.segCount; }; }; SegAndIndex: TYPE = GGObjects.SegAndIndex; NextSegmentAndIndex: PUBLIC PROC [segGen: SegmentGenerator] RETURNS [next: SegAndIndex] = { start, end: NAT; toGo: NAT; UNTIL segGen.toGo > 0 DO IF segGen.nextParts = NIL THEN RETURN[[NIL, 999]]; start _ segGen.nextParts.first.start; end _ segGen.nextParts.first.end; segGen.nextParts _ segGen.nextParts.rest; IF segGen.traj.role = open THEN { IF end < start THEN toGo _ 0 ELSE toGo _ end - start; } ELSE { IF start = end THEN toGo _ 0 ELSE IF start < end THEN toGo _ end - start ELSE toGo _ segGen.traj.segCount - end + start - 2; }; segGen.toGo _ toGo; segGen.index _ start; ENDLOOP; next.seg _ FetchSegment[segGen.traj, segGen.index]; next.index _ segGen.index; segGen.toGo _ segGen.toGo - 1; IF segGen.traj.role = open THEN { segGen.index _ segGen.index + 1; } ELSE { segGen.index _ (segGen.index + 1) MOD segGen.traj.segCount; }; }; <<>> JointsInJointPair: PUBLIC PROC [traj: Traj, start: NAT, end: INT] RETURNS [jointGen: JointGenerator] = { toGo: NAT; SELECT traj.role FROM open => { IF end < start THEN toGo _ 0 ELSE toGo _ end - start + 1; }; fence, hole => { IF start = end THEN toGo _ 1 ELSE IF start < end THEN toGo _ end - start + 1 ELSE toGo _ traj.segCount - start + end + 1; }; ENDCASE => ERROR; jointGen _ NEW[JointGeneratorObj _ [ traj: traj, toGo: toGo, index: start]]; }; JointsInSequence: PUBLIC PROC [seq: Sequence] RETURNS [jointGen: JointGenerator] = { start, end: NAT; IF seq.parts = NIL THEN { jointGen _ NEW[JointGeneratorObj _ [ traj: seq.traj, toGo: 0, index: 0]]; RETURN; }; IF seq.all THEN RETURN[JointsInTraj[seq.traj]]; start _ seq.parts.first.start; end _ seq.parts.first.end; jointGen _ JointsInJointPair[seq.traj, start, end]; jointGen.nextParts _ seq.parts.rest; }; JointsInTraj: PUBLIC PROC [traj: Traj] RETURNS [jointGen: JointGenerator] = { start, end: NAT; start _ 0; end _ GGObjects.HiJoint[traj]; jointGen _ JointsInJointPair[traj, start, end]; jointGen.nextParts _ NIL; }; NextJoint: PUBLIC PROC [jointGen: JointGenerator] RETURNS [next: INT] = { start, end: NAT; toGo: NAT; UNTIL jointGen.toGo > 0 DO IF jointGen.nextParts = NIL THEN RETURN[-1]; start _ jointGen.nextParts.first.start; end _ jointGen.nextParts.first.end; jointGen.nextParts _ jointGen.nextParts.rest; IF jointGen.traj.role = open THEN { IF end < start THEN toGo _ 0 ELSE toGo _ end - start + 1; } ELSE { IF start = end THEN toGo _ 1 ELSE IF start < end THEN toGo _ end - start + 1 ELSE toGo _ jointGen.traj.segCount - end + start - 1; }; jointGen.toGo _ toGo; jointGen.index _ start; ENDLOOP; next _ jointGen.index; jointGen.toGo _ jointGen.toGo - 1; IF jointGen.traj.role = open THEN { jointGen.index _ jointGen.index + 1; } ELSE { jointGen.index _ (jointGen.index + 1) MOD jointGen.traj.segCount; }; }; BoundBoxesInScene: PUBLIC PROC [scene: Scene] RETURNS [bBoxGen: BoundBoxGenerator] = { <> list: LIST OF BoundBox _ ListBoxesInScene[scene]; bBoxGen _ NEW[BoundBoxGeneratorObj _ [ list: list ]]; }; NextBox: PUBLIC PROC [g: BoundBoxGenerator] RETURNS [next: BoundBox] = { IF g.list = NIL THEN RETURN[NIL] ELSE { next _ g.list.first; g.list _ g.list.rest; }; }; <<>> <> <<>> AppendTrajs: PUBLIC PROC [l1, l2: LIST OF Traj] RETURNS [result: LIST OF Traj] = { <> z: LIST OF Traj _ l1; IF z = NIL THEN RETURN[l2]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ l2; RETURN[l1]; }; AppendBoxes: PUBLIC PROC [l1, l2: LIST OF BoundBox] RETURNS [result: LIST OF BoundBox] = { <> z: LIST OF BoundBox _ l1; IF z = NIL THEN RETURN[l2]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ l2; RETURN[l1]; }; ListBoxesInScene: PUBLIC PROC [scene: Scene] RETURNS [allBoxes: LIST OF BoundBox] = { allBoxes _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM cluster: Cluster => { allBoxes _ AppendBoxes[ListBoxesInCluster[cluster], allBoxes]; }; outline: Outline => { FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO allBoxes _ CONS[trajs.first.boundBox, allBoxes]; ENDLOOP; }; ENDCASE => ERROR; ENDLOOP; }; ListBoxesInCluster: PUBLIC PROC [cluster: Cluster] RETURNS [allBoxes: LIST OF BoundBox] = { allBoxes _ NIL; FOR children: LIST OF REF ANY _ cluster.children, children.rest UNTIL children = NIL DO WITH children.first SELECT FROM outline: Outline => { FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO allBoxes _ CONS[trajs.first.boundBox, allBoxes]; ENDLOOP; }; cluster: Cluster => { allBoxes _ AppendBoxes[ListBoxesInCluster[cluster], allBoxes]; }; ENDCASE => ERROR; ENDLOOP; }; ListTrajsInScene: PUBLIC PROC [scene: Scene] RETURNS [allTrajs: LIST OF Traj] = { allTrajs _ NIL; FOR entities: LIST OF REF ANY _ scene.entities, entities.rest UNTIL entities = NIL DO WITH entities.first SELECT FROM cluster: Cluster => { allTrajs _ AppendTrajs[ListTrajsInCluster[cluster], allTrajs]; }; outline: Outline => { FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO allTrajs _ CONS[trajs.first, allTrajs]; ENDLOOP; }; ENDCASE => ERROR; ENDLOOP; }; ListTrajsInOutline: PROC [outline: Outline] RETURNS [trajList: LIST OF Traj] = { trajList _ outline.children; }; ListHolesOfOutline: PROC [outline: Outline] RETURNS [trajList: LIST OF Traj] = { trajList _ outline.children.rest; }; ListTrajsInCluster: PUBLIC PROC [cluster: Cluster] RETURNS [allTrajs: LIST OF Traj] = { allTrajs _ NIL; FOR children: LIST OF REF ANY _ cluster.children, children.rest UNTIL children = NIL DO WITH children.first SELECT FROM outline: Outline => { FOR trajs: LIST OF Traj _ outline.children, trajs.rest UNTIL trajs = NIL DO allTrajs _ CONS[trajs.first, allTrajs]; ENDLOOP; }; cluster: Cluster => { allTrajs _ AppendTrajs[ListTrajsInCluster[cluster], allTrajs]; }; ENDCASE => ERROR; ENDLOOP; }; ListSegmentsInTraj: PROC [traj: Traj] RETURNS [segList: LIST OF Segment] = { segList _ NIL; FOR i: NAT DECREASING IN [0..HiSegment[traj]] DO segList _ CONS[FetchSegment[traj, i], segList]; ENDLOOP; }; <> OutlineOfTraj: PUBLIC PROC [traj: Traj] RETURNS [outline: Outline] = { <> outline _ traj.outline; }; <<>> <> HiSegment: PUBLIC PROC [traj: Traj] RETURNS [highestIndex: NAT] = { highestIndex _ traj.segCount - 1; }; FetchSegment: PUBLIC PROC [traj: Traj, index: NAT] RETURNS [seg: Segment] = { seg _ NARROW[Rosary.Fetch[traj.segments, index]]; }; HiJoint: PUBLIC PROC [traj: Traj] RETURNS [highestIndex: NAT] = { SELECT traj.role FROM open => highestIndex _ traj.segCount; fence, hole => highestIndex _ traj.segCount -1; ENDCASE => ERROR; }; FollowingJoint: PUBLIC PROC [traj: Traj, index: NAT] RETURNS [nextIndex: NAT] = { SELECT traj.role FROM open => { IF index = traj.segCount THEN ERROR; nextIndex _ index + 1; }; fence, hole => nextIndex _ (index + 1) MOD traj.segCount; ENDCASE => ERROR; }; FetchJointPos: PUBLIC PROC [traj: Traj, index: NAT] RETURNS [point: Point] = { joint: Joint; IF index < 0 OR index > HiJoint[traj] THEN ERROR; joint _ NARROW[Rosary.Fetch[traj.joints, index]]; point _ joint.point }; LastJointPos: PUBLIC PROC [traj: Traj] RETURNS [point: Point] = { joint: Joint _ NARROW[Rosary.Fetch[traj.joints, traj.segCount]]; point _ joint.point }; SetJointPos: PUBLIC PROC [traj: Traj, index: NAT, newPos: Point] = { <> joint: Joint _ NARROW[Rosary.Fetch[traj.joints, index]]; segLeft, segRight: Segment; joint.point _ newPos; IF index > 0 THEN { segLeft _ FetchSegment[traj, index-1]; segLeft.hi _ newPos; }; IF index < traj.segCount THEN { segRight _ FetchSegment[traj, index]; segRight.lo _ newPos; }; }; IsEndJoint: PUBLIC PROC [traj: Traj, index: NAT] RETURNS [BOOL] = { SELECT traj.role FROM open => RETURN[index = 0 OR index = traj.segCount]; fence, hole => RETURN[FALSE]; ENDCASE => ERROR; }; CopyJointSelectedFalse: PROC [joint: Joint] RETURNS [copy: Joint] = { copy _ NEW[JointObj _ [ point: joint.point, selected: [ normal: FALSE, copy: FALSE, hot: FALSE, active: FALSE ] ]]; }; <> <<>> FetchJoint: PUBLIC PROC [traj: Traj, index: NAT] RETURNS [joint: Joint] = { joint _ NARROW[Rosary.Fetch[traj.joints, index]]; }; IndexOfJoint: PUBLIC PROC [joint: Joint, traj: Traj] RETURNS [index: INT] = { <> thisJoint: Joint; FOR i: NAT IN [0..HiJoint[traj]] DO thisJoint _ FetchJoint[traj, i]; IF thisJoint = joint THEN RETURN[i]; ENDLOOP; RETURN[-1]; }; IndexOfSegment: PUBLIC PROC [segment: Segment, traj: Traj] RETURNS [index: INT] = { <> thisSeg: Segment; FOR i: NAT IN [0..HiSegment[traj]] DO thisSeg _ FetchSegment[traj, i]; IF thisSeg = segment THEN RETURN[i]; ENDLOOP; RETURN[-1]; }; <<>> CreateSimpleSequence: PUBLIC PROC [traj: Traj, start, end: NAT] RETURNS [seq: Sequence] = { seq _ NEW[SequenceObj _ [ traj: traj, all: FALSE, parts: LIST[[start, end]], boundBox: GGBoundBox.CopyBoundBox[traj.boundBox] ]]; }; CreateEmptySequence: PUBLIC PROC [traj: Traj] RETURNS [seq: Sequence] = { seq _ NEW[SequenceObj _ [ traj: traj, all: FALSE, parts: NIL, boundBox: NIL]]; }; CreateCompleteSequence: PUBLIC PROC [traj: Traj] RETURNS [seq: Sequence] = { <> seq _ NEW[SequenceObj _ [ traj: traj, all: TRUE, parts: LIST[[0,0]], boundBox: GGBoundBox.CopyBoundBox[traj.boundBox] ]]; }; CreateSequenceFromJoint: PUBLIC PROC [traj: Traj, jointNum: NAT] RETURNS [seq: Sequence] = { seq _ CreateSimpleSequence[traj, jointNum, jointNum]; }; CreateSequenceFromSegment: PUBLIC PROC [traj: Traj, segNum: NAT] RETURNS [seq: Sequence] = { nextJointNum: NAT _ FollowingJoint[traj, segNum]; seq _ CreateSimpleSequence[traj, segNum, nextJointNum]; }; AddPart: PUBLIC PROC [seq: Sequence, start, end: NAT] = { <> z: LIST OF JointPair _ seq.parts; IF z = NIL THEN { seq.parts _ CONS[[start, end], NIL]; RETURN; }; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ CONS[[start, end], NIL]; }; BitArray: TYPE = REF BitArrayObj; BitArrayObj: TYPE = RECORD [ seq: SEQUENCE len: NAT OF BOOL]; SequencesOverlap: PUBLIC PROC [seq1, seq2: Sequence] RETURNS [BOOL] = { segBits1, segBits2, jointBits1, jointBits2: BitArray; segBits1 _ NEW[BitArrayObj[seq1.traj.segCount]]; segBits2 _ NEW[BitArrayObj[seq2.traj.segCount]]; jointBits1 _ NEW[BitArrayObj[seq1.traj.segCount + 1]]; jointBits2 _ NEW[BitArrayObj[seq2.traj.segCount + 1]]; <> InitializeCombine[seq1, seq2, jointBits1, jointBits2, segBits1, segBits2]; <> FOR i: NAT IN [0..GGObjects.HiSegment[seq1.traj]] DO IF segBits1[i] AND segBits2[i] THEN RETURN[TRUE]; ENDLOOP; <> FOR i: NAT IN [0..GGObjects.HiJoint[seq1.traj]] DO IF jointBits1[i] AND jointBits2[i] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; CombineSequences: PUBLIC PROC [new, old: Sequence] RETURNS [union: Sequence, newMinusOld: Sequence] = { IF new.traj # old.traj THEN ERROR; IF new.traj.role = open THEN [union, newMinusOld] _ CombineSequencesOpen[new, old] ELSE { [union, newMinusOld] _ CombineSequencesOpen[new, old]; IF new.all THEN union _ new; -- kludge until CombineSequencesClosed is done IF old.all THEN union _ old; }; }; InitializeCombine: PROC [new, old: Sequence, newJointBits, oldJointBits, newSegmentBits, oldSegmentBits: BitArray] = { segGen: SegmentGenerator; jointGen: JointGenerator; <> FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO newSegmentBits[i] _ FALSE; oldSegmentBits[i] _ FALSE; ENDLOOP; FOR i: NAT IN [0..GGObjects.HiJoint[new.traj]] DO newJointBits[i] _ FALSE; oldJointBits[i] _ FALSE; ENDLOOP; <> segGen _ SegmentsInSequence[new]; FOR next: GGObjects.SegAndIndex _ NextSegmentAndIndex[segGen], NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO newSegmentBits[next.index] _ TRUE; ENDLOOP; jointGen _ JointsInSequence[new]; FOR index: INT _ NextJoint[jointGen], NextJoint[jointGen] UNTIL index = -1 DO newJointBits[index] _ TRUE; ENDLOOP; <> segGen _ SegmentsInSequence[old]; FOR next: GGObjects.SegAndIndex _ NextSegmentAndIndex[segGen], NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO oldSegmentBits[next.index] _ TRUE; ENDLOOP; jointGen _ JointsInSequence[old]; FOR index: INT _ NextJoint[jointGen], NextJoint[jointGen] UNTIL index = -1 DO oldJointBits[index] _ TRUE; ENDLOOP; }; CombineSequencesOpen: PROC [new, old: Sequence] RETURNS [union: Sequence, newMinusOld: Sequence] = { unionJointBit, diffJointBit, unionSegmentBit, diffSegmentBit, lastSegmentBit, lastJointBit: BOOL; newJointBits, oldJointBits, newSegmentBits, oldSegmentBits: BitArray; start, end: NAT; newSegmentBits _ NEW[BitArrayObj[new.traj.segCount]]; oldSegmentBits _ NEW[BitArrayObj[new.traj.segCount]]; newJointBits _ NEW[BitArrayObj[new.traj.segCount + 1]]; oldJointBits _ NEW[BitArrayObj[new.traj.segCount + 1]]; <> InitializeCombine[new, old, newJointBits, oldJointBits, newSegmentBits, oldSegmentBits]; <> FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO unionSegmentBit _ newSegmentBits[i] OR oldSegmentBits[i]; diffSegmentBit _ newSegmentBits[i] AND NOT oldSegmentBits[i]; newSegmentBits[i] _ unionSegmentBit; oldSegmentBits[i] _ diffSegmentBit; ENDLOOP; <> FOR i: NAT IN [0..GGObjects.HiJoint[new.traj]] DO unionJointBit _ newJointBits[i] OR oldJointBits[i]; diffJointBit _ newJointBits[i] AND NOT oldJointBits[i]; newJointBits[i] _ unionJointBit; oldJointBits[i] _ diffJointBit; ENDLOOP; <<>> <> union _ GGObjects.CreateEmptySequence[new.traj]; lastSegmentBit _ FALSE; FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO IF NOT lastSegmentBit AND newJointBits[i] THEN { -- The start of a new part start _ i; }; IF lastSegmentBit AND NOT newJointBits[i] THEN ERROR; lastJointBit _ newJointBits[i]; IF lastJointBit AND NOT newSegmentBits[i] THEN { -- the end of the current part end _ i; GGObjects.AddPart[union, start, end]; }; lastSegmentBit _ newSegmentBits[i]; REPEAT FINISHED => { IF NOT lastSegmentBit AND newJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { <> start _ end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[union, start, end]; } ELSE IF lastSegmentBit THEN { end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[union, start, end]; }; }; ENDLOOP; <> newMinusOld _ GGObjects.CreateEmptySequence[new.traj]; lastSegmentBit _ FALSE; FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO IF NOT lastSegmentBit AND oldJointBits[i] THEN { -- The start of a new part start _ i; }; IF lastSegmentBit AND NOT oldJointBits[i] THEN { <> end _ i-1; GGObjects.AddPart[newMinusOld, start, end]; }; lastJointBit _ oldJointBits[i]; IF lastJointBit AND NOT oldSegmentBits[i] THEN { -- the end of the current part end _ i; GGObjects.AddPart[newMinusOld, start, end]; }; IF NOT lastJointBit AND oldSegmentBits[i] THEN { <> lastSegmentBit _ FALSE; } ELSE lastSegmentBit _ oldSegmentBits[i]; REPEAT FINISHED => { IF NOT lastSegmentBit AND oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { <> start _ end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[newMinusOld, start, end]; } ELSE IF lastSegmentBit AND NOT oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { <> end _ GGObjects.HiSegment[new.traj]; GGObjects.AddPart[newMinusOld, start, end]; } ELSE IF lastSegmentBit THEN { end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[newMinusOld, start, end]; }; }; ENDLOOP; }; CombineSequencesClosed: PROC [new, old: Sequence] RETURNS [union: Sequence, newMinusOld: Sequence] = { <> unionJointBit, diffJointBit, unionSegmentBit, diffSegmentBit, lastSegmentBit, lastJointBit: BOOL; newJointBits, oldJointBits, newSegmentBits, oldSegmentBits: BitArray; start, end: NAT; newSegmentBits _ NEW[BitArrayObj[new.traj.segCount]]; oldSegmentBits _ NEW[BitArrayObj[new.traj.segCount]]; newJointBits _ NEW[BitArrayObj[new.traj.segCount]]; oldJointBits _ NEW[BitArrayObj[new.traj.segCount]]; <> InitializeCombine[new, old, newJointBits, oldJointBits, newSegmentBits, oldSegmentBits]; <> FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO unionSegmentBit _ newSegmentBits[i] OR oldSegmentBits[i]; diffSegmentBit _ newSegmentBits[i] AND NOT oldSegmentBits[i]; newSegmentBits[i] _ unionSegmentBit; oldSegmentBits[i] _ diffSegmentBit; ENDLOOP; <> FOR i: NAT IN [0..GGObjects.HiJoint[new.traj]] DO unionJointBit _ newJointBits[i] OR oldJointBits[i]; diffJointBit _ newJointBits[i] AND NOT oldJointBits[i]; newJointBits[i] _ unionJointBit; oldJointBits[i] _ diffJointBit; ENDLOOP; <<>> <> union _ GGObjects.CreateEmptySequence[new.traj]; lastSegmentBit _ newSegmentBits[HiSegment[new.traj]]; FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO IF NOT lastSegmentBit AND newJointBits[i] THEN { -- The start of a new part start _ i; }; IF lastSegmentBit AND NOT newJointBits[i] THEN ERROR; lastJointBit _ newJointBits[i]; IF lastJointBit AND NOT newSegmentBits[i] THEN { -- the end of the current part end _ i; GGObjects.AddPart[union, start, end]; }; lastSegmentBit _ newSegmentBits[i]; REPEAT FINISHED => { IF NOT lastSegmentBit AND newJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { <> start _ end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[union, start, end]; } ELSE IF lastSegmentBit THEN { end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[union, start, end]; }; }; ENDLOOP; <> newMinusOld _ GGObjects.CreateEmptySequence[new.traj]; lastSegmentBit _ FALSE; FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO IF NOT lastSegmentBit AND oldJointBits[i] THEN { -- The start of a new part start _ i; }; IF lastSegmentBit AND NOT oldJointBits[i] THEN { <> end _ i-1; GGObjects.AddPart[newMinusOld, start, end]; }; lastJointBit _ oldJointBits[i]; IF lastJointBit AND NOT oldSegmentBits[i] THEN { -- the end of the current part end _ i; GGObjects.AddPart[newMinusOld, start, end]; }; IF NOT lastJointBit AND oldSegmentBits[i] THEN { <> lastSegmentBit _ FALSE; } ELSE lastSegmentBit _ oldSegmentBits[i]; REPEAT FINISHED => { IF NOT lastSegmentBit AND oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { <> start _ end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[newMinusOld, start, end]; } ELSE IF lastSegmentBit AND NOT oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { <> end _ GGObjects.HiSegment[new.traj]; GGObjects.AddPart[newMinusOld, start, end]; } ELSE IF lastSegmentBit THEN { end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[newMinusOld, start, end]; }; }; ENDLOOP; }; IsEmptySequence: PUBLIC PROC [seq: Sequence] RETURNS [BOOL] = { RETURN[(NOT seq.all) AND seq.parts = 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; }; InJointRange: PUBLIC PROC [index: NAT, seq: Sequence] RETURNS [BOOL] = { <> IF seq.all THEN ERROR NotYetImplemented; FOR partList: LIST OF JointPair _ seq.parts, partList.rest UNTIL partList = NIL DO IF InMODRegion[index, partList.first.start, partList.first.end, seq.traj.segCount] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; <> TransformTraj: PUBLIC PROC [traj: Traj, transform: ImagerTransformation.Transformation] = { <> seg: Segment; joint: Joint; FOR i: NAT IN [0..GGObjects.HiSegment[traj]] DO seg _ FetchSegment[traj, i]; TransformSegment[seg, transform]; ENDLOOP; FOR i: NAT IN [0..GGObjects.HiJoint[traj]] DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; joint.point _ GGTransform.Transform[transform, joint.point]; ENDLOOP; traj.boundBox _ GGBoundBox.BoundBoxOfTraj[traj]; }; TransformSegment: PUBLIC PROC [seg: Segment, transform: ImagerTransformation.Transformation] = { seg.lo _ GGTransform.Transform[transform, seg.lo]; seg.hi _ GGTransform.Transform[transform, seg.hi]; seg.class.transform[transform, seg]; seg.class.boundBox[seg]; GGBoundBox.AdjustForJoints[seg.boundBox]; }; MoveEndPointSegment: PROC [seg: Segment, lo: BOOL, newPoint: Point] = { IF lo THEN seg.lo _ newPoint ELSE seg.hi _ newPoint; seg.class.endpointMoved[seg, lo, newPoint]; seg.class.boundBox[seg]; GGBoundBox.AdjustForJoints[seg.boundBox]; }; TransformSequence: PUBLIC PROC [seq: Sequence, transform: ImagerTransformation.Transformation] = { start, end: NAT; IF seq.all THEN TransformTraj[seq.traj, transform] ELSE { FOR partList: LIST OF JointPair _ seq.parts, partList.rest UNTIL partList = NIL DO <> start _ partList.first.start; end _ partList.first.end; SELECT seq.traj.role FROM open => TransformOpenSequence[seq.traj, start, end, transform]; fence, hole => TransformClosedSequence[seq.traj, start, end, transform]; ENDCASE => ERROR; ENDLOOP; seq.traj.boundBox _ GGBoundBox.BoundBoxOfTraj[seq.traj]; }; }; TransformOpenSequence: PUBLIC PROC [traj: Traj, start, end: NAT, transform: ImagerTransformation.Transformation] = { <<[start..end] is a range of jointCount joints. From jointCount-1 to jointCount+1 segments are affected, depending on how the joints are placed.>> seg: Segment; joint: Joint; segGen: SegmentGenerator; IF start > 0 THEN { seg _ FetchSegment[traj, start-1]; MoveEndPointSegment[seg, FALSE, GGTransform.Transform[transform, seg.hi]]; }; segGen _ SegmentsInJointPair[traj, start, end]; FOR seg _ NextSegment[segGen], NextSegment[segGen] UNTIL seg = NIL DO TransformSegment[seg, transform]; ENDLOOP; IF end < traj.segCount THEN { seg _ FetchSegment[traj, end]; MoveEndPointSegment[seg, TRUE, GGTransform.Transform[transform, seg.lo]]; }; FOR i: NAT IN [start..end] DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; joint.point _ GGTransform.Transform[transform, joint.point]; ENDLOOP; }; TransformClosedSequence: PUBLIC PROC [traj: Traj, start, end: NAT, transform: ImagerTransformation.Transformation] = { <<[start..end] MOD segCount is a range of jointCount joints. jointCount+1 segments are affected.>> seg: Segment; joint: Joint; segGen: SegmentGenerator; fullCycle: BOOL; <> seg _ PreviousSegment[traj, start]; MoveEndPointSegment[seg, FALSE, GGTransform.Transform[transform, seg.hi]]; <> segGen _ SegmentsInJointPair[traj, start, end]; FOR seg _ NextSegment[segGen], NextSegment[segGen] UNTIL seg = NIL DO TransformSegment[seg, transform]; ENDLOOP; <> seg _ FetchSegment[traj, end]; MoveEndPointSegment[seg, TRUE, GGTransform.Transform[transform, seg.lo]]; <> fullCycle _ FALSE; FOR i: NAT _ start, (i+1) MOD traj.segCount UNTIL fullCycle DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; joint.point _ GGTransform.Transform[transform, joint.point]; IF i = end THEN fullCycle _ TRUE; ENDLOOP; }; TranslateSegment: PUBLIC PROC [seg: Segment, vector: Vector] = { <> transform: ImagerTransformation.Transformation; transform _ ImagerTransformation.Translate[[vector[1], vector[2]]]; TransformSegment[seg, transform]; }; <> SetStrokeWidth: PUBLIC PROC [seq: Sequence, strokeWidth: REAL] = { segGen: SegmentGenerator; segGen _ SegmentsInSequence[seq]; FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO seg.strokeWidth _ strokeWidth; ENDLOOP; }; SetColor: PUBLIC PROC [seq: Sequence, color: Imager.Color] = { segGen: SegmentGenerator; segGen _ SegmentsInSequence[seq]; FOR seg: Segment _ GGObjects.NextSegment[segGen], GGObjects.NextSegment[segGen] UNTIL seg = NIL DO seg.color _ color; ENDLOOP; }; END. <<>>