<> <> <> <> <> <<>> DIRECTORY GGBasicTypes, GGDescribe, Feedback, GGInterfaceTypes, GGModelTypes, GGObjects, GGOutline, GGSegmentTypes, GGSelect, GGShapes, GGSequence, GGTouch, GGTransform, Imager, ImagerTransformation, Rope, Rosary; GGTouchImpl: CEDAR PROGRAM IMPORTS GGDescribe, Feedback, GGObjects, GGOutline, GGSelect, GGSequence, GGShapes, GGTransform, Rosary EXPORTS GGTouch = BEGIN Slice: TYPE = GGModelTypes.Slice; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGSequence.JointGenerator; Outline: TYPE = GGModelTypes.Outline; Point: TYPE = GGBasicTypes.Point; Segment: TYPE = GGSegmentTypes.Segment; Sequence: TYPE = GGModelTypes.Sequence; Traj: TYPE = GGModelTypes.Traj; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; TrajGenerator: TYPE = GGObjects.TrajGenerator; TouchGroup: TYPE = REF TouchGroupObj; TouchGroupObj: TYPE = GGSegmentTypes.TouchGroupObj; TouchingPartType: TYPE = GGSegmentTypes.TouchingPartType; TouchItem: TYPE = REF TouchItemObj; TouchItemObj: TYPE = GGSegmentTypes.TouchItemObj; TouchItemGenerator: TYPE = REF TouchItemGeneratorObj; TouchItemGeneratorObj: TYPE = GGTouch.TouchItemGeneratorObj; NotYetImplemented: PUBLIC SIGNAL = CODE; CreateTouchGroup: PUBLIC PROC [gargoyleData: GargoyleData, point: Point] RETURNS [empty: TouchGroup] = { empty _ NEW[TouchGroupObj _ [ list: NIL, point: point ]]; gargoyleData.touching _ CONS[empty, gargoyleData.touching]; }; AddJoint: PUBLIC PROC [traj: Traj, joint: Joint, touchGroup: TouchGroup] RETURNS [item: TouchItem] = { item _ NEW[TouchItemObj _ [ group: touchGroup, traj: traj, touchingPartType: joint, joint: joint, seg: NIL, segPoint: [0.0,0.0] ]]; touchGroup.list _ CONS[item, touchGroup.list]; }; AddSegment: PUBLIC PROC [traj: Traj, seg: Segment, segPoint: Point, touchGroup: TouchGroup] RETURNS [item: TouchItem] = { item _ NEW[TouchItemObj _ [ group: touchGroup, traj: traj, touchingPartType: segment, joint: NIL, seg: seg, segPoint: segPoint ]]; touchGroup.list _ CONS[item, touchGroup.list]; }; MergeGroups: PUBLIC PROC [group1, group2: TouchGroup, gargoyleData: GargoyleData] = { touchItemGen: TouchItemGenerator; IF group1 = group2 THEN RETURN; touchItemGen _ AllTouchItems[group1]; FOR item1: TouchItem _ NextTouchItem[touchItemGen], NextTouchItem[touchItemGen] UNTIL item1 = NIL DO item1.group _ group2; group2.list _ CONS[item1, group2.list]; ENDLOOP; group1.list _ NIL; gargoyleData.touching _ DeleteTouchGroupFromList[group1, gargoyleData.touching]; }; <<>> <> InitializeTouching: PUBLIC PROC [gargoyleData: GargoyleData] = { FOR groupList: LIST OF TouchGroup _ gargoyleData.touching, groupList.rest UNTIL groupList = NIL DO groupList.first.updated _ FALSE; ENDLOOP; }; UpdateTouchGroup: PUBLIC PROC [item: TouchItem, point: Point, gargoyleData: GargoyleData] = { group: TouchGroup _ item.group; itemGen: TouchItemGenerator; IF group.updated THEN { <> <> <> <> <> RETURN; }; group.updated _ TRUE; group.point _ point; itemGen _ AllTouchItems[group]; FOR thisItem: TouchItem _ NextTouchItem[itemGen], NextTouchItem[itemGen] UNTIL thisItem = NIL DO SELECT thisItem.touchingPartType FROM joint => { IF NOT GGSelect.IsSelectedInFull[thisItem.joint, gargoyleData.scene, normal] THEN { thisItem.joint.touchItem _ NIL; group.list _ DeleteTouchItemFromList[thisItem, group.list]; }; }; segment => { IF NOT GGSelect.IsSelectedInFull[thisItem.seg, gargoyleData.scene, normal] THEN { thisItem.seg.touchItemList _ DeleteTouchItemFromList[thisItem, thisItem.seg.touchItemList]; group.list _ DeleteTouchItemFromList[thisItem, group.list]; }; }; ENDCASE => ERROR; ENDLOOP; IF group.list = NIL THEN ERROR; IF group.list.rest = NIL THEN { -- only one item left. Delete group. thisItem: TouchItem _ group.list.first; SELECT thisItem.touchingPartType FROM joint => { thisItem.joint.touchItem _ NIL; group.list _ DeleteTouchItemFromList[thisItem, group.list]; }; segment => { thisItem.seg.touchItemList _ DeleteTouchItemFromList[thisItem, thisItem.seg.touchItemList]; group.list _ DeleteTouchItemFromList[thisItem, group.list]; }; ENDCASE => ERROR; gargoyleData.touching _ DeleteTouchGroupFromList[group, gargoyleData.touching]; }; }; <<>> <> SequenceMoved: PUBLIC PROC [seq: Sequence, gargoyleData: GargoyleData, transform: ImagerTransformation.Transformation _ NIL] = { jointGen: JointGenerator; joint: Joint; segGen: SegmentGenerator; jointGen _ GGSequence.JointsInSequence[seq]; FOR i: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, i]]; IF joint.touchItem # NIL THEN { UpdateTouchGroup[joint.touchItem, joint.point, gargoyleData]; }; ENDLOOP; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO FOR itemList: LIST OF TouchItem _ seg.touchItemList, itemList.rest UNTIL itemList = NIL DO itemList.first.segPoint _ GGTransform.Transform[transform, itemList.first.segPoint]; UpdateTouchGroup[itemList.first, itemList.first.segPoint, gargoyleData]; ENDLOOP; ENDLOOP; }; TrajMoved: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData, transform: ImagerTransformation.Transformation _ NIL] = { jointGen: JointGenerator; joint: Joint; segGen: SegmentGenerator; jointGen _ GGSequence.JointsInTraj[traj]; FOR i: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; IF joint.touchItem # NIL THEN { UpdateTouchGroup[joint.touchItem, joint.point, gargoyleData]; }; ENDLOOP; segGen _ GGSequence.SegmentsInTraj[traj]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO FOR itemList: LIST OF TouchItem _ seg.touchItemList, itemList.rest UNTIL itemList = NIL DO itemList.first.segPoint _ GGTransform.Transform[transform, itemList.first.segPoint]; UpdateTouchGroup[itemList.first, itemList.first.segPoint, gargoyleData]; ENDLOOP; ENDLOOP; }; <<>> <> DeleteTouchItem: PUBLIC PROC [touchItem: TouchItem, gargoyleData: GargoyleData] = { <> lastItem: TouchItem; group: TouchGroup _ touchItem.group; touchItem.joint _ NIL; touchItem.seg _ NIL; group.list _ DeleteTouchItemFromList[touchItem, group.list]; IF group.list.rest = NIL THEN { lastItem _ group.list.first; IF lastItem.touchingPartType = joint THEN { lastItem.joint.touchItem _ NIL; lastItem.joint _ NIL; } ELSE { lastItem.seg.touchItemList _ DeleteTouchItemFromList[lastItem, lastItem.seg.touchItemList]; lastItem.seg _ NIL; }; group.list _ NIL; gargoyleData.touching _ DeleteTouchGroupFromList[group, gargoyleData.touching]; }; }; <> SequenceDeleted: PUBLIC PROC [seq: Sequence, gargoyleData: GargoyleData] = { jointGen: JointGenerator; joint: Joint; segGen: SegmentGenerator; jointGen _ GGSequence.JointsInSequence[seq]; FOR i: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[seq.traj.joints, i]]; IF joint.touchItem # NIL THEN { DeleteTouchItem[joint.touchItem, gargoyleData]; joint.touchItem _ NIL; }; ENDLOOP; segGen _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO FOR itemList: LIST OF TouchItem _ seg.touchItemList, itemList.rest UNTIL itemList = NIL DO DeleteTouchItem[itemList.first, gargoyleData]; ENDLOOP; seg.touchItemList _ NIL; ENDLOOP; }; TrajDeleted: PUBLIC PROC [traj: Traj, gargoyleData: GargoyleData] = { jointGen: JointGenerator; joint: Joint; segGen: SegmentGenerator; jointGen _ GGSequence.JointsInTraj[traj]; FOR i: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL i = -1 DO joint _ NARROW[Rosary.Fetch[traj.joints, i]]; IF joint.touchItem # NIL THEN { DeleteTouchItem[joint.touchItem, gargoyleData]; joint.touchItem _ NIL; }; ENDLOOP; segGen _ GGSequence.SegmentsInTraj[traj]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg = NIL DO FOR itemList: LIST OF TouchItem _ seg.touchItemList, itemList.rest UNTIL itemList = NIL DO DeleteTouchItem[itemList.first, gargoyleData]; ENDLOOP; seg.touchItemList _ NIL; ENDLOOP; }; OutlineDeleted: PUBLIC PROC [outline: Outline, gargoyleData: GargoyleData] = { trajGen: TrajGenerator; trajGen _ GGOutline.TrajsInOutline[outline]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO TrajDeleted[traj, gargoyleData]; ENDLOOP; }; SliceDeleted: PUBLIC PROC [slice: Slice, gargoyleData: GargoyleData] = { ERROR NotYetImplemented; }; <> TouchGroupOfItem: PUBLIC PROC [item: TouchItem] RETURNS [touchGroup: TouchGroup] = { touchGroup _ item.group; }; AllTouchItems: PUBLIC PROC [touchGroup: TouchGroup] RETURNS [touchItemGen: TouchItemGenerator] = { touchItemGen _ NEW[TouchItemGeneratorObj _ [ list: touchGroup.list ]]; }; NextTouchItem: PUBLIC PROC [touchItemGen: TouchItemGenerator] RETURNS [item: TouchItem] = { IF touchItemGen.list = NIL THEN RETURN[NIL]; item _ touchItemGen.list.first; touchItemGen.list _ touchItemGen.list.rest; }; <> DrawAllTouchPoints: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { FOR groupList: LIST OF TouchGroup _ gargoyleData.touching, groupList.rest UNTIL groupList = NIL DO GGShapes.DrawPlus[dc, groupList.first.point]; ENDLOOP; }; DescribeAllTouchPoints: PUBLIC PROC [gargoyleData: GargoyleData] = { text: Rope.ROPE; FOR groupList: LIST OF TouchGroup _ gargoyleData.touching, groupList.rest UNTIL groupList = NIL DO text _ GGDescribe.DescribeTouchGroup[groupList.first]; Feedback.AppendTypescript[gargoyleData.feedback, text, oneLiner]; ENDLOOP; }; <<>> <> FindTouchItemAndNeighbors: PROC [entity: TouchItem, entityList: LIST OF TouchItem] RETURNS [beforeEnt, ent, afterEnt: LIST OF TouchItem] = { lastE: LIST OF TouchItem _ NIL; eList: LIST OF TouchItem _ entityList; IF eList = NIL THEN ERROR EntityNotFound; UNTIL eList = NIL DO IF eList.first = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; RETURN}; lastE _ eList; eList _ eList.rest; ENDLOOP; SIGNAL EntityNotFound; }; DeleteTouchItemFromList: PUBLIC PROC [entity: TouchItem, entityList: LIST OF TouchItem] RETURNS [smallerList: LIST OF TouchItem] = { beforeEnt, ent, afterEnt: LIST OF TouchItem; notFound: BOOL _ FALSE; [beforeEnt, ent, afterEnt] _ FindTouchItemAndNeighbors[entity, entityList]; IF notFound THEN RETURN[entityList]; IF beforeEnt = NIL THEN smallerList _ afterEnt ELSE { beforeEnt.rest _ afterEnt; smallerList _ entityList; }; }; -- end of DeleteTouchItemFromList FindTouchGroupAndNeighbors: PROC [entity: TouchGroup, entityList: LIST OF TouchGroup] RETURNS [beforeEnt, ent, afterEnt: LIST OF TouchGroup] = { lastE: LIST OF TouchGroup _ NIL; eList: LIST OF TouchGroup _ entityList; IF eList = NIL THEN ERROR EntityNotFound; UNTIL eList = NIL DO IF eList.first = entity THEN { beforeEnt _ lastE; ent _ eList; afterEnt _ eList.rest; RETURN}; lastE _ eList; eList _ eList.rest; ENDLOOP; SIGNAL EntityNotFound; }; EntityNotFound: PUBLIC SIGNAL = CODE; DeleteTouchGroupFromList: PUBLIC PROC [entity: TouchGroup, entityList: LIST OF TouchGroup] RETURNS [smallerList: LIST OF TouchGroup] = { beforeEnt, ent, afterEnt: LIST OF TouchGroup; notFound: BOOL _ FALSE; [beforeEnt, ent, afterEnt] _ FindTouchGroupAndNeighbors[entity, entityList]; IF notFound THEN RETURN[entityList]; IF beforeEnt = NIL THEN smallerList _ afterEnt ELSE { beforeEnt.rest _ afterEnt; smallerList _ entityList; }; }; -- end of DeleteTouchGroupFromList END.