DIRECTORY --CombinePoly,-- Ascii, Atom, AtomButtonsTypes, BasicTime, CodeTimer, ColorTool, CubicSplines, Feedback, FileNames, FS, GGBasicTypes, GGBoundBox, GGCaret, GGEvent, GGFileIn, GGFileOut, GGGravity, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGOutline, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGSlice, GGUtility, GGWindow, Icons, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, IO, List, NamedColors, PrincOpsUtils, Random, Rope, Rosary, Vectors2d, ViewerClasses, ViewerOps, ViewerTools; GGEventImplD: CEDAR PROGRAM IMPORTS ColorTool, --CombinePoly,-- PrincOpsUtils, Ascii, Atom, BasicTime, CodeTimer, Feedback, FileNames, FS, GGCaret, GGEvent, GGFileIn, GGFileOut, GGGravity, GGMultiGravity, GGOutline, GGScene, GGSelect, GGSequence, GGSlice, GGUtility, GGWindow, Icons, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, IO, List, NamedColors, Random, Rope, Vectors2d, ViewerOps, ViewerTools EXPORTS GGEvent = BEGIN BoundBox: TYPE = GGBoundBox.BoundBox; WalkProc: TYPE = GGModelTypes.WalkProc; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGInterfaceTypes.FeatureData; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; GGData: TYPE = GGInterfaceTypes.GGData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; AlignBag: TYPE = GGGravity.AlignBag; Outline: TYPE = GGModelTypes.Outline; OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor; Point: TYPE = GGBasicTypes.Point; Scene: TYPE = GGModelTypes.Scene; SegAndIndex: TYPE = GGSequence.SegAndIndex; Segment: TYPE = GGSegmentTypes.Segment; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; Sequence: TYPE = GGModelTypes.Sequence; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajGenerator: TYPE = GGModelTypes.TrajGenerator; TriggerBag: TYPE = GGGravity.TriggerBag; Vector: TYPE = GGBasicTypes.Vector; Viewer: TYPE = ViewerClasses.Viewer; PaintActionArea: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; ViewerOps.PaintViewer[ viewer: ggData.actionArea, hint: client, whatChanged: ggData, clearClient: FALSE]; }; NotNewVersion: PROC [ggData: GGData, op: ATOM] = { ggData.outer.newVersion _ FALSE; ggData.outer.icon _ SELECT op FROM $clear => noNameIcon, $clean => cleanIcon, ENDCASE => ERROR; ViewerOps.PaintViewer[ggData.outer, caption]; }; GetGargoyleFileName: PROC [event: LIST OF REF ANY, currentWDir: Rope.ROPE, feedback: FeedbackData, emergency: BOOL _ FALSE] RETURNS [fullName: Rope.ROPE _ NIL, success: BOOL _ TRUE, versionSpecified: BOOL _ FALSE] = { RopeFromRef: PROC [ref: REF ANY] RETURNS [rope: Rope.ROPE] ~ { WITH ref SELECT FROM text: REF TEXT => RETURN[Rope.FromRefText[text] ]; r: Rope.ROPE => RETURN[r]; ENDCASE => ERROR; }; fileName: Rope.ROPE; fileName _ IF event#NIL AND event.first#NIL THEN RopeFromRef[event.first] ELSE ViewerTools.GetSelectionContents[]; [fullName, success, versionSpecified] _ GGUtility.GetGargoyleFileName[fileName, currentWDir, feedback, emergency]; }; Get: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; fullName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback]; IF NOT success THEN { Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner]; GOTO Abort; }; ClearAux[event, ggData]; GetMergeAux[fullName, versionSpecified, $Get, "Getting", ggData]; NotNewVersion[ggData, $clean]; EXITS Abort => Feedback.Blink[NARROW[clientData, GGData].feedback]; }; Merge: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; fullName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback]; IF NOT success THEN { Feedback.Append[ggData.feedback, "Could not find requested file", oneLiner]; GOTO Abort; }; GetMergeAux[fullName, versionSpecified, $Merge, "Merging", ggData]; EXITS Abort => Feedback.Blink[NARROW[clientData, GGData].feedback]; }; GetMergeAux: PROC [fullName: Rope.ROPE, versionSpecified: BOOL _ FALSE, event: ATOM, opName: Rope.ROPE, ggData: GGData] = { f: IO.STREAM; fsName: Rope.ROPE; startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope: Rope.ROPE; f _ FS.StreamOpen[fullName, $read ! FS.Error, IO.Error => { msgRope _ IO.PutFR["Could not find: %g", [rope[fullName]]]; Feedback.Append[ggData.feedback, msgRope, oneLiner]; GOTO Abort; };]; msgRope _ IO.PutFR["%g %g . . . ", [rope[opName]], [rope[fullName]]]; Feedback.Append[ggData.feedback, msgRope, begin]; startTime _ BasicTime.Now[]; GGFileIn.FileinSceneAndOptions[f, ggData]; f.Close[]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; Feedback.Append[ggData.feedback, msgRope, end]; IF event=$Get OR ggData.outer.file=NIL THEN { -- update viewer name on Get or on first Merge if no Get preceeded it. fsName _ FS.FileInfo[name: fullName, wDir: ggData.currentWDir].fullFName; ggData.outer.file _ FileNames.StripVersionNumber[fsName]; ggData.outer.label _ FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE]; ggData.outer.name _ IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", ggData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"]; }; GGEvent.SawTextFinish[ggData, LIST[$SawTextFinish]]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: event=$Merge, okToClearFeedback: FALSE]; EXITS Abort => Feedback.Blink[ggData.feedback]; }; -- end GetMergeAux Store: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; tKeep: CARDINAL _ 0; f: IO.STREAM; fullName, fsName: Rope.ROPE; success, versionSpecified: BOOL _ FALSE; startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope, opName: Rope.ROPE; ofile: FS.OpenFile; emergency: BOOL _ event.first=$Emergency; [fullName, success, versionSpecified] _ GetGargoyleFileName[event.rest, ggData.currentWDir, ggData.feedback, emergency]; IF NOT success THEN RETURN; tKeep _ FS.FileInfo[name: fullName ! FS.Error => CONTINUE].keep; ofile _ FS.Create[name: fullName, setPages: FALSE, setKeep: TRUE, keep: MAX[tKeep, 2] ! FS.Error => { msgRope _ IO.PutFR["Could not create: %g", [rope[fullName]]]; IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, oneLiner]; GOTO Abort; };]; f _ FS.StreamFromOpenFile[openFile: ofile, accessRights: $write]; opName _ IF event.first = NIL THEN "someSave" ELSE Atom.GetPName[NARROW[event.first]]; msgRope _ IO.PutFR["%g: %g . . . ", [rope[opName]], [rope[fullName]]]; IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, begin]; startTime _ BasicTime.Now[]; GGFileOut.FileoutSceneAndOptions[f, ggData, fullName]; f.Close[]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; IF NOT emergency THEN Feedback.Append[ggData.feedback, msgRope, end]; fsName _ FS.FileInfo[name: fullName, wDir: ggData.currentWDir].fullFName; --latest version ggData.outer.file _ FileNames.StripVersionNumber[fsName]; ggData.outer.label _ FileNames.GetShortName[path: fsName, stripOffVersionNumber: TRUE]; ggData.outer.name _ IF versionSpecified THEN Rope.Concat["Gargoyle: ", fsName] ELSE Rope.Cat["Gargoyle: ", ggData.outer.file, " (!", FileNames.Tail[fsName, '!], ")"]; NotNewVersion[ggData, $clean]; GGEvent.SawTextFinish[ggData, NIL]; EXITS Abort => { ggData: GGData _ NARROW[clientData]; IF NOT event.first=$Emergency THEN Feedback.Blink[ggData.feedback]; }; }; Save: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ggData.outer.file#NIL THEN Store[event: LIST[$Save, ggData.outer.file], clientData: clientData] ELSE { Feedback.Append[ggData.feedback, "Can't save an unnamed viewer: try Store", oneLiner]; Feedback.Blink[ggData.feedback]; }; }; Split: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData];}; Reset: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; fileName: Rope.ROPE _ ggData.outer.file; ClearAux[event, ggData]; GetMergeAux[fileName, FALSE, $Get, "Restoring", ggData]; NotNewVersion[ggData, $clean]; }; Clear: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; ClearAux[event, ggData]; ggData.outer.file _ NIL; ggData.outer.label _ "Gargoyle"; ggData.outer.name _ "Gargoyle"; GGEvent.SawTextFinish[ggData, NIL]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; NotNewVersion[ggData, $clear]; }; -- end Clear ClearAux: PROC [event: LIST OF REF ANY, ggData: GGData] = { ggData.refresh.overlayList _ NIL; GGSelect.DeselectAllAllClasses[ggData.scene]; ggData.scene _ GGScene.CreateScene[]; ggData.caret _ NEW[GGInterfaceTypes.CaretObj]; ggData.anchor _ NEW[GGInterfaceTypes.CaretObj]; GGEvent.StandardAlignments[ggData, LIST[$StandardAlignments]]; ggData.aborted _ ALL[FALSE]; }; AddToGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { someAddition: BOOL _ FALSE; seqGen: SequenceGenerator; ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; IF name=NIL OR Rope.Equal[name, ""] THEN { Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[ggData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO duplicate: BOOL _ FALSE; FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN { duplicate _ TRUE; -- already in this group EXIT; }; ENDLOOP; IF NOT duplicate THEN seg.props _ List.Append[seg.props, LIST[name]]; someAddition _ TRUE; ENDLOOP; ENDLOOP; Feedback.PutF[ggData.feedback, oneLiner, IF someAddition THEN "Added selected segments to group %g" ELSE "No segment selections to add to group %g", [rope[name]] ]; }; SelectGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; trajGen: TrajGenerator _ GGScene.TrajsInScene[ggData.scene]; segGen: SegmentGenerator; seq: Sequence; segsFound: BOOL; GGSelect.DeselectAll[ggData.scene, normal]; -- get rid of old selection FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO segGen _ GGSequence.SegmentsInTraj[traj]; segsFound _ FALSE; FOR next: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL next.seg=NIL DO FOR prop: LIST OF REF ANY _ next.seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF Rope.Equal[name, nextProp, FALSE] THEN { IF NOT segsFound THEN seq _ GGSequence.CreateEmpty[traj]; segsFound _ TRUE; IF NOT seq.segments[next.index] THEN { seq.segments[next.index] _ TRUE; seq.segCount _ seq.segCount + 1; }; }; ENDLOOP; -- next prop ENDLOOP; -- next segment IF segsFound THEN GGSelect.SelectSequence[seq, ggData.scene, normal]; ENDLOOP; -- next trajectory GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; IF GGSelect.NoSelections[ggData.scene, normal] THEN Feedback.AppendHerald[ggData.feedback, "No such group", oneLiner ] ELSE Feedback.PutF[ggData.feedback, oneLiner, "Group %g selected", [rope[name]] ]; }; RemoveFromGroup: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { someRemoval: BOOL _ FALSE; newProps: LIST OF REF ANY; seqGen: SequenceGenerator; ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; IF name=NIL OR Rope.Equal[name, ""] THEN { Feedback.AppendHerald[ggData.feedback, "Select a group name", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[ggData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO newProps _ NIL; FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; IF NOT Rope.Equal[name, nextProp, FALSE] THEN newProps _ List.Append[newProps, LIST[nextProp]] ELSE someRemoval _ TRUE; ENDLOOP; seg.props _ newProps; ENDLOOP; ENDLOOP; Feedback.PutF[ggData.feedback, oneLiner, IF someRemoval THEN "Removed selected segments from group %g" ELSE "No member segments selected to remove from group %g", [rope[name]] ]; }; PrintGroupsOfSelected: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { groupList: LIST OF REF ANY; seqGen: SequenceGenerator; ggData: GGData _ NARROW[clientData]; IF GGSelect.NoSelections[ggData.scene, normal] THEN { Feedback.AppendHerald[ggData.feedback, "No selections => no groups", oneLiner]; RETURN; }; seqGen _ GGSelect.SelectedSequences[ggData.scene, normal]; FOR seq: Sequence _ GGSequence.NextSequence[seqGen], GGSequence.NextSequence[seqGen] UNTIL seq=NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInSequence[seq]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; duplicate: BOOL _ FALSE; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; IF Rope.Equal[nextGroup, nextProp, FALSE] THEN { duplicate _ TRUE; -- already on the group list EXIT; }; ENDLOOP; IF NOT duplicate THEN groupList _ List.Append[groupList, LIST[nextProp]]; ENDLOOP; ENDLOOP; ENDLOOP; IF groupList#NIL THEN { Feedback.Append[ggData.feedback, "Groups of Selected: ", begin]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.feedback, "", end]; } ELSE Feedback.Append[ggData.feedback, "No Groups of Selected", oneLiner]; }; PrintAllGroups: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { groupList: LIST OF REF ANY; ggData: GGData _ NARROW[clientData]; trajGen: TrajGenerator _ GGScene.TrajsInScene[ggData.scene]; FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; FOR seg: Segment _ GGSequence.NextSegment[segGen], GGSequence.NextSegment[segGen] UNTIL seg=NIL DO FOR prop: LIST OF REF ANY _ seg.props, prop.rest UNTIL prop=NIL DO nextProp: Rope.ROPE _ NARROW[prop.first]; duplicate: BOOL _ FALSE; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; IF Rope.Equal[nextGroup, nextProp, FALSE] THEN { duplicate _ TRUE; -- already on the group list EXIT; }; ENDLOOP; IF NOT duplicate THEN groupList _ List.Append[groupList, LIST[nextProp]]; ENDLOOP; ENDLOOP; ENDLOOP; IF groupList#NIL THEN { Feedback.Append[ggData.feedback, "Groups: ", begin]; FOR group: LIST OF REF ANY _ groupList, group.rest UNTIL group=NIL DO nextGroup: Rope.ROPE _ NARROW[group.first]; Feedback.PutF[ggData.feedback, middle, "%g ", [rope[nextGroup]] ]; ENDLOOP; Feedback.Append[ggData.feedback, "", end]; } ELSE Feedback.Append[ggData.feedback, "No Groups", oneLiner]; }; RGBFromRopeError: SIGNAL = CODE; AreaColorFromColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN AreaColorAux[ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[]], ggData]; }; LineColorFromColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN LineColorAux[ImagerColor.ColorFromRGB[ColorTool.GetRGBValue[]], ggData]; }; AreaColorFollowColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { color: Imager.Color _ GGUtility.GetSpecialColor[]; -- "animation" color; IF color#NIL THEN { ggData.refresh.areaFollowColorTool _ TRUE; AreaColorAux[color, ggData]; } ELSE Feedback.Append[ggData.feedback, ". . . Can't find ColorTool", oneLiner]; }; }; LineColorFollowColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { color: Imager.Color _ GGUtility.GetSpecialColor[]; -- "animation" color; IF color#NIL THEN { ggData.refresh.lineFollowColorTool _ TRUE; LineColorAux[color, ggData]; } ELSE Feedback.Append[ggData.feedback, ". . . Can't find ColorTool", oneLiner]; }; }; AreaColorToColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { red, green, blue: REAL; color: Imager.Color _ NIL; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; WITH GGScene.NextEntity[entityGen] SELECT FROM outlineD: OutlineDescriptor => color _ outlineD.slice.class.getFillColor[outlineD.slice]; sliceD: SliceDescriptor => color _ sliceD.slice.class.getFillColor[sliceD.slice]; ENDCASE => ERROR; IF color#NIL THEN { [red, green, blue] _ GGUtility.ExtractRGB[color]; ColorTool.SetRGBValue[[red, green, blue], NIL]; } ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL fill color", oneLiner]; }; }; LineColorToColorTool: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; IF ColorToolIsBound[ggData] THEN { red, green, blue: REAL; color: Imager.Color _ NIL; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; WITH GGScene.NextEntity[entityGen] SELECT FROM outlineD: OutlineDescriptor => color _ outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]; sliceD: SliceDescriptor => color _ sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]; ENDCASE => ERROR; IF color#NIL THEN { [red, green, blue] _ GGUtility.ExtractRGB[color]; ColorTool.SetRGBValue[[red, green, blue], NIL]; } ELSE Feedback.Append[ggData.feedback, ". . . Object has NIL stroke color", oneLiner]; }; }; AreaColorFromSelectedName: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; AreaColorAux[color, ggData]; EXITS UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; LineColorFromSelectedName: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]]]; LineColorAux[color, ggData]; EXITS UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; AreaColorFromSelectedRGB: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; AreaColorAux[color, ggData]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; LineColorFromSelectedRGB: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; color: Imager.Color _ ImagerColor.ColorFromRGB[RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError]]; LineColorAux[color, ggData]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; SelectMatchingAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; entityGen: EntityGenerator _ GGScene.TopLevelEntitiesInScene[ggData.scene]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingAreaCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingAreaRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGSelect.DeselectAll[ggData.scene, normal]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outline: Outline => { fillColor: Imager.Color _ outline.class.getFillColor[outline]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectEntireOutline[outline, ggData.scene, normal]; }; slice: Slice => { fillColor: Imager.Color _ slice.class.getFillColor[slice]; IF RGBEqualsColor[rgb, fillColor, noneFlag] THEN GGSelect.SelectSlice[slice.class.newParts[slice, NIL, topLevel], ggData.scene, normal]; }; ENDCASE => ERROR; ENDLOOP; Feedback.PutFHerald[ggData.feedback, oneLiner, "Areas with fill color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; SelectMatchingLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; rgb: ImagerColor.RGB; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; trajGen: TrajGenerator _ GGScene.TrajsInScene[ggData.scene]; sliceGen: SliceGenerator _ GGScene.SlicesInScene[ggData.scene]; noneFlag: BOOL _ Rope.Equal[name, "none", FALSE]; IF NOT noneFlag THEN rgb _ SELECT event.first FROM $SelectMatchingLineCNS => ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[name ! NamedColors.UndefinedName => GOTO UndefinedName; NamedColors.BadGrammar => GOTO BadGrammar; ]], $SelectMatchingLineRGB => RGBFromRope[name ! RGBFromRopeError => GOTO SyntaxError] ENDCASE => ERROR; GGSelect.DeselectAll[ggData.scene, normal]; FOR traj: Traj _ GGScene.NextTraj[trajGen], GGScene.NextTraj[trajGen] UNTIL traj = NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; FOR segAndIndex: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL segAndIndex.seg = NIL DO IF RGBEqualsColor[rgb, segAndIndex.seg.color, noneFlag] THEN { seq: Sequence _ GGSequence.CreateFromSegment[traj, segAndIndex.index]; GGSelect.SelectSequence[seq, ggData.scene, normal]; }; ENDLOOP; ENDLOOP; FOR slice: Slice _ GGScene.NextSlice[sliceGen], GGScene.NextSlice[sliceGen] UNTIL slice = NIL DO -- for every slice in the scene ColorProc: WalkProc = { RETURN [RGBEqualsColor[rgb, seg.color, noneFlag]]; }; sliceD: SliceDescriptor _ GGSlice.WalkSegments[slice, ColorProc]; -- get a descriptor of matching parts GGSelect.SelectSlice[sliceD, ggData.scene, normal]; -- and select it ENDLOOP; Feedback.PutFHerald[ggData.feedback, oneLiner, "Segments with color %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; EXITS SyntaxError => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "RGB Syntax is R: [0.0..1.0] G: [0.0..1.0] B: [0.0..1.0]", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; UndefinedName => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Undefined Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; BadGrammar => {Feedback.AppendHerald[NARROW[clientData, GGData].feedback, "Bad Color Name", oneLiner]; Feedback.Blink[NARROW[clientData, GGData].feedback];}; }; SetDefaultLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; entity: REF ANY; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; IF entityGen=NIL OR (entity _ GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for setting default line color", oneLiner] ELSE { isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor; WITH entity SELECT FROM outlineD: OutlineDescriptor => color _ NARROW[outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]]; sliceD: SliceDescriptor => color _ NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]]; ENDCASE => ERROR; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Stroke Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Stroke Color: None", oneLiner]; ggData.defaults.strokeColor _ color; }; }; SetDefaultFillColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; entity: REF ANY; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; IF entityGen=NIL OR (entity _ GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for setting default fill color", oneLiner] ELSE { isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor; WITH entity SELECT FROM outlineD: OutlineDescriptor => { IF GGOutline.FenceOfOutline[outlineD.slice].role#open THEN color _ NARROW[outlineD.slice.class.getFillColor[outlineD.slice]] ELSE { Feedback.AppendHerald[ggData.feedback, "Select exactly one filled entity for setting default fill color", oneLiner]; RETURN; }; }; sliceD: SliceDescriptor => color _ NARROW[sliceD.slice.class.getFillColor[sliceD.slice]]; ENDCASE => ERROR; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Fill Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Fill Color: None", oneLiner]; ggData.defaults.fillColor _ color; }; }; ShowDefaultLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[ggData.defaults.strokeColor]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Stroke Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Stroke Color: None", oneLiner]; }; ShowDefaultFillColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; isProcessBlack: Rope.ROPE; red, green, blue: REAL; color: Imager.ConstantColor _ NARROW[ggData.defaults.fillColor]; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["Default Fill Color: R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "Default Fill Color: None", oneLiner]; }; AreaColorBlack: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[Imager.black, ggData]; }; LineColorBlack: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[Imager.black, ggData]; }; PrintAreaColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; entity: REF ANY; isProcessBlack: Rope.ROPE; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; IF entityGen=NIL OR (entity _ GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for PrintFillColor", oneLiner] ELSE { red, green, blue: REAL; color: Imager.ConstantColor; WITH entity SELECT FROM outlineD: OutlineDescriptor => color _ NARROW[outlineD.slice.class.getFillColor[outlineD.slice]]; sliceD: SliceDescriptor => color _ NARROW[sliceD.slice.class.getFillColor[sliceD.slice]]; ENDCASE => ERROR; IF color#NIL THEN { [red,green,blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "No Fill Color", oneLiner]; }; }; PrintLineColor: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; entity: REF ANY; isProcessBlack: Rope.ROPE; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; IF entityGen=NIL OR (entity _ GGScene.NextEntity[entityGen])=NIL OR GGScene.NextEntity[entityGen]#NIL THEN Feedback.AppendHerald[ggData.feedback, "Select exactly one entity for PrintLineColor", oneLiner] ELSE { red, green, blue: REAL; color: Imager.ConstantColor; WITH entity SELECT FROM outlineD: OutlineDescriptor => color _ NARROW[outlineD.slice.class.getStrokeColor[outlineD.slice, outlineD.parts]]; sliceD: SliceDescriptor => color _ NARROW[sliceD.slice.class.getStrokeColor[sliceD.slice, sliceD.parts]]; ENDCASE => ERROR; IF color#NIL THEN { [red, green, blue] _ GGUtility.ExtractRGB[color]; IF color = Imager.black THEN isProcessBlack _ " (process black)" ELSE IF ImagerColorPrivate.GrayFromColor[color]=1.0 THEN isProcessBlack _ " (CMY black)" ELSE isProcessBlack _ ""; Feedback.Append[ ggData.feedback, IO.PutFR["R: %1.3f G: %1.3f B: %1.3f CNS: %g%g", [real[red]], [real[green]], [real[blue]], [rope[NamedColors.HSLToRope[ImagerColorFns.HSLFromRGB[[red,green,blue]]]]], [rope[isProcessBlack]] ], oneLiner]; } ELSE Feedback.Append[ggData.feedback, "No Stroke Color", oneLiner]; }; }; AreaColorWhite: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[Imager.white, ggData]; }; LineColorWhite: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[Imager.white, ggData]; }; AreaColorGray: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[GGOutline.fillColor, ggData]; }; LineColorGray: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[GGOutline.fillColor, ggData]; }; AreaColorNone: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; AreaColorAux[NIL, ggData]; }; LineColorNone: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; LineColorAux[NIL, ggData]; }; AreaColorAux: PROC [color: Imager.Color, clientData: REF ANY] = { ggData: GGData _ NARROW[clientData]; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outlineD: OutlineDescriptor => outlineD.slice.class.setFillColor[outlineD.slice, color]; sliceD: SliceDescriptor => sliceD.slice.class.setFillColor[sliceD.slice, color]; ENDCASE => ERROR; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; LineColorAux: PROC [color: Imager.Color, clientData: REF ANY] = { ggData: GGData _ NARROW[clientData]; entityGen: EntityGenerator _ GGSelect.SelectedStuff[ggData.scene, normal]; FOR entity: REF ANY _ GGScene.NextEntity[entityGen], GGScene.NextEntity[entityGen] UNTIL entity = NIL DO WITH entity SELECT FROM outlineD: OutlineDescriptor => outlineD.slice.class.setStrokeColor[outlineD.slice, outlineD.parts, color]; sliceD: SliceDescriptor => sliceD.slice.class.setStrokeColor[sliceD.slice, sliceD.parts, color]; ENDCASE => ERROR; ENDLOOP; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedInPlace, ggData: ggData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; ColorToolIsBound: PROC [ggData: GGData] RETURNS [BOOL _ FALSE] = TRUSTED { IF PrincOpsUtils.IsBound[LOOPHOLE[ColorTool.GetRGBValue]] THEN RETURN[TRUE]; Feedback.AppendHerald[ggData.feedback, "Please start ColorTool and retry this operation", oneLiner]; }; RGBEqualsColor: PROC [rgb: ImagerColor.RGB, color: Imager.Color, noneFlag: BOOL] RETURNS [BOOL] = { epsilon: REAL = 1.0E-2; IF color=NIL THEN RETURN [noneFlag]; -- fillColor is none IF noneFlag THEN RETURN [FALSE] -- looking for none, but color is non-NIL ELSE { r, g, b: REAL; [r,g,b] _ GGUtility.ExtractRGB[color]; RETURN[(r=rgb.R AND g=rgb.G AND b=rgb.B) OR (ABS[r-rgb.R] GOTO RGBError; Check: PROC [x: REAL] = { IF x NOT IN [0.0..1.0] THEN SIGNAL RGBFromRopeError; }; rs: IO.STREAM _ IO.RIS[name]; IF Ascii.Upper[rs.GetChar[]]#'R THEN GOTO RGBError; IF rs.GetChar[]#': THEN GOTO RGBError; rgb.R _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; IF Ascii.Upper[rs.GetChar[]]#'G THEN GOTO RGBError; IF rs.GetChar[]#': THEN GOTO RGBError; rgb.G _ rs.GetReal[]; [] _ rs.SkipWhitespace[]; IF Ascii.Upper[rs.GetChar[]]#'B THEN GOTO RGBError; IF rs.GetChar[]#': THEN GOTO RGBError; rgb.B _ rs.GetReal[]; Check[rgb.R]; Check[rgb.G]; Check[rgb.B]; EXITS RGBError => SIGNAL RGBFromRopeError; }; TestMultiGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { }; TestGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; xRandomStream, yRandomStream: Random.RandomStream; desiredCount: INT _ NARROW[event.rest.first, REF INT]^; testPoint: Point; x, y: INT; totalCount, multiHitCount, uniHitCount, diffCount: NAT _ 0; uniPoint, multiPoint: Point; uniFeature, multiFeature: FeatureData; currentObjects: AlignBag; sceneObjects: TriggerBag; IF desiredCount < 0 THEN RETURN; xRandomStream _ Random.Create[ggData.actionArea.cw]; yRandomStream _ Random.Create[ggData.actionArea.ch]; ggData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount >= desiredCount DO IF ggData.aborted[gravitytest] THEN { ggData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, ggData: ggData]; ggData.refresh.spotPoint _ testPoint; currentObjects _ ggData.hitTest.alignBag; sceneObjects _ ggData.hitTest.sceneBag; [uniPoint, uniFeature] _ GGGravity.UniMap[testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE]; [multiPoint, multiFeature] _ GGMultiGravity.Map[testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE]; IF uniFeature = NIL AND multiFeature = NIL THEN { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; totalCount _ totalCount + 1; LOOP; }; IF uniFeature = NIL OR multiFeature = NIL OR uniFeature # multiFeature OR uniFeature.type # multiFeature.type OR uniPoint # multiPoint THEN { ReportResultsAndPaint[testPoint, uniPoint, uniFeature, multiPoint, multiFeature, ggData]; totalCount _ totalCount + 1; diffCount _ diffCount + 1; IF multiFeature # NIL THEN multiHitCount _ multiHitCount + 1; IF uniFeature # NIL THEN uniHitCount _ uniHitCount + 1; } ELSE { multiHitCount _ multiHitCount + 1; uniHitCount _ uniHitCount + 1; totalCount _ totalCount + 1; ggData.refresh.hitPoint _ multiPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; ENDLOOP; Feedback.PutF[ggData.feedback, oneLiner, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]]; }; -- end TestGravity noisyTestGravity: BOOL _ FALSE; ReportResultsAndPaint: PROC [testPoint: Point, uniPoint: Point, uniFeature: FeatureData, multiPoint: Point, multiFeature: FeatureData, ggData: GGData] = { multiMag, uniMag: REAL; IF uniFeature = NIL THEN { multiMag _ Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No unihit at [%g, %g]. multihit distance: %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]]]; ggData.refresh.hitPoint _ multiPoint; } ELSE IF multiFeature = NIL THEN { uniMag _ Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "No multihit at [%g, %g]. unihit distance: %g", [real[uniPoint.x]], [real[uniPoint.y]], [real[uniMag]]]; ggData.refresh.hitPoint _ uniPoint; } ELSE IF uniFeature # multiFeature THEN { multiMag _ Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]]; uniMag _ Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Features differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]]; ggData.refresh.hitPoint _ multiPoint; } ELSE IF uniFeature.type # multiFeature.type THEN { IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Feature types differ at [%g, %g]", [real[multiPoint.x]], [real[multiPoint.y]]]; ggData.refresh.hitPoint _ multiPoint; } ELSE IF uniPoint # multiPoint THEN { multiMag _ Vectors2d.Magnitude[Vectors2d.Sub[multiPoint, testPoint]]; uniMag _ Vectors2d.Magnitude[Vectors2d.Sub[uniPoint, testPoint]]; IF noisyTestGravity THEN Feedback.PutFTypescript[ggData.feedback, oneLiner, "Points differ at [%g, %g] by %g to %g", [real[multiPoint.x]], [real[multiPoint.y]], [real[multiMag]], [real[uniMag]]]; ggData.refresh.hitPoint _ uniPoint; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; ggData.refresh.hitPoint _ multiPoint; } ELSE ERROR; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOddHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; Statistics: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; f: IO.STREAM _ Feedback.GetTypescriptStream[$Gargoyle]; CodeTimer.PrintTable[f, CodeTimer.GetTable[$Gargoyle]]; }; PrintSelectedStatistic: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; intervalName: Rope.ROPE _ NARROW[event.rest.first]; atom: ATOM _ Atom.MakeAtom[intervalName]; f: IO.STREAM _ Feedback.GetTypescriptStream[$Gargoyle]; CodeTimer.PrintInt[f, atom, $Gargoyle]; }; ResetStatistics: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; CodeTimer.ResetTable[CodeTimer.GetTable[$Gargoyle]]; }; DrawTouchPoints: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTouchPoints, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawBoundBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintBoundBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawTightBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintTightBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawOutlineBoxes: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintOutlineBoxes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawSelectionBox: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSelectionBox, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawMovingBox: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; atom: ATOM _ NARROW[event.first]; GGWindow.RestoreScreenAndInvariants[paintAction: atom, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DescribeCaretObject: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; description: Rope.ROPE _ "no object"; chair: REF ANY; chair _ GGCaret.GetChair[ggData.caret]; IF chair # NIL THEN { WITH chair SELECT FROM outlineD: OutlineDescriptor => { description _ outlineD.slice.class.describe[outlineD]; }; sliceD: SliceDescriptor => { description _ sliceD.slice.class.describe[sliceD]; }; ENDCASE => ERROR; }; Feedback.Append[ggData.feedback, IO.PutFR["Caret is on %g.", [rope[description]]], oneLiner]; }; SlackLog: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; }; Typescript: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { [] _ Feedback.OpenTypescript["Gargoyle Typescript", $Gargoyle, 120]; }; cleanIcon: Icons.IconFlavor _ unInit; -- filled in by Init noNameIcon: Icons.IconFlavor _ unInit; -- filled in by Init Init: PROC = { -- copied from GGWindowImpl noNameIcon _ Icons.NewIconFromFile["Gargoyle.icons", 1]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ cleanIcon _ Icons.NewIconFromFile["Gargoyle.icons", 3]; -- done here so file will come from working directory into which Gargoyle was brought over, e.g. ///Commands/ }; Init[]; END. lGGEventImplD.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last edited by Bier on April 20, 1987 6:00:17 pm PDT Contents: Once an event reaches the front of the slack-process queue, it is dispatched to one of the procedures in this module. Pier, May 5, 1987 6:44:05 pm PDT File Operations need to repaint the caption because viewer is no longer edited ASSERT: event is either NIL or event.first=filename ASSERT: event.first=$Get, event.rest=NIL OR filename ASSERT: event.first=$Merge, event.rest=NIL OR filename ASSERT: event=$Merge or $Get TIMING VARIABLES START TIMING here if successfully read a new GG file ASSERT: event.first=$Store or $Save, event.rest=NIL OR filename Save is simply Store invoked with event.first=ggData.outer.file. KAP February 17, 1986 TIMING VARIABLES START TIMING can only reset to the latest version. No version numbers supported for resetting need to repaint the caption because viewer is no longer edited ggData.refresh.suppressRefresh _ FALSE; -- moved to abort processing code Group Operations Area and Line Colors WalkProc: TYPE = PROC [seg: Segment] RETURNS [keep: BOOL]; Debug Menu TestMultiGravity: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; Within the bounds of the viewer, randomly choose mouse positions. See if that mouse position is in range of any object. If so, draw a dot at that point. Repeat until 100 points have been drawn. xRandomStream, yRandomStream: Random.RandomStream; testPoint: Point; x, y: INT; totalCount: NAT _ 0; features: GGMultiGravity.NearFeatures; points: GGMultiGravity.NearPoints; distances: GGMultiGravity.NearDistances; currentObjects: AlignBag; sceneObjects: TriggerBag; count: NAT; xRandomStream _ Random.Create[ggData.actionArea.cw]; yRandomStream _ Random.Create[ggData.actionArea.ch]; GGAlign.SetBagsForAction[ggData, $CaretPos]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintAlign, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; ggData.hitTest.hitCount _ 0; ggData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount > 1000 DO IF ggData.aborted[gravitytest] THEN { ggData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, ggData: ggData]; ggData.refresh.spotPoint _ testPoint; currentObjects _ ggData.hitTest.alignBag; sceneObjects _ ggData.hitTest.sceneBag; [features, points, distances, count] _ GGMultiGravity.MultiMap[20, testPoint, ggData.hitTest.tolerance, currentObjects, sceneObjects, ggData, TRUE]; IF count > 0 THEN { FOR i: NAT IN [0..count-1] DO ggData.refresh.hitPoint _ points[i]; IF distances[i] > ggData.hitTest.tolerance THEN GOTO Done; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; ggData.hitTest.hitCount _ ggData.hitTest.hitCount + 1; REPEAT Done => { IF i = 0 THEN GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; ENDLOOP; } ELSE { GGWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; totalCount _ totalCount + 1; ENDLOOP; Feedback.PutF[ggData.feedback, oneLiner, "Tested %g total points. %g were hits", [integer[totalCount]], [integer[ggData.hitTest.hitCount]]]; }; Within the bounds of the viewer, randomly choose mouse positions. See if that mouse position is in range of any object. If so, draw a dot at that point. Repeat until 100 points have been drawn. GGAlign.SetStaticBags[ggData]; ggData.hitTest.hitCount _ 0; SlackProcess.OutputLog[ggData.slackHandle, Feedback.GetTypescriptStream[$Gargoyle]]; Ê1D˜Icodešœ™Kšœ Ïmœ1™™>KšœŸœ˜ šœŸœŸ˜"Kšœ˜Kšœ˜KšŸœŸœ˜—Kšœ-˜-Kšœ˜K˜—š žœŸœ ŸœŸœŸœŸœŸœ%ŸœŸœŸœŸœŸœ ŸœŸœŸœŸœ˜ÙKšŸœŸœ™3š ž œŸœŸœŸœŸœ Ÿœ˜>šŸœŸœŸ˜KšœŸœŸœŸœ˜2KšœŸœŸœ˜KšŸœŸœ˜—K˜—KšœŸœ˜Kš œ ŸœŸœŸœ ŸœŸœŸœ%˜sKšœr˜rK˜K™—šžœŸ9œ˜BKšœŸœ ˜$KšŸœŸœŸœ ™4KšœŸœ˜KšœŸœŸœ˜(Kšœm˜mšŸœŸœ Ÿœ˜KšœL˜LKšŸœ˜ Kšœ˜—Kšœ˜KšœA˜AKšœ˜šŸ˜KšœŸœ˜=—Kšœ˜K˜—šžœŸ9œ˜DKšœŸœ ˜$KšŸœ!ŸœŸœ ™6KšœŸœ˜KšœŸœŸœ˜(Kšœm˜mšŸœŸœ Ÿœ˜KšœL˜LKšŸœ˜ Kšœ˜—KšœC˜CšŸ˜KšœŸœ˜=—Kšœ˜K˜—šž œŸœŸœŸœŸœ ŸœŸœ˜|KšŸœ™KšœŸœŸœ˜ šœ Ÿœ˜KšÐbkÏb¡ ™—KšœŸœ˜KšœŸœ˜Kšœ Ÿœ˜KšœŸœ˜K˜šœŸœŸœŸœ ˜;Kšœ Ÿœ/˜;Kšœ4˜4KšŸœ˜ Kšœ˜—Kšœ Ÿœ9˜EKšœ1˜1KšŸœŸ™ Kš¢˜Kšœ*˜*Kšœ ˜ Kš¢˜Kšœ1˜1Kšœ Ÿœ3˜?Kšœ/˜/Kšœ Ÿœ™'š Ÿœ ŸœŸœŸœ F˜tKšœ Ÿœ>˜IKšœ9˜9KšœQŸœ˜WKšœŸœŸœ#ŸœS˜¦Kšœ˜—KšœŸœ˜4KšœsŸœ+Ÿœ˜ªšŸ˜Kšœ)˜)—Kšœ ˜K˜—šžœŸ9œ˜DKšœŸœ ˜$KšŸœ*ŸœŸœ ™?KšœBŸœ™WKšœŸœ˜KšœŸœŸœ˜ KšœŸœ˜KšœŸœŸœ˜(KšŸœŸ ™KšœŸœ˜KšœŸœ˜Kšœ Ÿœ˜KšœŸœ˜KšœŸœ ˜Kšœ Ÿœ˜)Kšœx˜xKšŸœŸœ ŸœŸœ˜KšœŸœŸœ Ÿœ˜@š œŸœ"Ÿœ ŸœŸœ Ÿœ ˜eKšœ Ÿœ1˜=KšŸœŸœ Ÿœ5˜JKšŸœ˜ Kšœ˜—KšœŸœ;˜AKš œ ŸœŸœŸœ ŸœŸœ˜VKšœ Ÿœ:˜FKšŸœŸœ Ÿœ2˜GKšŸœŸ™ Kš¢˜Kšœ6˜6Kšœ ˜ Kš¢˜Kšœ1˜1Kšœ Ÿœ3˜?KšŸœŸœ Ÿœ0˜EKšœ Ÿœ? ˜ZKšœ9˜9KšœQŸœ˜WKšœŸœŸœ#ŸœS˜¦Kšœ˜KšœŸœ˜#šŸ˜šœ ˜ KšœŸœ ˜$KšŸœŸœŸœ!˜CKšœ˜——Kšœ˜K˜—šžœŸ9œ˜CKšœŸœ ˜$KšŸœŸœŸœŸœ3˜bšŸœ˜KšœV˜VKšœ ˜ K˜—Kšœ˜K˜—šžœŸ9œ˜DKšœŸœ˜&K˜—šžœŸ9œ˜DKšœŸœ ˜$KšœŸœ˜(Kšœ˜Kš¢P™PšœŸœ˜8Kšœ>™>—Kšœ˜Kšœ˜K˜—šžœŸ9œ˜DKšœŸœ ˜$Kšœ˜KšœŸœ˜Kšœ ˜ Kšœ˜KšœŸœ˜#KšœsŸœ ŸœŸœ˜¢Kšœ˜Kšœ  ˜K˜—š žœŸœ ŸœŸœŸœŸœ˜;KšœŸœ˜!Kšœ-˜-Kšœ%˜%KšœŸœ˜.KšœŸœ˜/Kšœ#Ÿœ˜>Kšœ!Ÿœ !™IKšœŸœŸœ˜Kšœ˜—K˜K™šž œŸ9œ˜IKšœŸœŸœ˜Kšœ˜KšœŸœ ˜$Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lšŸœŸœŸœŸœ˜*KšœH˜HKšŸœ˜K˜—Kšœ:˜:šŸœSŸœŸœŸ˜fKšœ>˜>šŸœOŸœŸœŸ˜bKšœ ŸœŸœ˜šŸœŸœŸœŸœŸœŸœŸœŸ˜BKšœŸœŸœ ˜)šŸœŸœŸœ˜+Kšœ Ÿœ ˜*KšŸœ˜K˜—KšŸœ˜—KšŸœŸœ Ÿœ$Ÿœ˜EKšœŸœ˜KšŸœ˜—KšŸœ˜—Kšœ)ŸœŸœ'Ÿœ<˜¤šœ˜K˜——šž œŸ9œ˜JKšœŸœ ˜$Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lKšœ<˜˜>šŸœOŸœŸœŸ˜bKšœ Ÿœ˜šŸœŸœŸœŸœŸœŸœŸœŸ˜BKšœŸœŸœ ˜)KšŸœŸœŸœŸœ"Ÿœ ŸœŸœ˜wKšŸœ˜—Kšœ˜KšŸœ˜—KšŸœ˜—Kšœ)Ÿœ Ÿœ+ŸœG˜²šœ˜K˜——šžœŸ9œ˜TKš œ ŸœŸœŸœŸœ˜Kšœ˜KšœŸœ ˜$šŸœ-Ÿœ˜5KšœO˜OKšŸœ˜K˜—Kšœ:˜:šŸœSŸœŸœŸ˜fKšœ>˜>šŸœOŸœŸœŸ˜bšŸœŸœŸœŸœŸœŸœŸœŸ˜BKšœŸœŸœ ˜)Kšœ ŸœŸœ˜šŸœŸœŸœŸœŸœŸœŸœŸ˜EKšœŸœŸœ˜+šŸœ!ŸœŸœ˜0Kšœ Ÿœ ˜.KšŸœ˜K˜—KšŸœ˜—K•StartOfExpansion4[l1: LIST OF REF ANY, l2: LIST OF REF ANY _ NIL]šŸœŸœ Ÿœ$Ÿœ ˜IKšŸœ˜—KšŸœ˜—KšŸœ˜—šŸœ ŸœŸœ˜Kšœ@˜@šŸœŸœŸœŸœŸœŸœŸœŸ˜EKšœŸœŸœ˜+KšœB˜BKšŸœ˜—Kšœ*˜*Kšœ˜—KšŸœE˜IKšœ˜K˜—šžœŸ9œ˜MKš œ ŸœŸœŸœŸœ˜KšœŸœ ˜$Kšœ<˜<šŸœCŸœŸœŸ˜YKšœ;˜;šŸœOŸœŸœŸ˜bšŸœŸœŸœŸœŸœŸœŸœŸ˜BKšœŸœŸœ ˜)Kšœ ŸœŸœ˜šŸœŸœŸœŸœŸœŸœŸœŸ˜EKšœŸœŸœ˜+šŸœ!ŸœŸœ˜0Kšœ Ÿœ ˜.KšŸœ˜K˜—KšŸœ˜—K–4[l1: LIST OF REF ANY, l2: LIST OF REF ANY _ NIL]šŸœŸœ Ÿœ$Ÿœ ˜IKšŸœ˜—KšŸœ˜—KšŸœ˜—šŸœ ŸœŸœ˜Kšœ4˜4šŸœŸœŸœŸœŸœŸœŸœŸ˜EKšœŸœŸœ˜+KšœB˜BKšŸœ˜—Kšœ*˜*Kšœ˜—KšŸœ9˜=Kšœ˜—K˜K™KšžœŸœŸœ˜ šžœŸ9œ˜UKšœŸœ ˜$KšŸœŸœI˜iK˜K˜—šžœŸ9œ˜UKšœŸœ ˜$KšŸœŸœI˜iK˜K˜—šžœŸ9œ˜WKšœŸœ ˜$šŸœŸœ˜"Kšœ3 œ˜HšŸœŸœŸœ˜Kšœ%Ÿœ˜*Kšœ˜Kšœ˜—KšŸœJ˜NKšœ˜—K˜K˜—šžœŸ9œ˜WKšœŸœ ˜$šŸœŸœ˜"Kšœ3 œ˜HšŸœŸœŸœ˜Kšœ%Ÿœ˜*Kšœ˜Kšœ˜—KšŸœJ˜NKšœ˜—K˜K˜K˜—šžœŸ9œ˜SKšœŸœ ˜$šŸœŸœ˜"KšœŸœ˜KšœŸœ˜K–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]šœJ˜JšŸœŸœŸ˜.KšœY˜YKšœQ˜QKšŸœŸœ˜—šŸœŸœŸœ˜Kšœ1˜1Kšœ*Ÿœ˜/K˜—KšŸœO˜SK˜—K˜K˜—šžœŸ9œ˜SKšœŸœ ˜$šŸœŸœ˜"KšœŸœ˜KšœŸœ˜K–=[rgb: RGB, calibration: ImagerColor.RGBCalibration _ NIL]šœJ˜JšŸœŸœŸ˜.Kšœk˜kKšœa˜aKšŸœŸœ˜—šŸœŸœŸœ˜Kšœ1˜1Kšœ*Ÿœ˜/K˜—KšŸœQ˜UK˜—K˜K˜K˜—šžœŸ9œ˜XKšœŸœ ˜$Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lšœe˜eKšœŸœ˜0KšœŸœ ˜*K˜—Kšœ˜šŸ˜Kšœ(ŸœQŸœ!˜¦Kšœ%ŸœKŸœ!˜—K˜K˜—šžœŸ9œ˜XKšœŸœ ˜$Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lšœe˜eKšœŸœ˜0KšœŸœ ˜*K˜—Kšœ˜šŸ˜Kšœ(ŸœQŸœ!˜¦Kšœ%ŸœKŸœ!˜—K˜K˜—šžœŸ9œ˜WKšœŸœ ˜$Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lKšœVŸœ˜iKšœ˜šŸ˜Kšœ&ŸœtŸœ!˜Ç—K˜K˜—šžœŸ9œ˜WKšœŸœ ˜$Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lKšœVŸœ˜iKšœ˜šŸ˜Kšœ&ŸœtŸœ!˜Ç—K˜K˜—šžœŸ9œ˜VKšœŸœ ˜$KšœŸœ˜Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lKšœK˜KKšœ ŸœŸœ˜1š ŸœŸœ ŸœŸœ Ÿ˜3šœ˜Kšœ6˜6KšœŸœ˜0KšœŸœ ˜*K˜—šœ˜Kšœ'Ÿœ ˜8—KšŸœŸœ˜—Kšœ+˜+š Ÿœ ŸœŸœ@Ÿœ ŸœŸ˜hšŸœŸœŸ˜˜Kšœ>˜>KšŸœ*Ÿœ=˜mK˜—˜Kšœ:˜:KšŸœ*Ÿœ2Ÿœ#˜ˆK˜—KšŸœŸœ˜—KšŸœ˜—K–Û[feedback: ViewerClasses.Viewer, msgType: GGError.MsgType, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šœc˜cKšœmŸœ ŸœŸœ˜œšŸ˜Kšœ&ŸœtŸœ!˜ÇKšœ(ŸœQŸœ!˜¦Kšœ%ŸœKŸœ!˜—K˜K˜—šžœŸ9œ˜VKšœŸœ ˜$KšœŸœ˜Kš œ ŸœŸœŸœŸœ$ŸœŸœ˜lKšœ<˜KšœF˜FKšœ3˜3Kšœ˜—KšŸœ˜—KšŸœ˜—š ŸœIŸœ ŸœŸœ ˜€šž œ˜Kš ¢œŸœŸœŸœŸœ™:KšœŸœ,˜3K˜—Kšœ6ž œ %˜gK–s[sliceD: GGModelTypes.SliceDescriptor, scene: GGModelTypes.Scene, selectClass: GGSegmentTypes.SelectionClass]šœ4 ˜DKšŸœ˜—K–Û[feedback: ViewerClasses.Viewer, msgType: GGError.MsgType, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šœa˜aKšœmŸœ ŸœŸœ˜œšŸ˜Kšœ&ŸœtŸœ!˜ÇKšœ(ŸœQŸœ!˜¦Kšœ%ŸœKŸœ!˜—K˜K˜—šžœŸ9œ˜RKšœŸœ ˜$KšœŸœŸœ˜KšœJ˜JKšŸœ ŸœŸœ*ŸœŸœŸœŸœm˜×šŸœ˜KšœŸœ˜KšœŸœ˜Kšœ˜šŸœŸœŸ˜Kšœ'ŸœF˜sKšœ#Ÿœ@˜iKšŸœŸœ˜—šŸœŸœŸœ˜Kšœ/˜/KšŸœŸœ$˜@KšŸœŸœ-Ÿœ ˜XKšŸœ˜šœ˜Kšœ˜KšŸœÖ˜ØKšœ ˜ —K˜—KšŸœJ˜NK˜$K˜—K˜K˜—šžœŸ9œ˜RKšœŸœ ˜$KšœŸœŸœ˜KšœJ˜JKšŸœ ŸœŸœ*ŸœŸœŸœŸœm˜×šŸœ˜KšœŸœ˜KšœŸœ˜Kšœ˜šŸœŸœŸ˜šœ ˜ šŸœ4Ÿœ Ÿœ4Ÿœ˜ƒKšœt˜tKšŸœ˜K˜—K˜—Kšœ#Ÿœ0˜YKšŸœŸœ˜—šŸœŸœŸœ˜Kšœ/˜/KšŸœŸœ$˜@KšŸœŸœ-Ÿœ ˜XKšŸœ˜šœ˜Kšœ˜KšŸœÔ˜ÖKšœ ˜ —K˜—KšŸœH˜LK˜"K˜—K˜K˜—šžœŸ9œ˜SKšœŸœ ˜$KšœŸœ˜KšœŸœ˜KšœŸœ˜BšŸœŸœŸœ˜Kšœ/˜/KšŸœŸœ$˜@KšŸœŸœ-Ÿœ ˜XKšŸœ˜šœ˜Kšœ˜KšŸœÖ˜ØKšœ ˜ —K˜—KšŸœJ˜NK˜K˜—šžœŸ9œ˜SKšœŸœ ˜$KšœŸœ˜KšœŸœ˜KšœŸœ˜@šŸœŸœŸœ˜Kšœ/˜/KšŸœŸœ$˜@KšŸœŸœ-Ÿœ ˜XKšŸœ˜šœ˜Kšœ˜KšŸœÔ˜ÖKšœ ˜ —K˜—KšŸœH˜LK˜—K˜šžœŸ9œ˜MKšœŸœ ˜$Kšœ#˜#K˜K˜—šžœŸ9œ˜MKšœŸœ ˜$Kšœ#˜#K˜K˜—šžœŸ9œ˜MKšœŸœ ˜$KšœŸœŸœ˜KšœŸœ˜KšœJ˜JKšŸœ ŸœŸœ*ŸœŸœŸœŸœa˜ËšŸœ˜KšœŸœ˜Kšœ˜šŸœŸœŸ˜Kšœ'Ÿœ4˜aKšœ#Ÿœ0˜YKšŸœŸœ˜—šŸœŸœŸœ˜Kšœ/˜/KšŸœŸœ$˜@KšŸœŸœ-Ÿœ ˜XKšŸœ˜šœ˜Kšœ˜KšŸœÀ˜ÂKšœ ˜ —K˜—KšŸœ=˜AK˜—K˜K˜—šžœŸ9œ˜MKšœŸœ ˜$KšœŸœŸœ˜KšœŸœ˜KšœJ˜JKšŸœ ŸœŸœ*ŸœŸœŸœŸœa˜ËšŸœ˜KšœŸœ˜Kšœ˜šŸœŸœŸ˜Kšœ'ŸœF˜sKšœ#Ÿœ@˜iKšŸœŸœ˜—šŸœŸœŸœ˜Kšœ1˜1KšŸœŸœ$˜@KšŸœŸœ-Ÿœ ˜XKšŸœ˜šœ˜Kšœ˜KšŸœ¿˜ÁKšœ ˜ —K˜—KšŸœ?˜CK˜—K˜K˜K˜—šžœŸ9œ˜MKšœŸœ ˜$Kšœ#˜#K˜K˜—šžœŸ9œ˜MKšœŸœ ˜$Kšœ#˜#K˜K˜—šž œŸ9œ˜LKšœŸœ ˜$Kšœ*˜*K˜K˜—šž œŸ9œ˜LKšœŸœ ˜$Kšœ*˜*K˜K˜—šž œŸ9œ˜LKšœŸœ ˜$Kšœ Ÿœ ˜K˜K˜—šž œŸ9œ˜LKšœŸœ ˜$Kšœ Ÿœ ˜K˜K˜K˜—šž œŸœ#ŸœŸœ˜AKšœŸœ ˜$KšœJ˜Jš Ÿœ ŸœŸœ@Ÿœ ŸœŸ˜hšŸœŸœŸ˜KšœX˜XKšœP˜PKšŸœŸœ˜—KšŸœ˜—KšœqŸœ ŸœŸœ˜ŸK˜K˜—šž œŸœ#ŸœŸœ˜AKšœŸœ ˜$KšœJ˜Jš Ÿœ ŸœŸœ@Ÿœ ŸœŸ˜hšŸœŸœŸ˜Kšœj˜jKšœ`˜`KšŸœŸœ˜—KšŸœ˜—KšœqŸœ ŸœŸœ˜ŸK˜K™—š žœŸœŸœŸœŸœŸœ˜JKš ŸœŸœŸœŸœŸœ˜LKšœd˜dK˜K˜—š žœŸœŸœ!ŸœŸœŸœ˜cKšœ Ÿœ ˜Kš ŸœŸœŸœŸœ  ˜9Kš Ÿœ ŸœŸœŸœ )˜IšŸœ˜Kšœ Ÿ˜Kšœ&˜&KšŸœ Ÿœ Ÿœ ŸœŸœŸœŸœŸœŸœ˜xK˜—K˜K˜—š ž œŸœ ŸœŸœŸœ˜FKšŸœŸœŸœŸœ ˜1šžœŸœŸœ˜Kš ŸœŸœŸœ ŸœŸœ˜4K˜—Kš œŸœŸœŸœŸœ˜KšŸœŸœŸœ ˜3KšŸœŸœŸœ ˜&K˜/KšŸœŸœŸœ ˜3KšŸœŸœŸœ ˜&K˜/KšŸœŸœŸœ ˜3KšŸœŸœŸœ ˜&K˜K˜)šŸ˜Kšœ Ÿœ˜$—K˜—K˜K™ šžœŸ9œ˜OK˜—šžœŸ9œ™OKšœŸœ ™$K™ÄKšœ2™2Kšœ™KšœŸœ™ Kšœ Ÿœ™Kšœ&™&Kšœ"™"Kšœ(™(K™K™KšœŸœ™ Kšœ4™4Kšœ4™4Kšœ,™,KšœgŸœ ŸœŸœ™–Kšœ™KšœŸœ 3™YšŸœŸ™šŸœŸœ™%KšœŸœ™$KšŸœ™K™—Kšœ"™"Kšœ"™"K™KšœK™KKš¢œ ™%Kšœ)™)Kšœ'™'Kšœ6¢œPŸœ™”šŸœ Ÿœ™šŸœŸœŸœŸ™Kš¢œ ™$KšŸœ)ŸœŸœ™:KšœiŸœ ŸœŸœ™˜Kšœ6™6šŸ™šœ ™ KšŸœŸ™ KšœfŸœ ŸœŸœ™•K™——KšŸœ™—K™—šŸœ™KšœfŸœ ŸœŸœ™•K™—K™KšŸœ™—Kšœ™K™K™—šž œŸ9œ˜JKšœŸœ ˜$K™ÄKšœ2˜2Kš œŸœŸœŸœŸœ˜7Kšœ˜KšœŸœ˜ Kšœ3Ÿœ˜;Kšœ˜Kšœ&˜&K˜K˜K˜KšŸœŸœŸœ˜ Kšœ4˜4Kšœ4˜4Kšœ™Kšœ™KšœŸœ 3˜YšŸœŸ˜#šŸœŸœ˜%KšœŸœ˜$KšŸœ˜K˜—Kšœ"˜"Kšœ"˜"K˜KšœK˜KKš¢%˜%Kšœ)˜)Kšœ'˜'Kšœ#¢œLŸœ˜{K–Ò[testPoint: GGBasicTypes.Point, criticalR: REAL, currentObjects: GGMultiGravity.ObjectBag, activeObjects: GGMultiGravity.TriggerBag, gargoyleData: GGInterfaceTypes.GargoyleData, intersections: BOOL]šœ¢œLŸœ˜š ŸœŸœŸœŸœŸœ˜1KšœfŸœ ŸœŸœ˜•K˜KšŸœ˜K˜—šŸœŸœŸœŸœŸœŸœ%ŸœŸœ˜KšœY˜YK˜K˜KšŸœŸœŸœ#˜=KšŸœŸœŸœ˜7K˜—šŸœ˜Kšœ"˜"Kšœ˜K˜Kšœ%˜%KšœiŸœ ŸœŸœ˜˜K˜—KšŸœ˜—KšœÏ˜ÏKšœ ˜K˜—KšœŸœŸœ˜šžœŸœ˜šKšœŸœ˜šŸœŸœŸœ˜KšœE˜EKšŸœŸœ£˜»Kšœ%˜%K˜—šŸœŸœŸœŸœ˜!KšœA˜AKšŸœŸœ˜µKšœ#˜#K˜—šŸœŸœŸœ˜(KšœE˜EKšœA˜AKšŸœŸœ­˜ÅKšœ%˜%K˜—šŸœŸœ%Ÿœ˜2KšŸœŸœ„˜œKšœ%˜%K˜—šŸœŸœŸœ˜$KšœE˜EKšœA˜AKšŸœŸœ«˜ÃKšœ#˜#KšœlŸœ ŸœŸœ˜›Kšœ%˜%K˜—KšŸœŸœ˜ KšœlŸœ ŸœŸœ˜›K˜K˜—šž œŸ9œ˜IKšœŸœ ˜$KšœŸœŸœ+˜7Kšœ7˜7K˜K˜—šžœŸ9œ˜UKšœŸœ ˜$KšœŸœŸœ˜3KšœŸœ˜)KšœŸœŸœ+˜7Kšœ'˜'K˜K˜—šžœŸ9œ˜NKšœŸœ ˜$Kšœ4˜4K˜K˜—šžœŸ9œ˜NKšœŸœ ˜$KšœmŸœ ŸœŸœ˜›K˜K˜—šžœŸ9œ˜MKšœŸœ ˜$KšœlŸœ ŸœŸœ˜šK˜K˜—šžœŸ9œ˜MKšœŸœ ˜$KšœlŸœ ŸœŸœ˜šK˜K˜K˜—šžœŸ9œ˜OKšœŸœ ˜$KšœnŸœ ŸœŸœ˜œK˜K˜—šžœŸ9œ˜OKšœŸœ ˜$KšœnŸœ ŸœŸœ˜œK˜K˜—šž œŸ9œ˜LKšœŸœ ˜$KšœŸœŸœ˜!Kšœ`Ÿœ ŸœŸœ˜ŽK˜K™—šžœŸ9œ˜RKšœŸœ ˜$KšœŸœ˜%KšœŸœŸœ˜Kšœ'˜'šŸœ ŸœŸœ˜šŸœŸœŸ˜˜ Kšœ6˜6K˜—˜Kšœ2˜2K˜—KšŸœŸœ˜—K˜—Kšœ!Ÿœ:˜]K˜K˜—šžœŸ9œ˜GKšœŸœ ˜$KšœT™TK˜—K˜šž œŸ9œ˜IKšœD˜DK˜K˜—Kšœ& ˜:Kšœ' ˜;K˜šžœŸœ ˜*Kšœ9 m˜¦Kšœ8 m˜¥Kšœ˜—K˜Kšœ˜K˜KšŸœ˜—…—µÂör