GGScraps.tioga Last edited by Bier on July 29, 1985 1:26:59 pm PDT Pieces of code which will probably never be used again, but you never know. SELECT feature.resultType FROM joint => { end: BOOL; seqPart: SequencePart _ NARROW[feature.hitPart]; traj: Traj _ NARROW[feature.shape, Sequence].traj; SelectJoint[feature, resultPoint, gargoyleData]; jointNum _ seqPart.jointNum; GGCaret.SitOn[gargoyleData.caret, joint, traj, jointNum]; IF (end _ GGTraj.IsEndJoint[traj, jointNum]) THEN GGError.AppendHerald[gargoyleData.feedback, "End ", begin]; -- an end joint GGError.PutFHerald[gargoyleData.feedback, IF end THEN end ELSE oneLiner, "Joint %g selected", [integer[jointNum]] ]; gargoyleData.drag.extendMode _ joint; gargoyleData.drag.trajToExtend _ traj; }; segment => { seqPart: SequencePart _ NARROW[feature.hitPart]; segNum, cpNum: NAT; isACP, end: BOOL; traj: Traj _ NARROW[feature.shape, Sequence].traj; [isACP, jointNum, cpNum, segNum] _ SelectJointOrCP[feature, resultPoint, gargoyleData]; -- selects closest joint or CP IF isACP THEN { GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Control point %g selected", [integer[cpNum]]]; GGCaret.SitOn[gargoyleData.caret, cp, traj, 999, cpNum, segNum]; } ELSE { GGCaret.SitOn[gargoyleData.caret, joint, traj, jointNum]; IF (end _ GGTraj.IsEndJoint[traj, jointNum]) THEN GGError.AppendHerald[gargoyleData.feedback, "End ", begin]; -- an end joint GGError.PutFHerald[gargoyleData.feedback, IF end THEN end ELSE oneLiner, "Joint %g selected", [integer[jointNum]] ]; }; gargoyleData.drag.extendMode _ joint; gargoyleData.drag.trajToExtend _ traj; }; controlPoint => { seqPart: SequencePart _ NARROW[feature.hitPart]; segNum, cpNum: NAT; isACP: BOOL; traj: Traj _ NARROW[feature.shape, Sequence].traj; [isACP, ----, cpNum, segNum] _ SelectJointOrCP[feature, resultPoint, gargoyleData]; -- better get the CP !! GGCaret.SitOn[gargoyleData.caret, cp, traj, 999, cpNum, segNum]; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Control point %g selected", [integer[seqPart.controlPointNum]] ]; gargoyleData.drag.extendMode _ joint; -- we use joint extendMode for controlPoints gargoyleData.drag.trajToExtend _ traj; }; slice => { sliceD: SliceDescriptor _ NEW[SliceDescriptorObj _ [slice: NARROW[feature.shape, SliceDescriptor].slice] ]; [parts: sliceD.parts] _ SelectJointOrCP[feature, resultPoint, gargoyleData]; GGCaret.SitOn[gargoyleData.caret, slice, sliceD]; GGError.AppendHerald[gargoyleData.feedback, Rope.Concat[sliceD.slice.class.describe[sliceD.slice, sliceD.parts], " selected"], oneLiner]; gargoyleData.drag.extendMode _ joint; gargoyleData.drag.sliceToExtend _ sliceD.slice; }; ENDCASE => ERROR Problem[msg: "Unexpected feature type"]; BuiltInFilters: PUBLIC PROC [triggerBag: TriggerBag, objectBag: ObjectBag, gargoyleData: GargoyleData] = { jointGen: JointGenerator; cpGen: ControlPointGenerator; segGen: SegmentGenerator; seq: Sequence; seg: Segment; anchorFeature: FeatureData; joint: Joint; sliceD: SliceDescriptor; pointGen: PointGenerator; pointPairGen: PointPairGenerator; filters: Filters _ gargoyleData.hitTest; IF gargoyleData.camera.hideAlignments THEN { GGGravity.FlushObjectBag[objectBag]; RETURN; }; FOR l: LIST OF FeatureData _ triggerBag.seqs, l.rest UNTIL l = NIL DO seq _ NARROW[l.first.shape]; jointGen _ GGSequence.JointsInSequence[seq]; FOR i: INT _ GGSequence.NextJoint[jointGen], GGSequence.NextJoint[jointGen] UNTIL i = -1 DO joint _ GGTraj.FetchJoint[seq.traj, i]; [] _ JointFireRule[joint.point, filters, objectBag]; ENDLOOP; cpGen _ GGSequence.ControlPointsInSequence[seq]; FOR pad: PointAndDone _ GGSequence.NextControlPoint[cpGen], GGSequence.NextControlPoint[cpGen] UNTIL pad.done DO [] _ JointFireRule[pad.point, filters, objectBag]; ENDLOOP; segGen _ GGSequence.SegmentsInSequence[seq]; FOR next: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO seg _ GGTraj.FetchSegment[seq.traj, next.index]; [] _ SegmentFireRule[next.index, seg.lo, seg.hi, filters, objectBag]; ENDLOOP; ENDLOOP; anchorFeature _ triggerBag.anchor; IF anchorFeature # NIL AND GGCaret.Exists[NARROW[anchorFeature.shape, Caret]] THEN { point: Point; point _ GGCaret.GetPoint[NARROW[anchorFeature.shape, Caret]]; [] _ JointFireRule[point, filters, objectBag]; }; FOR l: LIST OF FeatureData _ triggerBag.slices, l.rest UNTIL l = NIL DO sliceD _ NARROW[l.first.shape]; pointGen _ sliceD.slice.class.pointsInDescriptor[sliceD]; FOR next: GGModelTypes.PointAndDone _ sliceD.slice.class.nextPoint[pointGen], sliceD.slice.class.nextPoint[pointGen] UNTIL next.done DO [] _ JointFireRule[next.point, filters, objectBag]; ENDLOOP; pointPairGen _ sliceD.slice.class.pointPairsInDescriptor[sliceD]; FOR next: GGModelTypes.PointPairAndDone _ sliceD.slice.class.nextPointPair[pointPairGen], sliceD.slice.class.nextPointPair[pointPairGen] UNTIL next.done DO [] _ SegmentFireRule[9999, next.lo, next.hi, filters, objectBag]; ENDLOOP; ENDLOOP; }; CurveClosestPoint: PROC [seg: Segment, testPoint: Point, tolerance: REAL] RETURNS [point: Point, success: BOOL] = { path: CubicPaths.Path; IF useBBox THEN { bigBox: GGBasicTypes.BoundBoxObj _ [seg.bBox.loX-tolerance, seg.bBox.loY-tolerance, seg.bBox.hiX+tolerance, seg.bBox.hiY+tolerance, FALSE, FALSE]; IF NOT PointIsInBox[testPoint, bigBox] THEN RETURN[[0,0], FALSE]; }; GGStatistics.StartInterval[$CurveClosestPoint, GGStatistics.GlobalTable[]]; path _ GetPath[seg]; [point, success] _ GGCubic2.ClosestPointSubdivide[[testPoint.x,testPoint.y], path, 1.0, tolerance]; GGStatistics.StopInterval[$CurveClosestPoint, GGStatistics.GlobalTable[]]; }; BτGGMouseEventImpl SameJointAsLastTime: PROC [thisTraj: Traj, thisJointNum: NAT, gargoyleData: GargoyleData] RETURNS [BOOL] = CHECKED { RETURN[ gargoyleData.hitTest.responsibleFor # NIL AND gargoyleData.hitTest.responsibleFor.traj = thisTraj AND gargoyleData.hitTest.responsibleFor.start = thisJointNum AND gargoyleData.hitTest.responsibleFor.end = thisJointNum ]; }; NearestJoint: PROC [scene: Scene, worldPt: Point, tolerance: REAL] RETURNS [result: Traj, index: NAT] = { Returns traj = NIL if no joints are found within tolerance. d2, d2guess: REAL; joint: INT; trajGen: TrajectoryGenerator; trajGen _ GGObjects.TrajsInScene[scene]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL trajs = NIL DO [joint, d2] _ GGObjects.NearestJoint[traj, worldPt, tolerance]; IF joint # -1 THEN { result _ traj; index _ joint; GOTO NearFound; }; REPEAT NearFound => { FOR traj2: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj2 = NIL DO [joint, d2guess] _ GGObjects.NearestJoint[traj2, worldPt, tolerance]; IF joint # -1 THEN { IF d2guess < d2 THEN { result _ traj2; index _ joint; d2 _ d2guess; }; }; ENDLOOP; }; FINISHED => {result _ NIL}; ENDLOOP; }; August 2, 1985 2:31:39 pm PDT GGObjectsImpl.mesa Hit Testing NearestJoint: PUBLIC PROC [traj: Traj, testPoint: Point, tolerance: REAL] RETURNS [index: INT, d2: REAL] = CHECKED { Finds the joint which is closest to testPoint. If there are several, it returns one of them. If none, index = -1. thisPos: Point; d2guess: REAL; hiJoint: NAT _ HiJoint[traj]; FOR i: INT IN [0..hiJoint] DO thisPos _ FetchJointPos[traj, i]; d2 _ GGVector.DistanceSquared[thisPos, testPoint]; IF d2 < tolerance*tolerance THEN { index _ i; GOTO NearFound; }; REPEAT NearFound => { FOR j: INT IN [index+1..hiJoint] DO thisPos _ FetchJointPos[traj, j]; d2guess _ GGVector.DistanceSquared[thisPos, testPoint]; IF d2guess < tolerance*tolerance THEN { d2 _ d2guess; index _ j; }; ENDLOOP; }; FINISHED => {index _ -1; d2 _ 0.0}; ENDLOOP; }; NearJoints: PUBLIC PROC [traj: Traj, testPoint: Point, tolerance: REAL] RETURNS [indexes: LIST OF NAT, distancesSquared: LIST OF REAL] = CHECKED { Finds all of the joints of traj which are within tolerance (and their distances from testPoint). If none, indexes = NIL. thisPos: Point; d2: REAL; indexes _ NIL; distancesSquared _ NIL; FOR i: NAT IN [0..HiJoint[traj]] DO thisPos _ FetchJointPos[traj, i]; d2 _ GGVector.DistanceSquared[thisPos, testPoint]; IF d2 < tolerance*tolerance THEN { indexes _ CONS[i, indexes]; distancesSquared _ CONS[d2, distancesSquared]; }; ENDLOOP; }; IsNearTraj: PUBLIC PROC [traj: Traj, testPoint: Point, tolerance: REAL] RETURNS [near: BOOL, howNear: REAL] = CHECKED { For now, we just look for near joints. indexes: LIST OF NAT; distancesSquared: LIST OF REAL; [indexes, distancesSquared] _ NearJoints[traj, testPoint, tolerance]; IF indexes = NIL THEN { near _ FALSE; howNear _ 0.0; RETURN; } ELSE { near _ TRUE; howNear _ distancesSquared.first; FOR dList: LIST OF REAL _ distancesSquared.rest, dList.rest UNTIL dList = NIL DO howNear _ MIN[dList.first, howNear]; ENDLOOP; }; }; IsNearOutline: PUBLIC PROC [outline: Outline, testPoint: Point, tolerance: REAL] RETURNS [near: BOOL, howNear: REAL] = { howNearGuess: REAL; nearGuess: BOOL; FOR children: LIST OF Traj _ outline.children, children.rest UNTIL children = NIL DO [near, howNearGuess] _ IsNearTraj[children.first, testPoint, tolerance]; IF near THEN GOTO FoundNear; REPEAT FoundNear => { howNear _ howNearGuess; FOR children2: LIST OF Traj _ children.rest, children2.rest UNTIL children2 = NIL DO [nearGuess, howNearGuess] _ IsNearTraj[children2.first, testPoint, tolerance]; IF nearGuess THEN howNear _ MIN[howNearGuess, howNear]; ENDLOOP; }; FINISHED => { near _ FALSE; howNear _ 0.0; }; ENDLOOP; }; IsNearCluster: PUBLIC PROC [cluster: Cluster, testPoint: Point, tolerance: REAL] RETURNS [near: BOOL, howNear: REAL] = { howNearGuess: REAL; nearGuess: BOOL; FOR children: LIST OF REF ANY _ cluster.children, children.rest UNTIL children = NIL DO WITH children.first SELECT FROM outline: Outline => { [near, howNearGuess] _ IsNearOutline[outline, testPoint, tolerance]; IF near THEN GOTO FoundNear }; subCluster: Cluster => { [near, howNearGuess] _ IsNearCluster[subCluster, testPoint, tolerance]; IF near THEN GOTO FoundNear; }; ENDCASE => ERROR; REPEAT FoundNear => { howNear _ howNearGuess; FOR children2: LIST OF REF ANY _ children.rest, children2.rest UNTIL children2 = NIL DO WITH children2.first SELECT FROM outline: Outline => { [nearGuess, howNearGuess] _ IsNearOutline[outline, testPoint, tolerance]; IF nearGuess THEN howNear _ MIN[howNearGuess, howNear]; }; subCluster: Cluster => { [nearGuess, howNearGuess] _ IsNearCluster[subCluster, testPoint, tolerance]; IF nearGuess THEN howNear _ MIN[howNearGuess, howNear]; }; ENDCASE => ERROR; ENDLOOP; }; FINISHED => { near _ FALSE; howNear _ 0.0; }; ENDLOOP; }; From GGSequenceImpl, Bier on February 25, 1986 11:56:00 am PST: 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: BitVector] = { segGen: SegmentGenerator; jointGen: JointGenerator; Initialize FOR i: NAT IN [0..GGObjects.HiSegment[new.traj]] DO newSegmentBits[i] _ FALSE; oldSegmentBits[i] _ FALSE; ENDLOOP; FOR i: NAT IN [0..GGObjects.GGObjects.HiJoint[new.traj]] DO newJointBits[i] _ FALSE; oldJointBits[i] _ FALSE; ENDLOOP; Set new Bits. 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; Set old Bits. 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: BitVector; start, end: NAT; newSegmentBits _ NEW[BitVectorObj[new.traj.segCount]]; oldSegmentBits _ NEW[BitVectorObj[new.traj.segCount]]; newJointBits _ NEW[BitVectorObj[new.traj.segCount + 1]]; oldJointBits _ NEW[BitVectorObj[new.traj.segCount + 1]]; Make the bitmaps reflect the sequences InitializeCombine[new, old, newJointBits, oldJointBits, newSegmentBits, oldSegmentBits]; Combine the segment bit vectors. 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; Combine the joint bit vectors. 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; Convert union back to sequences. union _ GGObjects.CreateEmpty[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 { The last joint is a lone part. 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; Convert diff back to sequences. newMinusOld _ GGObjects.CreateEmpty[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 { It is time to kludge. The LIST OF JointPair data structure isn't rich enough to represent this situation. Pretend that lastSegmentBit was never true and close the currently open part. 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 { Another chance to kludge. (See kludge comment above). We pretend that this segment doesn't exist. lastSegmentBit _ FALSE; } ELSE lastSegmentBit _ oldSegmentBits[i]; REPEAT FINISHED => { IF NOT lastSegmentBit AND oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { The last joint is a lone part. start _ end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[newMinusOld, start, end]; } ELSE IF lastSegmentBit AND NOT oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { One last kludge. 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] = { Not yet done. unionJointBit, diffJointBit, unionSegmentBit, diffSegmentBit, lastSegmentBit, lastJointBit: BOOL; newJointBits, oldJointBits, newSegmentBits, oldSegmentBits: BitVector; start, end: NAT; newSegmentBits _ NEW[BitVectorObj[new.traj.segCount]]; oldSegmentBits _ NEW[BitVectorObj[new.traj.segCount]]; newJointBits _ NEW[BitVectorObj[new.traj.segCount]]; oldJointBits _ NEW[BitVectorObj[new.traj.segCount]]; Make the bitmaps reflect the sequences InitializeCombine[new, old, newJointBits, oldJointBits, newSegmentBits, oldSegmentBits]; Combine the segment bit vectors. 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; Combine the joint bit vectors. 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; Convert union back to sequences (new = union, old = difference). union _ GGObjects.CreateEmpty[new.traj]; lastSegmentBit _ newSegmentBits[GGObjects.HiSegment[new.traj]]; FOR i: NAT IN [0..GGObjects.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 { The last joint is a lone part. 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; Convert diff back to sequences. newMinusOld _ GGObjects.CreateEmpty[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 { It is time to kludge. The LIST OF JointPair data structure isn't rich enough to represent this situation. Pretend that lastSegmentBit was never true and close the currently open part. 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 { Another chance to kludge. (See kludge comment above). We pretend that this segment doesn't exist. lastSegmentBit _ FALSE; } ELSE lastSegmentBit _ oldSegmentBits[i]; REPEAT FINISHED => { IF NOT lastSegmentBit AND oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { The last joint is a lone part. start _ end _ GGObjects.HiSegment[new.traj] + 1; GGObjects.AddPart[newMinusOld, start, end]; } ELSE IF lastSegmentBit AND NOT oldJointBits[GGObjects.HiSegment[new.traj] + 1] THEN { One last kludge. 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; }; 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; }; SegmentsInJointPair: PUBLIC PROC [traj: Traj, start: NAT, end: INT] RETURNS [segGen: SegmentGenerator] = { toGo: NAT; IF start > GGObjects.HiJoint[traj] OR end > GGObjects.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 ]]; }; 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]]; }; 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; }; }; 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 _ GGObjects.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; }; }; Parts of EndSelectJoint, Bier, December 12, 1986 9:35:07 pm PST SelectJoint[feature, resultPoint, gargoyleData]; GGAlignImpl.BuiltInFilters, Bier, December 12, 1986 11:56:14 pm PST Add Alignment Objects to the objectBag, using the triggers in the triggerBag. Joints as triggers. CPs as triggers. Segments as triggers. The anchor as a trigger. Triggers from slices. From GGSegmentImplA.mesa on January 19, 1987, Bier GGSegmentTypes.ClosestPointProc Used for hit testing. Find the nearest point on seg to testPoint. epsilon should be 0.072, but I will wait until GGCubic2.ClosestPoint is faster. Κ˜J˜J˜3J˜J˜KJ˜J™J™š ΟnœΟkœ žœžœžœžœ™tšžœ™Jšœ&ž™)Jšžœ4™7Jšžœ9™