DIRECTORY AtomButtons, AtomButtonsTypes, Basics, BasicTime, CodeTimer, Containers, CoordSys, DisplayListToTree, Feedback, FileNames, FS, Imager, IO, Menus, Random, Real, Rope, SlackProcess, SV2d, SV3d, SVAlign, SVAssembly, SVBasicTypes, SVCaret, SVCastRays, SVDrawMonitor, SVEditUser, SVEvent, SVFiles, SVGravity, SVInterfaceTypes, SVModelTypes, SVMouseEvent, SVRefresh, SVScene, SVSceneTypes, SVSelect, SVSelections, SVSessionLog, SVState, SVUserInput, SVUtility, SVViewersOnScene, SVViewerTool, SVWindow, TFO3d, ViewerClasses, ViewerOps, ViewerTools; SVEventImplA: CEDAR PROGRAM IMPORTS AtomButtons, BasicTime, CodeTimer, CoordSys, DisplayListToTree, Feedback, FileNames, FS, IO, Random, Rope, SlackProcess, SVAlign, SVAssembly, SVCaret, SVCastRays, SVEditUser, SVEvent, SVFiles, SVGravity, SVMouseEvent, SVRefresh, SVScene, SVSelect, SVSelections, SVSessionLog, SVState, SVUserInput, SVUtility, SVViewersOnScene, SVWindow, TFO3d, ViewerOps, ViewerTools EXPORTS SVEvent = BEGIN AlignBag: TYPE = SVInterfaceTypes.AlignBag; BoundBox: TYPE = SVBasicTypes.BoundBox; Camera: TYPE = SVModelTypes.Camera; Color: TYPE = Imager.Color; CoordSysGenerator: TYPE = SVScene.CoordSysGenerator; CoordSystem: TYPE = SVModelTypes.CoordSystem; CSGTree: TYPE = SVSceneTypes.CSGTree; DisplayContextProc: TYPE = SVInterfaceTypes.DCProc; DrawStyle: TYPE = SVModelTypes.DrawStyle; EditToolData: TYPE = SVInterfaceTypes.EditToolData; FeatureData: TYPE = SVInterfaceTypes.FeatureData; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; FileCamera: TYPE = SVSceneTypes.FileCamera; GravityType: TYPE = SVInterfaceTypes.GravityType; MasterObject: TYPE = SVSceneTypes.MasterObject; Matrix4by4: TYPE = SV3d.Matrix4by4; MouseButton: TYPE = Menus.MouseButton; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; Primitive: TYPE = SVSceneTypes.Primitive; Scene: TYPE = SVSceneTypes.Scene; Slice: TYPE = SVSceneTypes.Slice; SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = SVSceneTypes.SliceDescriptorGenerator; SortedButtonHandle: TYPE = AtomButtonsTypes.SortedButtonHandle; TriggerBag: TYPE = SVInterfaceTypes.TriggerBag; TwoState: TYPE = AtomButtons.TwoState; Vector2d: TYPE = SV2d.Vector2d; Vector3d: TYPE = SV3d.Vector3d; Viewer: TYPE = ViewerClasses.Viewer; SVData: TYPE = SVInterfaceTypes.SVData; GravityChoiceChange: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { forward: BOOL _ event.rest.first = $FlipForward; SVState.CycleGravityType[svData, forward]; }; GravityExtentChange: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { extent: REAL _ SVState.GetGravityExtent[svData]; -- in inches success: BOOL _ TRUE; SELECT event.rest.first FROM $ValueUp => { IF extent < 256.0 THEN extent _ extent*2.0 ELSE { Feedback.PutF[svData.feedback, oneLiner, "Can't extend gravity further than 256 inches."]; Feedback.Blink[svData.feedback]; success _ FALSE; }; }; $ValueDown => extent _ extent/2.0; ENDCASE => extent _ SVEditUser.GetDefaultGravityExtent[]; IF success THEN { SVState.SetGravityExtent[svData, extent]; }; }; ToggleGravity: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVState.ToggleGravity[svData]; }; ToggleMidpoints: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVState.ToggleMidpoints[svData]; }; InitializeAlignments: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AllAlignmentsOff[NIL, svData]; SVState.SetShowAlignments[svData, TRUE]; SVState.SetGravity[svData, TRUE]; SVState.SetGravityType[svData, pointsPreferred]; SVEvent.InchScaleUnit[NIL, svData]; SVState.SetHeuristics[svData, TRUE]; }; AllAlignmentsOff: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SlopeLinePrompt[event, svData]; SlopePlanePrompt[event, svData]; SVState.SetMidpoints[svData, FALSE]; }; StandardSlopes: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AtomButtons.BuildScalarButtons[svData.hitTest.slopeHandle, svData, SVUserInput.EventNotify, NIL, LIST[ ["150", 150.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 150.0]]], FALSE], ["135", 135.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 135.0]]], FALSE], ["120", 120.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 120.0]]], FALSE], ["90", 90.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 90.0]]], FALSE], ["60", 60.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 60.0]]], FALSE], ["45", 45.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 45.0]]], FALSE], ["30", 30.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 30.0]]], FALSE], ["0", 0.0, LIST[LIST[$ChooseSlope, NEW[REAL _ 0.0]]], TRUE] ]]; }; StandardAzimuths: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AtomButtons.BuildScalarButtons[svData.hitTest.azimuthHandle, svData, SVUserInput.EventNotify, NIL, LIST[ ["150", 150.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 150.0]]], FALSE], ["135", 135.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 135.0]]], FALSE], ["120", 120.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 120.0]]], FALSE], ["90", 90.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 90.0]]], FALSE], ["60", 60.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 60.0]]], FALSE], ["45", 45.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 45.0]]], FALSE], ["30", 30.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 30.0]]], FALSE], ["0", 0.0, LIST[LIST[$ChooseAzimuth, NEW[REAL _ 0.0]]], TRUE] ]]; }; StandardSlopeLines: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AtomButtons.BuildSortedButtons[svData.hitTest.slopeLineHandle, svData, SVUserInput.EventNotify, NIL, LIST[ ["(0 0)",NEW[Vector2d_[0,0]], LIST[LIST[$ToggleSlopeLine,NEW[Vector2d_[0,0]]]],TRUE], ["(0 90)",NEW[Vector2d_[0,90]],LIST[LIST[$ToggleSlopeLine,NEW[Vector2d_[0,90]]]],FALSE], ["(90 0)",NEW[Vector2d_[90,0]], LIST[LIST[$ToggleSlopeLine,NEW[Vector2d_[90,0]]]],FALSE] ]]; IF event.first = $StandardSlopeLines THEN SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; StandardSlopePlanes: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AtomButtons.BuildSortedButtons[svData.hitTest.slopePlaneHandle, svData, SVUserInput.EventNotify, NIL, LIST[ ["(0 0)",NEW[Vector2d_[0,0]],LIST[LIST[$ToggleSlopePlane,NEW[Vector2d_[0,0]]]],FALSE], ["(0 90)",NEW[Vector2d_[0,90]],LIST[LIST[$ToggleSlopePlane,NEW[Vector2d_[0,90]]]],FALSE], ["(90 0)",NEW[Vector2d_[90,0]],LIST[LIST[$ToggleSlopePlane,NEW[Vector2d_[90,0]]]],TRUE] ]]; IF event.first = $StandardSlopePlanes THEN SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; AzimuthPrompt: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; GetAzimuth: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; AddAzimuth: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { azimuth: REAL; success, alreadyThere: BOOL; [azimuth, success] _ SVState.GetAzimuthValue[svData]; IF NOT success THEN RETURN; alreadyThere _ SVState.AddAzimuth[svData, azimuth]; IF NOT alreadyThere THEN { -- a new button was added SVWindow.RestoreScreenAndInvariants[paintAction: $None, svData: svData, remake: none, backgndOK: TRUE, edited: TRUE, okToClearFeedback: TRUE]; }; }; DeleteAzimuth: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVState.DeleteAzimuth[svData]; SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ChooseAzimuth: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { azimuth: REAL _ NARROW[event.rest.first, REF REAL]^; AtomButtons.SetAllScalarStates[svData, svData.hitTest.azimuthHandle, FALSE]; AtomButtons.SetScalarState[svData, svData.hitTest.azimuthHandle, azimuth, TRUE]; }; SlopePrompt: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; GetSlope: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; AddSlope: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { slope: REAL; success, alreadyThere: BOOL; [slope, success] _ SVState.GetSlopeValue[svData]; IF NOT success THEN RETURN; alreadyThere _ SVState.AddSlope[svData, slope]; IF NOT alreadyThere THEN { -- a new button was added SVWindow.RestoreScreenAndInvariants[paintAction: $None, svData: svData, remake: none, backgndOK: TRUE, edited: TRUE, okToClearFeedback: TRUE]; }; }; DeleteSlope: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVState.DeleteSlope[svData]; SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ChooseSlope: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { slope: REAL _ NARROW[event.rest.first, REF REAL]^; AtomButtons.SetAllScalarStates[svData, svData.hitTest.slopeHandle, FALSE]; AtomButtons.SetScalarState[svData, svData.hitTest.slopeHandle, slope, TRUE]; }; SlopeLinePrompt: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AtomButtons.SetAllScalarStates[svData, svData.hitTest.slopeLineHandle, FALSE]; IF event.first = $SlopeLinePrompt THEN SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; GetSlopeLine: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; AddSlopeLine: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AddAzimuth[event, svData]; AddSlope[event, svData]; NewSlopeLine[event, svData]; }; NewSlopeLine: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { azimuth, slope: REAL; alreadyThere: BOOL; azimuth _ SVState.GetSelectedAzimuth[svData]; slope _ SVState.GetSelectedSlope[svData]; alreadyThere _ SVState.AddSlopeLine[svData, azimuth, slope]; SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DeleteSlopeLine: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVState.DeleteSlopeLines[svData]; SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleSlopeLine: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { restoreNow: BOOL _ event.first = $ToggleSlopeLine; ToggleAlignmentAux[event, svData, svData.hitTest.slopeLineHandle, restoreNow]; }; ToggleAlignmentAux: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData, handle: SortedButtonHandle, restoreNow: BOOL] = { FindAzimuthSlope: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [newState: BOOL, newName: Rope.ROPE _ NIL, newValue: REF ANY, done: BOOL _ FALSE] = { azimuthSlope: Vector2d _ NARROW[value, REF Vector2d]^; IF ABS[azimuthSlope[1]-azimuth] < epsilon AND ABS[azimuthSlope[2]-slope] < epsilon THEN {totalNewState _ newState _ NOT state; done _ TRUE} ELSE newState _ state; newName _ name; newValue _ value; }; epsilon: REAL = 0.001; totalNewState: BOOL; azimuth, slope: REAL; azimuthSlope: Vector2d; azimuthSlope _ NARROW[event.rest.first, REF Vector2d]^; azimuth _ azimuthSlope[1]; slope _ azimuthSlope[2]; AtomButtons.WriteSortedButtons[handle, FindAzimuthSlope, svData]; IF restoreNow AND totalNewState THEN SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE] ELSE SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; SlopePlanePrompt: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AtomButtons.SetAllScalarStates[svData, svData.hitTest.slopePlaneHandle, FALSE]; IF event.first = $SlopePlanePrompt THEN SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; GetSlopePlane: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; AddSlopePlane: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { AddAzimuth[event, svData]; AddSlope[event, svData]; NewSlopePlane[event, svData]; }; NewSlopePlane: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { azimuth, slope: REAL; alreadyThere: BOOL; azimuth _ SVState.GetSelectedAzimuth[svData]; slope _ SVState.GetSelectedSlope[svData]; alreadyThere _ SVState.AddSlopePlane[svData, azimuth, slope]; SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsSelected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DeleteSlopePlane: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVState.DeleteSlopePlanes[svData]; SVWindow.RestoreScreenAndInvariants[paintAction: $NewAlignmentsDeselected, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; ToggleSlopePlane: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { restoreNow: BOOL _ event.first = $ToggleSlopePlane; ToggleAlignmentAux[event, svData, svData.hitTest.slopePlaneHandle, restoreNow]; }; Painter: PUBLIC PROC [proc: DisplayContextProc, svData: SVData _ NIL] = { }; -- end of Painter UpdateHeader: PUBLIC PROC [pictureFile: Rope.ROPE, svData: SVData] = { headerRope: Rope.ROPE; aisName: Rope.ROPE; viewName: Rope.ROPE _ svData.camera.viewName; IF pictureFile = NIL THEN pictureFile _ svData.scene.name; headerRope _ Rope.Cat[viewName, " View of Solid Scene: ", pictureFile]; aisName _ Rope.Concat[SVFiles.FilenameMinusExtension[pictureFile], ".ais"]; svData.outer.name _ headerRope; ViewerOps.PaintViewer[svData.outer, caption, FALSE, NIL]; }; NewVersion: PUBLIC PROC [viewer: Viewer] = { svData: SVData _ NARROW[viewer.data]; scene: Scene _ svData.scene; scene.dirty _ TRUE; svData.scene.tree.outOfDate _ TRUE; svData.outer.newVersion _ TRUE; UpdateHeader[scene.name, svData]; }; SceneOldVersion: PUBLIC PROC [svData: SVData] = { scene: Scene _ svData.scene; SVViewersOnScene.SceneOldVersion[svData, scene]; }; OldVersion: PUBLIC PROC [viewer: Viewer] = { svData: SVData _ NARROW[viewer.data]; scene: Scene _ svData.scene; scene.dirty _ FALSE; svData.scene.tree.outOfDate _ TRUE; -- OldVersion may result from loading a new scene, or creating an empty scene. In either case, the ray tracing tree is out of date. Set flag just in case. svData.outer.newVersion _ FALSE; UpdateHeader[scene.name, svData]; }; EraseAndDrawScene: PUBLIC PROC [svData: SVData] = { SVWindow.RestoreScreenAndInvariants[$PaintEntireScene, svData]; }; DrawSceneButton: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVWindow.RestoreScreenAndInvariants[$PaintEntireScene, svData]; }; Clear: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { editToolData: EditToolData _ svData.editToolData; oldScene: Scene _ svData.scene; newScene: Scene; oldScreenCS: CoordSystem; fileCamera: FileCamera; cameraName: Rope.ROPE; drawStyle: DrawStyle; oldScreenCS _ svData.camera.screenCS; newScene _ svData.scene _ SVScene.CreateScene["NoName.pic"]; SVSelections.KillSkitterAndSelections[editToolData]; UpdateHeader[newScene.name, svData]; SVEvent.Selected[event, svData]; IF newScene.cameraOrder = NIL THEN fileCamera _ newScene.cameras.first ELSE { success: BOOL; cameraName _ newScene.cameraOrder.first; [fileCamera, success] _ SVScene.FindFileCameraFromName[cameraName, newScene]; IF NOT success THEN { fileCamera _ newScene.cameras.first; Feedback.Append[svData.feedback, Rope.Cat["Camera ", cameraName, " not found"], oneLiner]; Feedback.Blink[svData.feedback]; }; }; drawStyle _ SVEvent.CurrentStyle[svData]; svData.camera _ SVScene.CreateCamera[newScene.coordSysRoot, CoordSys.CopyCoordSysFromAnyTree[oldScreenCS, "SCREEN", NIL, NIL], drawStyle]; SVScene.StuffCameraFromFileCamera[svData.camera, fileCamera, svData.camera.style, newScene]; SVViewersOnScene.NotifyOfEmpty[svData: svData, from: oldScene, to: svData.scene]; SceneOldVersion[svData]; SVWindow.RestoreScreenAndInvariants[$PaintEntireScene, svData]; }; Restore: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { editToolData: EditToolData _ svData.editToolData; success: BOOL; wdir: Rope.ROPE; scene: Scene _ svData.scene; wdir _ editToolData.originalWorkingDirectory; [scene, success] _ SVViewersOnScene.LoadScene[svData, scene.name, wdir]; IF success THEN { svData.scene _ scene; SVSelections.KillSkitterAndSelections[editToolData]; SceneOldVersion[svData]; UpdateHeader[scene.name, svData]; EraseAndDrawScene[svData]; SVEvent.Selected[event, svData]; }; }; -- end of Reset Save: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { success: BOOL; sceneName: Rope.ROPE; scene: Scene _ svData.scene; sceneName _ FileNames.StripVersionNumber[scene.name]; success _ SVViewersOnScene.SaveScene[svData, sceneName]; IF success THEN { SVEvent.Selected[event, svData]; SceneOldVersion[svData]; UpdateHeader[scene.name, svData]; }; }; -- end of Save GetMergeAux: PROC [fullName: Rope.ROPE, wdir: Rope.ROPE, versionSpecified: BOOL _ FALSE, event: ATOM, opName: Rope.ROPE, svData: SVData] = { success: BOOL; scene: Scene; oldScreenCS: CoordSystem _ svData.camera.screenCS; startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; timeRope: Rope.ROPE; drawStyle: DrawStyle; fileCamera: FileCamera; cameraName: Rope.ROPE; startTime _ BasicTime.Now[]; [scene, success] _ SVViewersOnScene.LoadScene[svData, fullName, wdir]; IF NOT success THEN RETURN; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; timeRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; Feedback.Append[svData.feedback, timeRope, oneLiner]; IF scene.cameraOrder = NIL THEN fileCamera _ scene.cameras.first ELSE { cameraName _ scene.cameraOrder.first; [fileCamera, success] _ SVScene.FindFileCameraFromName[cameraName, scene]; IF NOT success THEN { fileCamera _ scene.cameras.first; Feedback.Append[svData.feedback, Rope.Cat["Camera ", cameraName, " not found"], oneLiner]; Feedback.Blink[svData.feedback]; }; }; drawStyle _ SVEvent.CurrentStyle[svData]; svData.camera _ SVScene.CreateCamera[scene.coordSysRoot, CoordSys.CopyCoordSysFromAnyTree[oldScreenCS, "SCREEN", NIL, NIL], drawStyle]; SVScene.StuffCameraFromFileCamera[svData.camera, fileCamera, svData.camera.style, scene]; svData.scene _ scene; UpdateHeader[fullName, svData]; SceneOldVersion[svData]; SVEvent.Selected[NIL, svData]; SVWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, svData: svData, remake: triggerBag, backgndOK: FALSE, edited: event=$Merge, okToClearFeedback: FALSE]; }; Get: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { editToolData: EditToolData _ NARROW[svData.editToolData]; picName: Rope.ROPE _ NARROW[event.rest.first]; success: BOOL; fullName: Rope.ROPE; wdir: Rope.ROPE; IF Rope.Length[picName] = 0 THEN RETURN; wdir _ editToolData.originalWorkingDirectory; success _ TRUE; [fullName,,] _ FS.ExpandName[picName, wdir ! FS.Error => IF error.group = user THEN { success _ FALSE; CONTINUE; } ]; IF NOT success THEN RETURN; ClearAux[event, svData]; GetMergeAux[fullName, wdir, FALSE, $Get, "Get", svData]; }; -- end of Get ClearAux: PROC [event: LIST OF REF ANY, svData: SVData] = { svData.refresh.overlayList _ NIL; SVSelect.DeselectAllAllClasses[svData.scene]; svData.editToolData.skitter _ SVCaret.Create[]; svData.scene.anchor _ SVCaret.Create[]; svData.aborted _ ALL[FALSE]; }; Store: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { editToolData: EditToolData _ NARROW[svData.editToolData]; wdir: Rope.ROPE; success: BOOL; picName: Rope.ROPE _ NARROW[event.rest.first]; fullName: Rope.ROPE; scene: Scene _ svData.scene; IF Rope.Length[picName] = 0 THEN RETURN; wdir _ editToolData.originalWorkingDirectory; success _ TRUE; [fullName,,] _ FS.ExpandName[picName, wdir ! FS.Error => IF error.group = user THEN { success _ FALSE; CONTINUE; } ]; IF NOT success THEN RETURN; success _ SVViewersOnScene.StoreScene[svData, scene, fullName]; IF success THEN { UpdateHeader[fullName, svData]; SVEvent.Selected[event, svData]; SceneOldVersion[svData]; UpdateHeader[scene.name, svData]; }; }; -- end of Store Split: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { scene: Scene _ svData.scene; SVViewersOnScene.Split[svData, scene]; }; OpenScript: PUBLIC Menus.ClickProc = { svData: SVData _ NARROW[clientData]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; SVSessionLog.OpenScript[name, svData]; IF svData.debug.logStream#NIL THEN [] _ SlackProcess.EnableSessionLogging[svData.slackHandle]; }; AppendToScript: PUBLIC Menus.ClickProc = { svData: SVData _ NARROW[clientData]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; SVSessionLog.AppendScript[name, svData]; IF svData.debug.logStream#NIL THEN [] _ SlackProcess.EnableSessionLogging[svData.slackHandle]; }; CloseScript: PUBLIC Menus.ClickProc = { svData: SVData _ NARROW[clientData]; [] _ SlackProcess.DisableSessionLogging[svData.slackHandle]; SVSessionLog.CloseScript[svData]; }; PlaybackScript: PUBLIC Menus.ClickProc = { svData: SVData _ NARROW[clientData]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; SVSessionLog.PlaybackFromFile[name, svData]; }; FastPlayScript: PUBLIC Menus.ClickProc = { svData: SVData _ NARROW[clientData]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; SVUserInput.EventNotify[svData, LIST[$DisableRefresh]]; SVSessionLog.PlaybackFromFile[name, svData]; SVUserInput.EventNotify[svData, LIST[$EnableRefresh]]; SVUserInput.EventNotify[svData, LIST[$Refresh, $DoNotClearFeedback]]; }; RayCast: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { editToolData: EditToolData _ NARROW[svData.editToolData]; scene: Scene _ svData.scene; camera: Camera _ svData.camera; feedback: FeedbackData _ svData.feedback; tree: CSGTree; startTime: BasicTime.GMT; afterTreeTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope, wdir: Rope.ROPE; aisFileRope: Rope.ROPE; success: BOOL; maxRed, maxGreen, maxBlue, maxBlack: NAT; aisFileRope _ Rope.Concat[SVFiles.FilenameMinusExtension[scene.name], ".ais"]; wdir _ editToolData.originalWorkingDirectory; success _ TRUE; [aisFileRope,,] _ FS.ExpandName[aisFileRope, wdir ! FS.Error => IF error.group = user THEN { Feedback.Append[svData.feedback, Rope.Concat["RayCast: ", error.explanation], oneLiner]; success _ FALSE; CONTINUE; } ]; IF NOT success THEN RETURN; startTime _ BasicTime.Now[]; tree _ DisplayListToTree.AssemblyToTree[scene.assembly, scene, camera]; afterTreeTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[from: startTime, to: afterTreeTime]; Feedback.PutF[svData.feedback, oneLiner, "Building tree took (%r)",[integer[totalTime]]]; [success, maxRed, maxGreen, maxBlue, maxBlack] _ SVCastRays.DrawTree[tree, scene.lightSources, camera, aisFileRope, TRUE, SVEvent.RayCastProgress, svData, feedback]; IF NOT success THEN { Feedback.PutF[feedback, end, "...Raycast aborted."]; RETURN; }; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[from: afterTreeTime, to: endTime]; Feedback.PutF[svData.feedback, begin, " Raycast took (%r).",[integer[totalTime]]]; msgRope _ IO.PutFR[" Max values were: red: (%g) green: (%g) blue: (%g) black: (%g)\n", [integer[maxRed]], [integer[maxGreen]], [integer[maxBlue]], [integer[maxBlack]]]; Feedback.AppendTypescript[svData.feedback, msgRope, end]; SVEvent.DrawBlackAndWhite[event, svData]; }; -- end of RayCast StopRays: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { camera: Camera _ svData.camera; camera.abort _ TRUE; }; ARay: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { scene: Scene _ svData.scene; camera: Camera _ svData.camera; outHandle: IO.STREAM _ Feedback.GetTypescriptStream[$Solidviews]; x, y: REAL; tree: CSGTree _ DisplayListToTree.AssemblyToTree[scene.assembly, scene, camera]; color: Color; [x, y] _ SVUtility.ReadTwoReals[svData.textSection.xyz]; color _ SVCastRays.SingleRay[[x, y], tree, scene.lightSources, camera, svData.feedback, TRUE]; Feedback.PutFTypescript[svData.feedback, begin, "[%g,%g]: ",[real[x]], [real[y]]]; TFO3d.FileoutColor[outHandle, color]; Feedback.PutFTypescript[svData.feedback, end, "\n"]; }; -- end of ARay CycleSelection: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { scene: Scene _ svData.scene; pointWorld: Point3d; normalWorld: Vector3d; feature: FeatureData; hitData: REF ANY; featureCycler: SVGravity.FeatureCycler _ SVState.GetSelectionCycler[svData]; direction: ATOM _ NARROW[event.rest.first]; SELECT direction FROM $Forward => [pointWorld, normalWorld, feature, hitData] _ SVGravity.NextFeature[featureCycler]; $Backward => [pointWorld, normalWorld, feature, hitData] _ SVGravity.PreviousFeature[featureCycler]; ENDCASE => ERROR; SVMouseEvent.SelectFromFeature[svData, featureCycler.cameraPt, pointWorld, normalWorld, feature, hitData]; }; MakeHot: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { sliceDescGen: SliceDescriptorGenerator _ SVSelect.SelectedSlices[svData.scene, normal]; FOR sliceD: SliceDescriptor _ SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO SVSelect.SelectSlice[sliceD, svData.scene, hot]; ENDLOOP; sliceDescGen _ SVSelect.SelectedSlices[svData.scene, hot]; FOR sliceD: SliceDescriptor _ SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO sliceFeature: FeatureData _ SVAlign.AddHotSlice[sliceD, svData.hitTest.triggerBag]; -- fix triggerBag alignObjects: LIST OF FeatureData _ SVAlign.IncrementalFilters[sliceFeature, svData.hitTest, NOT SVState.GetShowAlignments[svData], svData.hitTest.alignBag]; SVRefresh.NoteNewForeground[alignObjects, svData]; -- fix foreground plane ENDLOOP; SVWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, svData: svData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; MakeCold: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { sliceDescGen: SliceDescriptorGenerator _ SVSelect.SelectedSlices[svData.scene, normal]; FOR sliceD: SliceDescriptor _ SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO SVSelect.DeselectSlice[sliceD.slice, sliceD.parts, svData.scene, hot]; ENDLOOP; SVWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, svData: svData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; MakeAllHot: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { triggerBag: TriggerBag _ svData.hitTest.triggerBag; alignBag: AlignBag _ svData.hitTest.alignBag; sliceDescGen: SliceDescriptorGenerator; sliceGen: SVScene.AssemblyGenerator _ SVScene.PrimAssembliesInScene[svData.scene]; FOR slice: Slice _ SVScene.NextAssembly[sliceGen], SVScene.NextAssembly[sliceGen] UNTIL slice = NIL DO sliceD: SliceDescriptor _ SVAssembly.NewParts[slice, NIL, [0,0,0], topLevel]; SVSelect.SelectSlice[sliceD, svData.scene, hot]; ENDLOOP; sliceDescGen _ SVSelect.SelectedSlices[svData.scene, hot]; -- expects only outline types !! FOR sliceD: SliceDescriptor _ SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO feature: FeatureData _ SVAlign.AddHotSlice[sliceD, triggerBag]; alignObjects: LIST OF FeatureData; alignObjects _ SVAlign.IncrementalFilters[feature, svData.hitTest, NOT SVState.GetShowAlignments[svData], alignBag]; SVRefresh.NoteNewForeground[alignObjects, svData]; ENDLOOP; SVWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeHot, svData: svData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; MakeAllCold: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { sliceDescGen: SliceDescriptorGenerator _ SVSelect.SelectedSlices[svData.scene, hot]; FOR sliceD: SliceDescriptor _ SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO SVSelect.DeselectSlice[sliceD.slice, sliceD.parts, svData.scene, hot]; ENDLOOP; SVWindow.RestoreScreenAndInvariants[paintAction: $SequencesMadeCold, svData: svData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; DropAnchor: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { editToolData: EditToolData _ svData.editToolData; SVCaret.Copy[from: editToolData.skitter, to: svData.scene.anchor]; [] _ SVAlign.CreateAnchorTrigger[SVState.GetAnchor[svData], svData.hitTest.triggerBag]; -- anchor can trigger SVWindow.RestoreScreenAndInvariants[paintAction: $AnchorAdded, svData: svData, remake: alignBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; LiftAnchor: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { IF SVCaret.Exists[svData.scene.anchor] THEN { SVCaret.Kill[svData.scene.anchor]; SVWindow.RestoreScreenAndInvariants[paintAction: $AnchorRemoved, svData: svData, remake: triggerBag, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; }; }; StandardAlignments: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { }; ToggleShowColors: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { stateInfo: TwoState _ svData.refresh.showColors; AtomButtons.SwitchBinaryState[stateInfo]; SVWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireViewer, svData: svData, remake: none, backgndOK: FALSE, edited: FALSE, okToClearFeedback: TRUE]; }; DrawCoordSystems: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVWindow.RestoreScreenAndInvariants[$DrawCoordSystems, svData]; }; DrawBoundBoxes: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVWindow.RestoreScreenAndInvariants[$DrawBoundBoxes, svData]; }; -- end of DrawBoundBoxes DrawBoundSpheres: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVWindow.RestoreScreenAndInvariants[$DrawBoundSpheres, svData]; }; -- end of DrawBoundSpheres DrawPt: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { camera: Camera _ svData.camera; SVWindow.RestoreScreenAndInvariants[$DrawPt, svData]; }; CrossHairs: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { SVWindow.RestoreScreenAndInvariants[$DrawCrossHairs, svData]; }; -- end of CrossHairs TestGravity: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { xRandomStream, yRandomStream: Random.RandomStream; testPoint: Point2d; pointCount: INT _ NARROW[event.rest.first, REF INT]^; x, y: INT; totalCount, hitCount, diffCount: NAT _ 0; surfacePtWORLD: Point3d; camera: Camera _ svData.camera; scene: Scene _ svData.scene; screenCS: CoordSystem _ camera.screenCS; feature: FeatureData; gravityType: GravityType _ SVState.GetGravityType[svData]; xRandomStream _ Random.Create[svData.actionArea.cw]; yRandomStream _ Random.Create[svData.actionArea.ch]; UNTIL totalCount >= pointCount DO x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ CoordSys.ScreenToCamera[testPoint, screenCS]; svData.refresh.spotPoint _ testPoint; [surfacePtWORLD, ----, feature] _ SVGravity.RayMap[testPoint, svData.hitTest.t, NIL, svData.hitTest.sceneBag, svData]; totalCount _ totalCount + 1; IF feature = NIL THEN { SVWindow.RestoreScreenAndInvariants[paintAction: $PaintSpot, svData: svData]; } ELSE { hitCount _ hitCount + 1; svData.refresh.hitPoint _ surfacePtWORLD; SVWindow.RestoreScreenAndInvariants[paintAction: $PaintHitLine, svData: svData]; }; ENDLOOP; Feedback.PutF[svData.feedback, oneLiner, "Tested %g total points. %g hits.", [integer[totalCount]], [integer[hitCount]]]; }; -- end TestGravity ResetStatistics: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { CodeTimer.ResetTable[CodeTimer.GetTable[$Solidviews]]; }; PrintStatistics: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { f: IO.STREAM _ Feedback.GetTypescriptStream[$Solidviews]; CodeTimer.PrintTable[f, CodeTimer.GetTable[$Solidviews]]; }; RaiseSIGNAL: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { scene: SVSceneTypes.Scene _ svData.scene; firstSlice, secondSlice: SVSceneTypes.Slice; sliceGen: SVScene.AssemblyGenerator; sliceGen _ SVScene.PrimAssembliesInScene[scene]; firstSlice _ SVScene.NextAssembly[sliceGen]; secondSlice _ SVScene.NextAssembly[sliceGen]; SIGNAL Feedback.Problem[msg: "Client requested SIGNAL"]; }; END. 8File: SVEventImplA.mesa Author: Eric Bier in October 1982 Copyright c 1984 by Xerox Corporation. All rights reserved. Last edited by Bier on July 12, 1987 11:39:13 pm PDT Contents: Code to respond to button presses made in an SVViewer Gravity Line Operations Alignment Lines ["", 999.9, LIST[$NoOp, NEW[REAL _ 999.9]], FALSE], -- dummy first button ["", 999.9, LIST[$NoOp, NEW[REAL _ 999.9]], FALSE], -- dummy first button Azimuth Line adds azimuth from azimuth viewer in measure line If azimuthViewValue was set internally, viewer and value will be consistent. If AzimuthValue viewer was set by typein, viewer and value will be inconsistent. Slope Line Since slopes are mutually exclusive, there is no reason to turn them all off. We could set the slope to 0 or do nothing at all. adds slope from angle viewer in measure line If slopeViewValue was set internally, viewer and value will be consistent. If SlopeValue viewer was set by typein, viewer and value will be inconsistent. Slope Line Line Slope Plane Line MISCELLANEOUS Tell EditTool that scene is no longer dirty. EditTool will call back all affected viewers using OldVersion (see below). DRAW SOMETHING IN A SOLID VIEWER (Fetches a display context first) MENU PROCS Creates a new empty scene for the viewer to view. This must be done after NotifyOfEmpty since SVViewersOnScene expects to register to the newly created NoName scene before it resets the [New Version] headers. Reload this scene from its backing file. TIMING VARIABLES Choose a Tripod Finish Up svData.scene _ SVScene.CreateScene["NoName.pic"]; aisName _ Rope.Concat[SVFiles.FilenameMinusExtension[fullName], ".ais"]; Create a new viewer onto this scene. Update the ring of links joining all viewers onto this scene, Script Menu in SVEventImplA.OpenScript IF mouseButton = red OR mouseButton = blue THEN { [success, maxRed, maxGreen, maxBlue, maxBlack] _ SVCastRays.DrawTree[tree, scene.lightSources, camera, aisFileRope, mouseButton = blue, SVEvent.RayCastProgress, svData, feedback]; } ELSE { -- yellow bug cameraPoint: Point2d; [cameraPoint, ----] _ SVSelections.GetPositionSkitter[]; [success, maxRed, maxGreen, maxBlue, maxBlack] _ SVCastRays.DrawTreeWithStartLine[cameraPoint[2], tree, scene.lightSources, camera, aisFileRope, mouseButton = blue, SVEvent.RayCastProgress, svData, feedback]; }; Get x and y from appropriate slots. Interpret this as camera coordinates and draw a cross. Select Menu Hot Spots Menu Make slices hot. Fix the trigger bags, object bags, and Foreground plane (for efficiency). Repaint Update the hot and current trigger bags. SVAlign.RemoveAnchorTrigger[svData.hitTest.triggerBag]; -- don't trigger SVAlign.RemoveAnchorTrigger[svData.hitTest.sceneBag]; -- don't be gravity active Other Style Buttons viewer is Container get x and y from appropriate slots. Interpret this as camera coordinates and draw a cross. viewer is the crossHairs button 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. Κ#˜˜Iheadšœ™Jšœ!™!Jšœ Οmœ1™Jšœ žœ˜Jšœžœ˜Jšœ˜Jšœ5˜5Jšœ8˜8šžœ žœ˜Jšœ ˜ Jšœ˜Jšœ!˜!Jšœ˜—Jšœ ˜J˜—šŸ œžœžœ žœžœžœ žœžœ˜ŒJšœ žœ˜Jšœ ˜ Jšœ2˜2Jšœ™Jšœ˜Jšœ˜Jšœ žœ˜Jšœžœ˜Jšœ˜Jšœ˜Jšœžœ˜J˜Jš‘˜Jšœ‘œ˜FJšžœžœ žœžœ˜Jš‘˜J˜Jšœ1˜1Jšœ@˜@Jšœ5˜5J˜Jš‘™Jšžœžœžœ!˜@šžœ˜Jšœ%˜%JšœJ˜Jšžœžœ žœ˜Jšœ!˜!JšœZ˜ZJšœ ˜ J˜—J˜—Jšœ)˜)Jšœqžœžœ˜‡JšœY˜YJš‘ ™ Jšœ˜Jšœ˜Jšœ˜Jšœžœ ˜Lšœsžœ+žœ˜ͺL˜L˜—šŸœžœžœ žœžœžœžœ˜=Jšœžœ˜9Jšœžœžœ˜.Jšœ žœ˜Jšœžœ˜Jšœ žœ˜J˜Jšžœžœžœ˜(Jšœ-˜-Jšœ žœ˜šœžœ˜*šœžœ žœžœ˜*Jšœ žœ˜Jšžœ˜ J˜—Jšœ˜—Jšžœžœ žœžœ˜Jšœ˜Jšœžœ˜8Jšœ  ˜J˜—š Ÿœžœ žœžœžœžœ˜;Lšœžœ˜!Lšœ-˜-Lšœ1™1Lšœ/˜/Lšœ'˜'Lšœžœžœ˜Lšœ˜L˜—šŸœžœžœ žœžœžœžœ˜?Jšœžœ˜9Jšœ žœ˜Jšœ žœ˜Jšœžœžœ˜.Jšœžœ˜Jšœ˜J˜Jšžœž œ˜(Jšœ-˜-Jšœ žœ˜šœžœ˜*šœžœ žœžœ˜*Jšœ žœ˜Jšžœ˜ J˜—Jšœ˜—Jšžœžœ žœžœ˜Jšœ?˜?šžœ žœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ!˜!JšœH™HJ˜—Jšœ ˜J˜—šŸœžœžœ žœžœžœžœ˜?Jšœc™cJšœ˜Jšœ&˜&Jšœ˜—J˜™ Mšœ™—šŸ œžœ˜&Lšœžœ ˜$Lšœ žœ&˜5Lšœ&˜&Lšžœžœžœ<˜^M˜—šŸœžœ˜*Lšœžœ ˜$Lšœ žœ&˜5Lšœ(˜(Lšžœžœžœ<˜^M˜—šŸ œžœ˜'Lšœžœ ˜$Lšœ<˜Jšœ˜Jšœ˜Jšœ žœžœ-˜AJšœ[™[Jšœžœ˜ JšœP˜PJšœ ˜ Jšœ8˜8JšœVžœ˜^JšœR˜RJšœ%˜%Jšœ4˜4Jšœ ˜—J˜Mšœ ™ šŸœžœžœ žœžœžœžœ˜HMšœ˜LšœΟuœ ˜Lšœ’œ ˜Lšœ˜Lšœ žœžœ˜MšœL˜LLšœ žœžœ˜+L˜šžœ ž˜Lšœ’œ’œ;˜_Lšœ’œ’œ?˜dLšžœžœ˜—MšœD’œ’œ˜jM˜—L™Lšœ™šŸœžœžœ žœžœžœžœ˜ALšœW˜WLš‘™šžœržœžœž˜ˆLšœ0˜0Lšžœ˜—Lš‘I™IJšœ5‘œ˜:šžœržœžœž˜ˆJšœ$‘ œ% ˜eLš œžœžœHžœ ‘œ#˜Lšœ3 ˜JJšžœ˜—Lš‘™Lšœmžœ žœžœ˜›M˜M˜—šŸœžœžœ žœžœžœžœ˜BLšœO‘œ˜Wšžœržœžœž˜ˆLšœF˜F—Lšžœ˜Lšœtžœ žœžœ˜’M˜M˜M˜—šŸ œžœžœ žœžœžœžœ˜DLšœ3˜3Lšœ-˜-Lšœ'˜'LšœR˜RšžœOžœ žœž˜fLšœ5žœ˜MLšœ0˜0Lšžœ˜Lš‘(™(—Lšœ5‘œ  ˜[šžœržœžœž˜ˆLšœ‘ œ˜?Lšœžœžœ ˜"Lšœt˜tLšœ2˜2Lšžœ˜—Lšœsžœ žœžœ˜‘M˜M˜—šŸ œžœžœ žœžœžœžœ˜ELšœO‘œ˜Tšžœržœžœž˜ˆLšœF˜F—Lšžœ˜Lšœtžœ žœžœ˜’M˜M˜—šŸ œžœžœ žœžœžœžœ˜DLšœ1˜1LšœB˜BLšœX ˜mLšœlžœ žœžœ˜šL˜L˜—šŸ œžœžœ žœžœžœžœ˜Dšžœ%žœ˜-Lšœ"˜"Lšœ8 ™HLšœ6 ™PLšœpžœ žœžœ˜žL˜—L˜L™—šŸœžœžœ žœžœžœžœ˜LM˜M˜—L™Lšœ™šŸœžœžœ žœžœžœžœ˜JLšœ0˜0Lšœ)˜)Lšœnžœ žœžœ˜J˜—J˜šŸœžœžœ žœžœžœžœ˜JJšœ?˜?Jšœ˜J˜—šŸœžœžœ žœžœžœžœ˜HJšœ™Jšœ=˜=Jšœ ˜J˜—šŸœžœžœ žœžœžœžœ˜JJšœ?˜?Jšœ ˜—J˜šŸœžœžœ žœžœžœžœ˜@Jšœ˜Jšœ[™[Jšœ5˜5Jšœ˜—šŸ œžœžœ žœžœžœžœ˜DJšœ™Jšœ=˜=Jšœ˜J˜—šŸ œžœžœ žœžœžœžœ˜EL™ΔLšœ2˜2Lšœ˜Lš œ žœžœžœžœ˜5Lšœžœ˜ Lšœ!žœ˜)Lšœ ’œ ˜Lšœ˜Lšœ˜Lšœ(˜(Lšœ˜Lšœ:˜:L˜Lšœ4˜4Lšœ4˜4šžœž˜!Lšœ"˜"Lšœ"˜"L˜Lšœ9˜9Lš‘%˜%Lšœ œ;žœ#˜vL˜šžœ žœžœ˜LšœM˜ML˜—šžœ˜L˜Lšœ#’œ˜)LšœP˜PL˜—Lšžœ˜—Lšœz˜zLšœ ˜L˜—šŸœžœžœ žœžœžœžœ˜ILšœ6˜6L˜—šŸœžœžœ žœžœžœžœ˜ILšœžœžœ-˜9Lšœ9˜9L˜—J˜šŸ œžœžœ žœžœžœžœ˜ELšœ)˜)Lšœ,˜,Jšœ$˜$Jšœ0˜0Jšœ,˜,Jšœ-˜-Jšžœ2˜8L˜L˜—Jšžœ˜J˜—…—}b­2