DIRECTORY BasicObject3d, CoordSys, DisplayList3d, Imager, Matrix3d, Random, Rope, SV2d, SV3d, SVEditUser, SVError, SVInputMonitor, SVInterfaceTypes, SVModelTypes, SVRayTypes, SVSceneTypes, SVSelections, SVTransforms, SVViewer, SVViewerInput, SVViewerTools, SVViewerUser, TIPUser, ViewerClasses; SVViewerInputImplA: PROGRAM IMPORTS CoordSys, DisplayList3d, Matrix3d, Random, Rope, SVEditUser, SVError, SVInputMonitor, SVSelections, SVTransforms, SVViewer, SVViewerInput, SVViewerTools, SVViewerUser EXPORTS SVViewerInput = BEGIN Artwork: TYPE = SVModelTypes.Artwork; ArtworkToolData: TYPE = SVInterfaceTypes.ArtworkToolData; Assembly: TYPE = SVSceneTypes.Assembly; AssemblyList: TYPE = SVSceneTypes.AssemblyList; BoundBox: TYPE = SVModelTypes.BoundBox; BoundSphere: TYPE = SVModelTypes.BoundSphere; Camera: TYPE = SVModelTypes.Camera; Classification: TYPE = SVRayTypes.Classification; Color: TYPE = Imager.Color; CoordSystem: TYPE = SVModelTypes.CoordSystem; CSGTree: TYPE = SVRayTypes.CSGTree; CylinderRec: TYPE = BasicObject3d.CylinderRec; EditToolData: TYPE = SVInterfaceTypes.EditToolData; FileCamera: TYPE = SVSceneTypes.FileCamera; FrameBox: TYPE = SVModelTypes.FrameBox; MasterObject: TYPE = SVSceneTypes.MasterObject; Matrix4by4: TYPE = SV3d.Matrix4by4; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; Primitive: TYPE = SVRayTypes.Primitive; Ray: TYPE = SVRayTypes.Ray; Scene: TYPE = SVSceneTypes.Scene; SearchDepth: TYPE = SVInterfaceTypes.SearchDepth; Selection: TYPE = SVInterfaceTypes.Selection; SelectionGenerator: TYPE = SVInterfaceTypes.SelectionGenerator; Shape: TYPE = SVSceneTypes.Shape; SkitterMode: TYPE = SVInterfaceTypes.SkitterMode; ToolData: TYPE = SVSceneTypes.ToolData; TrigLine: TYPE = SV2d.TrigLine; Vector: TYPE = SV3d.Vector; ViewerToolData: TYPE = SVInterfaceTypes.ViewerToolData; InputNotify: PUBLIC SAFE PROCEDURE [self: ViewerClasses.Viewer, input: LIST OF REF ANY] = TRUSTED { viewerToolData: ViewerToolData _ NARROW[self.data]; IF ISTYPE[input.first, TIPUser.TIPScreenCoords] THEN { controlPoint: Point2d; camera: Camera _ viewerToolData.camera; mousePlace: TIPUser.TIPScreenCoords _ NARROW[input.first]; controlPoint[1] _ mousePlace.mouseX; -- this is a fix to float conversion controlPoint[2] _ mousePlace.mouseY; controlPoint _ CoordSys.ScreenToCamera[controlPoint, camera.screenCS]; IF ISTYPE[input.rest.first, ATOM] THEN SELECT input.rest.first FROM $StartDrag, $SetDrag, $EndDrag => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartCameraDrag, $SetCameraDrag, $EndCameraDrag => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $SingleRay => SVViewerUser.SingleRay[viewerToolData, controlPoint]; $FrameUpLeft, $FrameDownRightMove, $FrameDownRightEnd, $DeleteFrame => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartSkitter, $DuringSkitter, $EndSkitter => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartBackSkitter, $DuringBackSkitter, $EndBackSkitter => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartTopLevelSkitter, $DuringTopLevelSkitter, $EndTopLevelSkitter => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartCoordSkitter, $DuringCoordSkitter, $EndCoordSkitter => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartTightRope, $DuringTightRope, $EndTightRope => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $StartWallWalk, $DuringWallWalk, $EndWallWalk => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $Paint => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $ExtendSkitter => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; $ExtendCoordSkitter => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData]; ENDCASE => { SVError.Append["Solid viewer: Unknown mouse action.", TRUE, TRUE]; SVError.Blink[]; } } -- is a Mousepoint ELSE { -- not a mouse-point dependent operation SELECT input.first FROM $ExtendCurrent => ExtendCurrent[viewerToolData]; $ReloadTipTable => SVViewer.ReloadTipTable[viewerToolData]; $RestartProcess => SVInputMonitor.Restart[]; $ClearAllSelections => SVSelections.KillSkitterAndSelections[viewerToolData.editToolData]; $DeleteSources => DeleteSources[viewerToolData]; $NoOp => {}; $AddCylinder => SVViewerInput.AddCylinder[]; $Skewer => SVViewerInput.Skewer[]; $MoveUntilTouch => SVViewerInput.MoveUntilTouch[]; $ArrowShoot => SVViewerInput.ArrowShoot[]; $DropPerpendicular => DropPerpendicular[]; $VolleyShoot => {}; $JackPivotX => SVViewerInput.JackPivotX[viewerToolData, 90]; $JackPivotY => SVViewerInput.JackPivotY[viewerToolData, 90]; $JackPivotZ => SVViewerInput.JackPivotZ[viewerToolData, 90]; $JackPivotXInverse => SVViewerInput.JackPivotX[viewerToolData, -90]; $JackPivotYInverse => SVViewerInput.JackPivotY[viewerToolData, -90]; $JackPivotZInverse => SVViewerInput.JackPivotZ[viewerToolData, -90]; $SourcePivotX => SVViewerInput.SourcePivotX[viewerToolData, 90]; $SourcePivotY => SVViewerInput.SourcePivotY[viewerToolData, 90]; $SourcePivotZ => SVViewerInput.SourcePivotZ[viewerToolData, 90]; $SourcePivotXInverse => SVViewerInput.SourcePivotX[viewerToolData, -90]; $SourcePivotYInverse => SVViewerInput.SourcePivotY[viewerToolData, -90]; $SourcePivotZInverse => SVViewerInput.SourcePivotZ[viewerToolData, -90]; $SourceRotX => SourceRotX[10]; $SourceRotY => SourceRotY[10]; $SourceRotZ => SourceRotZ[10]; $SourceRotXInverse => SourceRotX[-10]; $SourceRotYInverse => SourceRotY[-10]; $SourceRotZInverse => SourceRotZ[-10]; $CopyRandomToAllTargets => CopyRandomToAllTargets[viewerToolData]; $CopyToAllTargets => CopyToAllTargets[viewerToolData]; $CopyToAllTargetsTree => CopyToAllTargetsTree[viewerToolData]; $MoveToTarget => MoveToTarget[viewerToolData]; $CopyRotate => CopyRotate[]; $CycleTool => CycleTool[]; $SetTool => SetTool[]; $ResetTool => ResetTool[]; $ResetSpheres => ResetSpheres[viewerToolData]; $SetBoundingSpheres => SetBoundingSpheres[viewerToolData]; $SetSphereShadows => SetSphereShadows[viewerToolData]; $SkitterMakes => SkitterMakes[]; $SkitterMakesSource => SkitterMakesSource[viewerToolData]; $SkitterMakesTarget => SkitterMakesTarget[viewerToolData]; $SkitterMakesPlane => SkitterMakesPlane[viewerToolData]; $SkitterMakesSourceIndirect => SkitterMakesSourceIndirect[viewerToolData]; $SkitterMakesTargetIndirect => SkitterMakesTargetIndirect[viewerToolData]; $SkitterMakesSourceIndirectOnly => SkitterMakesSourceIndirectOnly[viewerToolData]; $SkitterMakesTargetIndirectOnly => SkitterMakesTargetIndirectOnly[viewerToolData]; $SkitterMakesPlaneIndirectOnly => SkitterMakesPlaneIndirectOnly[viewerToolData]; ENDCASE => { SVError.Append["Solid viewer: Unknown command.", TRUE, TRUE]; SVError.Blink[]; } }; }; -- end of InputNotify DeleteSources: PROC [viewerToolData: ViewerToolData] = { scene: Scene _ viewerToolData.scene; SVEditUser.DeleteSources[viewerToolData.editToolData]; }; SetBoundingSpheres: PROC [viewerToolData: ViewerToolData] = { camera: Camera _ viewerToolData.camera; camera.useBoundBoxes _ FALSE; }; SetSphereShadows: PROC [viewerToolData: ViewerToolData] = { camera: Camera _ viewerToolData.camera; camera.useBoundSpheresForShadows _ TRUE; }; ResetSpheres: PROC [viewerToolData: ViewerToolData] = { camera: Camera _ viewerToolData.camera; camera.useBoundBoxes _ TRUE; camera.useBoundSpheresForShadows _ FALSE; }; ComplementSkitter: PUBLIC PROC [] = { viewerToolData: ViewerToolData; camera: Camera; DoComplementSkitter: PROC [dc: Imager.Context] = { SVSelections.ComplementSkitter[dc, camera]; }; IF NOT SVSelections.IsAliveSkitter[] THEN RETURN; [----,----,viewerToolData] _ SVSelections.GetSkitterData[]; IF viewerToolData = NIL THEN ERROR; camera _ viewerToolData.camera; SVViewerUser.Painter[DoComplementSkitter, viewerToolData]; }; SkitterMakes: PUBLIC PROC [] = { viewerToolData: ViewerToolData; [----,----,viewerToolData] _ SVSelections.GetSkitterData[]; [] _ SkitterMakesAux[viewerToolData]; ComplementSkitter[]; -- erase the skitter SVSelections.KillSkitter[viewerToolData.editToolData]; }; SkitterMakesAux: PROC [viewerToolData: ViewerToolData] RETURNS [coincident: Assembly] = { scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; SELECT skitterMode FROM surface => { coincident _ SVSelections.AddHookFromSkitter[]; SVViewerUser.ComplementAssembly[viewerToolData, coincident]; -- Draw the hook }; tightrope => { coincident _ SVSelections.AddFloaterFromSkitter[]; SVViewerUser.ComplementAssembly[viewerToolData, coincident]; -- Draw the floater }; coordframe => { [coincident,----,----] _ SVSelections.GetSkitterData[]; }; ENDCASE => ERROR; }; SkitterMakesSource: PROC [viewerToolData: ViewerToolData] = { skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; coincident: Assembly; movee: Selection; DrawLatestMovee: PROC [dc: Imager.Context] = { SVSelections.ComplementReferentDC[dc, movee, viewerToolData]; -- erase the Jack if any SVSelections.ComplementSelectionDC[dc, movee, viewerToolData]; -- draw selection instead. }; coincident _ SkitterMakesAux[viewerToolData]; IF coincident = NIL THEN RETURN; SELECT skitterMode FROM surface => { skitterAssem: Assembly; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; movee _ SVSelections.CreateHookMovee[coincident, skitterAssem, viewerToolData]; SVSelections.PushMovee[movee]; }; tightrope => { movee _ SVSelections.CreateCoordSysMovee[coincident, viewerToolData]; SVSelections.PushMovee[movee]; }; coordframe => { movee _ SVSelections.CreateCoordSysMovee[coincident, viewerToolData]; SVSelections.PushMovee[movee]; }; ENDCASE => ERROR; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestMovee, viewerToolData]; }; SkitterMakesTarget: PROC [viewerToolData: ViewerToolData] = { skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; coincident: Assembly; target: Selection; DrawLatestTarget: PROC [dc: Imager.Context] = { SVSelections.ComplementReferentDC[dc, target, viewerToolData]; SVSelections.ComplementSelectionDC[dc, target, viewerToolData]; }; coincident _ SkitterMakesAux[viewerToolData]; -- create and draw the jack IF coincident = NIL THEN RETURN; SELECT skitterMode FROM surface => { skitterAssem: Assembly; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; target _ SVSelections.CreateHookTarget[coincident, skitterAssem, viewerToolData]; SVSelections.PushTarget[target]; }; tightrope => { target _ SVSelections.CreateCoordSysTarget[coincident, viewerToolData]; SVSelections.PushTarget[target]; }; coordframe => { target _ SVSelections.CreateCoordSysTarget[coincident, viewerToolData]; SVSelections.PushTarget[target]; }; ENDCASE => ERROR; ComplementSkitter[]; -- erase the skitter SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestTarget, viewerToolData]; }; SkitterMakesPlane: PROC [viewerToolData: ViewerToolData] = { scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; coincident: Assembly; planeSel: Selection; DrawLatestPlane: PROC [dc: Imager.Context] = { SVSelections.ComplementReferentDC[dc, planeSel, viewerToolData]; -- erase the Jack if any SVSelections.ComplementSelectionDC[dc, planeSel, viewerToolData]; -- draw selection instead. }; coincident _ SkitterMakesAux[viewerToolData]; IF coincident = NIL THEN RETURN; planeSel _ SVSelections.CreatePlaneSelection[coincident, viewerToolData]; SVSelections.PushPlane[planeSel]; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestPlane, viewerToolData]; }; SkitterMakesSourceIndirect: PROC [viewerToolData: ViewerToolData] = { skitterAssem: Assembly; skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; indirect: Assembly; sourceSel: Selection; camera: Camera _ viewerToolData.camera; scene: Scene _ viewerToolData.scene; found: BOOL; DrawLatestMovee: PROC [dc: Imager.Context] = { SVSelections.ComplementSelectionDC[dc, sourceSel, viewerToolData]; -- draw selection. }; IF skitterMode # coordframe THEN { SVError.Append["Can only select indirect with a coordframe skitter.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; IF skitterAssem.sittingOn = NIL THEN { SVError.Append[Rope.Concat[skitterAssem.name, " is not sitting on anything."], TRUE, TRUE]; SVError.Blink[]; RETURN; }; [indirect, ----, found] _ SVEditUser.FindAssemblyFromName[skitterAssem.sittingOn, scene]; IF NOT found THEN RETURN; sourceSel _ SVSelections.CreateHookMovee[skitterAssem, indirect, viewerToolData]; SVSelections.PushMovee[sourceSel]; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestMovee, viewerToolData]; }; SkitterMakesTargetIndirect: PROC [viewerToolData: ViewerToolData] = { skitterAssem: Assembly; skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; indirect: Assembly; targetSel: Selection; camera: Camera _ viewerToolData.camera; scene: Scene _ viewerToolData.scene; found: BOOL; DrawLatestTarget: PROC [dc: Imager.Context] = { SVSelections.ComplementSelectionDC[dc, targetSel, viewerToolData]; -- draw selection. }; IF skitterMode # coordframe THEN { SVError.Append["Can only select indirect with a coordframe skitter.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; IF skitterAssem.sittingOn = NIL THEN { SVError.Append[Rope.Concat[skitterAssem.name, " is not sitting on anything."], TRUE, TRUE]; SVError.Blink[]; RETURN; }; [indirect, ----, found] _ SVEditUser.FindAssemblyFromName[skitterAssem.sittingOn, scene]; IF NOT found THEN RETURN; targetSel _ SVSelections.CreateHookTarget[skitterAssem, indirect, viewerToolData]; SVSelections.PushTarget[targetSel]; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestTarget, viewerToolData]; }; SkitterMakesSourceIndirectOnly: PROC [viewerToolData: ViewerToolData] = { skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; coincident: Assembly; movee: Selection; DrawLatestMovee: PROC [dc: Imager.Context] = { SVSelections.ComplementReferentDC[dc, movee, viewerToolData]; -- erase the Jack if any SVSelections.ComplementSelectionDC[dc, movee, viewerToolData]; -- draw selection instead. }; SELECT skitterMode FROM surface => { skitterAssem: Assembly; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; movee _ SVSelections.CreateCoordSysMovee[skitterAssem, viewerToolData]; SVSelections.PushMovee[movee]; }; tightrope => { coincident _ SVSelections.AddFloaterFromSkitter[]; SVViewerUser.ComplementAssembly[viewerToolData, coincident]; -- Draw the floater movee _ SVSelections.CreateCoordSysMovee[coincident, viewerToolData]; SVSelections.PushMovee[movee]; }; coordframe => { [coincident,----,----] _ SVSelections.GetSkitterData[]; movee _ SVSelections.CreateCoordSysMovee[coincident, viewerToolData]; SVSelections.PushMovee[movee]; }; ENDCASE => ERROR; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestMovee, viewerToolData]; }; SkitterMakesTargetIndirectOnly: PROC [viewerToolData: ViewerToolData] = { skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; coincident: Assembly; targetSel: Selection; DrawLatestMovee: PROC [dc: Imager.Context] = { SVSelections.ComplementReferentDC[dc, targetSel, viewerToolData]; -- erase the Jack if any SVSelections.ComplementSelectionDC[dc, targetSel, viewerToolData]; -- draw selection instead. }; SELECT skitterMode FROM surface => { skitterAssem: Assembly; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; targetSel _ SVSelections.CreateCoordSysTarget[skitterAssem, viewerToolData]; SVSelections.PushTarget[targetSel]; }; tightrope => { coincident _ SVSelections.AddFloaterFromSkitter[]; SVViewerUser.ComplementAssembly[viewerToolData, coincident]; -- Draw the floater targetSel _ SVSelections.CreateCoordSysTarget[coincident, viewerToolData]; SVSelections.PushTarget[targetSel]; }; coordframe => { [coincident,----,----] _ SVSelections.GetSkitterData[]; targetSel _ SVSelections.CreateCoordSysTarget[coincident, viewerToolData]; SVSelections.PushTarget[targetSel]; }; ENDCASE => ERROR; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestMovee, viewerToolData]; }; SkitterMakesPlaneIndirectOnly: PROC [viewerToolData: ViewerToolData] = { skitterMode: SkitterMode _ SVSelections.GetModeSkitter[]; scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; coincident: Assembly; planeSel: Selection; DrawLatestPlane: PROC [dc: Imager.Context] = { SVSelections.ComplementReferentDC[dc, planeSel, viewerToolData]; -- erase the Jack if any SVSelections.ComplementSelectionDC[dc, planeSel, viewerToolData]; -- draw selection instead. }; SELECT skitterMode FROM surface => { skitterAssem: Assembly; [skitterAssem,----,----] _ SVSelections.GetSkitterData[]; planeSel _ SVSelections.CreatePlaneSelection[skitterAssem, viewerToolData]; SVSelections.PushPlane[planeSel]; }; tightrope => { coincident _ SVSelections.AddFloaterFromSkitter[]; SVViewerUser.ComplementAssembly[viewerToolData, coincident]; -- Draw the floater planeSel _ SVSelections.CreatePlaneSelection[coincident, viewerToolData]; SVSelections.PushPlane[planeSel]; }; coordframe => { [coincident,----,----] _ SVSelections.GetSkitterData[]; planeSel _ SVSelections.CreatePlaneSelection[coincident, viewerToolData]; SVSelections.PushPlane[planeSel]; }; ENDCASE => ERROR; ComplementSkitter[]; SVSelections.KillSkitter[viewerToolData.editToolData]; SVViewerUser.Painter[DrawLatestPlane, viewerToolData]; }; MoveToTarget: PROC [viewerToolData: ViewerToolData] = { source: Assembly; dockCS: CoordSystem; moveeSel, targetSel: Selection; relativeMat: Matrix4by4; editToolData: EditToolData _ viewerToolData.editToolData; scene: Scene _ viewerToolData.scene; moveeSel _ SVSelections.TopMovee[]; IF moveeSel = NIL THEN RETURN; targetSel _ SVSelections.TopTarget[]; IF targetSel = NIL THEN RETURN; IF moveeSel.viewerToolData # targetSel.viewerToolData THEN { SVError.Append["Move from viewer to viewer not yet implemented.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; dockCS _ targetSel.coincident.coordSys; [----, relativeMat] _ ParentAndPosition[moveeSel, targetSel, scene]; SELECT moveeSel.referentType FROM hook => { source _ moveeSel.indirect; SVTransforms.TugTransfLeaveTug[source.coordSys, moveeSel.coincident.coordSys, dockCS, relativeMat]; }; coordSys => { source _ moveeSel.coincident; SVTransforms.AbsTransf[source.coordSys, dockCS, relativeMat]; }; ENDCASE => ERROR; SVSelections.ClearMoveeStack[editToolData]; SVSelections.ClearTargetStack[editToolData]; SVEditUser.SceneNewVersion[viewerToolData]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene]; }; SourceRotX: PROC [degrees: REAL] = { sourceSel: Selection; scene: Scene; viewerToolData: ViewerToolData; editToolData: EditToolData; jack, indirect: Assembly; sourceSel _ SVSelections.TopMovee[]; IF sourceSel = NIL THEN RETURN; viewerToolData _ sourceSel.viewerToolData; editToolData _ viewerToolData.editToolData; SELECT sourceSel.referentType FROM hook => { jack _ sourceSel.coincident; indirect _ sourceSel.indirect; }; coordSys => { jack _ sourceSel.coincident; indirect _ sourceSel.coincident; }; ENDCASE => ERROR; scene _ viewerToolData.scene; SVEditUser.PaintAssemblyAllViewers[SVViewerUser.DrawAssemblyXOR, editToolData, scene, indirect]; SVTransforms.XRotate[indirect.coordSys, jack.coordSys, degrees, TRUE]; SVEditUser.PaintAssemblyAllViewers[SVViewerUser.DrawAssemblyXOR, editToolData, scene, indirect]; }; SourceRotY: PROC [degrees: REAL] = { sourceSel: Selection; scene: Scene; viewerToolData: ViewerToolData; editToolData: EditToolData; jack, indirect: Assembly; sourceSel _ SVSelections.TopMovee[]; IF sourceSel = NIL THEN RETURN; viewerToolData _ sourceSel.viewerToolData; editToolData _ viewerToolData.editToolData; SELECT sourceSel.referentType FROM hook => { jack _ sourceSel.coincident; indirect _ sourceSel.indirect; }; coordSys => { jack _ sourceSel.coincident; indirect _ sourceSel.coincident; }; ENDCASE => ERROR; scene _ viewerToolData.scene; SVEditUser.PaintAssemblyAllViewers[SVViewerUser.DrawAssemblyXOR, editToolData, scene, indirect]; SVTransforms.YRotate[indirect.coordSys, jack.coordSys, degrees, TRUE]; SVEditUser.PaintAssemblyAllViewers[SVViewerUser.DrawAssemblyXOR, editToolData, scene, indirect]; }; SourceRotZ: PROC [degrees: REAL] = { sourceSel: Selection; scene: Scene; viewerToolData: ViewerToolData; editToolData: EditToolData; jack, indirect: Assembly; sourceSel _ SVSelections.TopMovee[]; IF sourceSel = NIL THEN RETURN; viewerToolData _ sourceSel.viewerToolData; editToolData _ viewerToolData.editToolData; SELECT sourceSel.referentType FROM hook => { jack _ sourceSel.coincident; indirect _ sourceSel.indirect; }; coordSys => { jack _ sourceSel.coincident; indirect _ sourceSel.coincident; }; ENDCASE => ERROR; scene _ viewerToolData.scene; SVEditUser.PaintAssemblyAllViewers[SVViewerUser.DrawAssemblyXOR, editToolData, scene, indirect]; SVTransforms.ZRotate[indirect.coordSys, jack.coordSys, degrees, TRUE]; SVEditUser.PaintAssemblyAllViewers[SVViewerUser.DrawAssemblyXOR, editToolData, scene, indirect]; }; CopyToAllTargets: PROC [viewerToolData: ViewerToolData] = { moveeCopy, moveeOriginal, parent, moveeParent: Assembly; moveeSel: Selection; editToolData: EditToolData _ viewerToolData.editToolData; oldScene, newScene: Scene; dockCS: CoordSystem; relativeMat: Matrix4by4; targets: SelectionGenerator; targetsExist: BOOL; moveeSel _ SVSelections.TopMovee[]; IF moveeSel = NIL THEN RETURN; oldScene _ moveeSel.viewerToolData.scene; SELECT moveeSel.referentType FROM hook => moveeOriginal _ moveeSel.indirect; coordSys => moveeOriginal _ moveeSel.coincident; ENDCASE => ERROR; [----, moveeParent] _ DisplayList3d.FindAssemblyFromName[moveeOriginal.name, oldScene]; IF moveeParent = NIL THEN moveeParent _ moveeOriginal; [targets, targetsExist] _ SVSelections.GetSelectionGenerator[target]; IF NOT targetsExist THEN { SVError.Append["Please make some targets to copy to.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; FOR targetSel: Selection _ SVSelections.NextSelection[targets], SVSelections.NextSelection[targets] UNTIL targetSel = NIL DO newScene _ targetSel.viewerToolData.scene; IF newScene = oldScene THEN { parent _ moveeParent; [----, relativeMat] _ ParentAndPosition[moveeSel, targetSel, newScene]; } ELSE [parent, relativeMat] _ ParentAndPosition[moveeSel, targetSel, newScene]; dockCS _ targetSel.coincident.coordSys; moveeCopy _ DisplayList3d.CopyAssemblyAndSonsUniqueNames[moveeOriginal, oldScene, newScene, parent]; SVTransforms.Normalize[moveeCopy.coordSys, moveeOriginal.coordSys]; SELECT moveeSel.referentType FROM hook => SVTransforms.TugTransfLeaveTug[moveeCopy.coordSys, moveeSel.coincident.coordSys, dockCS, relativeMat]; coordSys => SVTransforms.AbsTransf[moveeCopy.coordSys, dockCS, relativeMat]; ENDCASE => ERROR; ENDLOOP; SVSelections.ClearTargetStack[editToolData]; SVEditUser.SceneNewVersion[viewerToolData]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, newScene]; }; CopyRotate: PROC [] = { copy, moveeOriginal, moveeParent: Assembly; sourceSel, planeSel: Selection; viewerToolData: ViewerToolData; planeAssem: Assembly; sourceCS, planeCS: CoordSystem; editToolData: EditToolData; scene: Scene; numberOfCopies: NAT; numberOfCopiesReal: REAL; degrees, deltaDegrees, realI: REAL; toolData: ToolData; sourceSel _ SVSelections.PopMovee[]; IF sourceSel = NIL THEN RETURN; planeSel _ SVSelections.PopPlane[]; IF planeSel = NIL THEN RETURN; planeAssem _ planeSel.coincident; IF planeAssem.toolMasterObject = NIL OR planeAssem.toolMasterObject.mainBody = NIL THEN ERROR; toolData _ NARROW[planeAssem.toolMasterObject.mainBody]; IF sourceSel.viewerToolData # planeSel.viewerToolData THEN { SVError.Append["Can't copy rotate between viewers.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; viewerToolData _ sourceSel.viewerToolData; scene _ viewerToolData.scene; editToolData _ viewerToolData.editToolData; sourceCS _ sourceSel.coincident.coordSys; planeCS _ planeSel.coincident.coordSys; numberOfCopies _ SVViewerTools.GetNat[viewerToolData.textSection.xyz]; numberOfCopiesReal _ numberOfCopies; SELECT sourceSel.referentType FROM hook => moveeOriginal _ sourceSel.indirect; coordSys => moveeOriginal _ sourceSel.coincident; ENDCASE => ERROR; [----, moveeParent] _ DisplayList3d.FindAssemblyFromName[moveeOriginal.name, scene]; deltaDegrees _ 360/numberOfCopiesReal; FOR i: NAT IN [1..numberOfCopies-1] DO realI _ i; degrees _ i*deltaDegrees; copy _ DisplayList3d.CopyAssemblyAndSonsUniqueNames[moveeOriginal, scene, scene, moveeParent]; SVTransforms.Normalize[copy.coordSys, moveeOriginal.coordSys]; SELECT toolData.plane FROM 1 => SVTransforms.XRotate[copy.coordSys, planeCS, degrees]; 2 => SVTransforms.YRotate[copy.coordSys, planeCS, degrees]; 3, 4 => SVTransforms.ZRotate[copy.coordSys, planeCS, degrees]; ENDCASE => ERROR; ENDLOOP; SVEditUser.SceneNewVersion[viewerToolData]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene]; }; -- end of CopyRotate CopyToAllTargetsTree: PROC [viewerToolData: ViewerToolData] = { moveeCopy, moveeOriginal, parent, moveeParent: Assembly; moveeSel: Selection; editToolData: EditToolData _ viewerToolData.editToolData; oldScene, newScene: Scene; dockCS: CoordSystem; relativeMat: Matrix4by4; targets: SelectionGenerator; targetsExist: BOOL; moveeSel _ SVSelections.TopMovee[]; IF moveeSel = NIL THEN RETURN; oldScene _ moveeSel.viewerToolData.scene; SELECT moveeSel.referentType FROM hook => moveeOriginal _ moveeSel.indirect; coordSys => moveeOriginal _ moveeSel.coincident; ENDCASE => ERROR; [----, moveeParent] _ DisplayList3d.FindAssemblyFromName[moveeOriginal.name, oldScene]; [targets, targetsExist] _ SVSelections.GetSelectionGenerator[target]; IF NOT targetsExist THEN { SVError.Append["Please make some targets to copy to.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; FOR targetSel: Selection _ SVSelections.NextSelection[targets], SVSelections.NextSelection[targets] UNTIL targetSel = NIL DO newScene _ targetSel.viewerToolData.scene; [parent, relativeMat] _ ParentAndPosition[moveeSel, targetSel, newScene]; dockCS _ targetSel.coincident.coordSys; moveeCopy _ DisplayList3d.CopyAssemblyAndSonsUniqueNames[moveeOriginal, oldScene, newScene, parent]; SVTransforms.Normalize[moveeCopy.coordSys, moveeOriginal.coordSys]; SELECT moveeSel.referentType FROM hook => SVTransforms.TugTransfLeaveTug[moveeCopy.coordSys, moveeSel.coincident.coordSys, dockCS, relativeMat]; coordSys => SVTransforms.AbsTransf[moveeCopy.coordSys, dockCS, relativeMat]; ENDCASE => ERROR; ENDLOOP; SVSelections.ClearTargetStack[editToolData]; SVEditUser.SceneNewVersion[viewerToolData]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, newScene]; }; ParentAndPosition: PRIVATE PROC [moveeSel, targetSel: Selection, newScene: Scene] RETURNS [parent: Assembly, relativeMat: Matrix4by4] = { target: Assembly; SELECT targetSel.referentType FROM hook => { [target, parent] _ DisplayList3d.FindAssemblyFromName[targetSel.indirect.name, newScene]; IF target # targetSel.indirect THEN ERROR; SELECT moveeSel.referentType FROM hook => relativeMat _ Matrix3d.MakeRotateYMat[180]; -- mushroom placement coordSys => relativeMat _ Matrix3d.Identity[]; -- antenae placement ENDCASE => ERROR; }; coordSys => { [target, parent] _ DisplayList3d.FindAssemblyFromName[targetSel.coincident.name, newScene]; IF Rope.Equal[targetSel.coincident.name, "sceneAssembly", TRUE] THEN parent _ targetSel.coincident; IF target # targetSel.coincident THEN ERROR; SELECT moveeSel.referentType FROM hook => relativeMat _ Matrix3d.Identity[]; -- will think about this some more. coordSys => relativeMat _ Matrix3d.Identity[]; ENDCASE => ERROR; }; ENDCASE => ERROR; }; RandomAngle: PRIVATE PROC [] RETURNS [degrees: REAL] = { randomNat: NAT _ Random.ChooseInt[NIL, 0, 9999]; degrees _ (randomNat/10000.0)*360.0; }; RandomScalar: PRIVATE PROC [min, max: REAL] RETURNS [scalar: REAL] = { randomNat: NAT _ Random.ChooseInt[NIL, 0, 9999]; scalar _ (randomNat/10000.0)*(max-min)+min; }; CopyRandomToAllTargets: PUBLIC PROC [viewerToolData: ViewerToolData] = { moveeCopy, moveeOriginal, parent, moveeParent: Assembly; moveeSel: Selection; editToolData: EditToolData _ viewerToolData.editToolData; oldScene, newScene: Scene; dockCS: CoordSystem; relativeMat: Matrix4by4; targets: SelectionGenerator; targetsExist: BOOL; min, max, randomScalar, randomDegrees: REAL; moveeSel _ SVSelections.TopMovee[]; IF moveeSel = NIL THEN RETURN; oldScene _ moveeSel.viewerToolData.scene; [min, max, ----] _ SVViewerTools.GetThreeReals[editToolData.transformSection.scaleXYZ]; SELECT moveeSel.referentType FROM hook => moveeOriginal _ moveeSel.indirect; coordSys => moveeOriginal _ moveeSel.coincident; ENDCASE => ERROR; [----, moveeParent] _ DisplayList3d.FindAssemblyFromName[moveeOriginal.name, oldScene]; [targets, targetsExist] _ SVSelections.GetSelectionGenerator[target]; IF NOT targetsExist THEN { SVError.Append["Please make some targets to copy to.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; FOR targetSel: Selection _ SVSelections.NextSelection[targets], SVSelections.NextSelection[targets] UNTIL targetSel = NIL DO newScene _ targetSel.viewerToolData.scene; IF newScene = oldScene THEN { parent _ moveeParent; [----, relativeMat] _ ParentAndPosition[moveeSel, targetSel, newScene]; } ELSE [parent, relativeMat] _ ParentAndPosition[moveeSel, targetSel, newScene]; dockCS _ targetSel.coincident.coordSys; moveeCopy _ DisplayList3d.CopyAssemblyAndSonsUniqueNames[moveeOriginal, oldScene, newScene, parent]; SELECT moveeSel.referentType FROM hook => SVTransforms.TugTransfLeaveTug[moveeCopy.coordSys, moveeSel.coincident.coordSys, dockCS, relativeMat]; coordSys => SVTransforms.AbsTransf[moveeCopy.coordSys, dockCS, relativeMat]; ENDCASE => ERROR; randomDegrees _ RandomAngle[]; randomScalar _ RandomScalar[min, max]; SVTransforms.ZRotate[moveeCopy.coordSys, dockCS, randomDegrees]; SVTransforms.ScaleEven[moveeCopy, dockCS, randomScalar]; ENDLOOP; SVSelections.ClearTargetStack[editToolData]; SVEditUser.SceneNewVersion[viewerToolData]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, newScene]; }; ExtendCurrent: PUBLIC PROC [viewerToolData: ViewerToolData] = TRUSTED { editToolData: EditToolData; scene: Scene; assembly, parent: Assembly; prim: Primitive; assemblyName: Rope.ROPE; success: BOOL; editToolData _ viewerToolData.editToolData; scene _ viewerToolData.scene; [assembly, prim, viewerToolData] _ SVSelections.GetSkitterData[]; IF assembly = NIL THEN RETURN; assemblyName _ assembly.name; [assembly, parent, success] _ SVEditUser.FindAssemblyFromName[assemblyName, scene]; IF NOT success THEN { SVError.Append[Rope.Cat["ExtendCurrent: assembly ", assemblyName, " not found."], TRUE, TRUE]; SVError.Blink[]; RETURN; }; SVSelections.UpdateSkitter[parent, prim, viewerToolData]; }; ParentOfSkitter: PROC [] = TRUSTED { viewerToolData: ViewerToolData; editToolData: EditToolData; scene: Scene; assembly, realAssembly, parent: Assembly; prim: Primitive; [realAssembly, prim, viewerToolData] _ SVSelections.GetSkitterData[]; editToolData _ viewerToolData.editToolData; scene _ viewerToolData.scene; IF realAssembly = NIL THEN RETURN; [assembly, parent] _ DisplayList3d.FindAssemblyFromName[realAssembly.name, scene]; IF assembly # realAssembly THEN ERROR; IF parent#NIL THEN SVSelections.UpdateSkitter[parent, prim, viewerToolData]; }; SetTool: PUBLIC PROC = TRUSTED { editToolData: EditToolData; viewerToolData: ViewerToolData; planeAssem: Assembly; planeSel: Selection; scene: Scene; planeSel _ SVSelections.TopPlane[]; IF planeSel = NIL THEN { SVError.Append["SetTool: Make a plane selection first", TRUE, TRUE]; SVError.Blink[]; RETURN; }; planeAssem _ planeSel.coincident; viewerToolData _ planeSel.viewerToolData; scene _ viewerToolData.scene; editToolData _ NARROW[viewerToolData.editToolData]; planeAssem.showAs _ tool; DisplayList3d.AddOrResizeToolToAssembly[planeAssem, scene]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene]; }; -- end of SetTool ResetTool: PUBLIC PROC = TRUSTED { editToolData: EditToolData; viewerToolData: ViewerToolData; planeAssem: Assembly; planeSel: Selection; scene: Scene; planeSel _ SVSelections.TopPlane[]; IF planeSel = NIL THEN { SVError.Append["ResetTool: Make a plane selection first", TRUE, TRUE]; SVError.Blink[]; RETURN; }; planeAssem _ planeSel.coincident; viewerToolData _ planeSel.viewerToolData; scene _ viewerToolData.scene; editToolData _ NARROW[viewerToolData.editToolData]; planeAssem.showAs _ normal; SVEditUser.SceneNewVersion[viewerToolData]; SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene]; }; CycleTool: PUBLIC PROC = TRUSTED { editToolData: EditToolData; viewerToolData: ViewerToolData; planeAssem: Assembly; planeSel: Selection; scene: Scene; camera: Camera; toolData: ToolData; DrawNewPlane: PROC [dc: Imager.Context] = { SVSelections.ComplementSelectionDC[dc, planeSel, viewerToolData]; }; planeSel _ SVSelections.TopPlane[]; IF planeSel = NIL THEN { SVError.Append["CycleTool: Make a plane selection first", TRUE, TRUE]; SVError.Blink[]; RETURN; }; planeAssem _ planeSel.coincident; viewerToolData _ planeSel.viewerToolData; camera _ viewerToolData.camera; scene _ viewerToolData.scene; editToolData _ NARROW[viewerToolData.editToolData]; IF planeAssem.toolMasterObject = NIL OR planeAssem.toolMasterObject.mainBody = NIL THEN DisplayList3d.AddOrResizeToolToAssembly[planeAssem, scene]; toolData _ NARROW[planeAssem.toolMasterObject.mainBody]; SVViewerUser.Painter[DrawNewPlane, viewerToolData]; toolData.plane _ IF toolData.plane = 3 THEN 1 ELSE toolData.plane + 1; SVViewerUser.Painter[DrawNewPlane, viewerToolData]; SELECT toolData.plane FROM 1 => SVError.Append[Rope.Cat["x = 0 plane of ", planeAssem.name, " now selected."], TRUE, TRUE]; 2 => SVError.Append[Rope.Cat["y = 0 plane of ", planeAssem.name, " now selected."], TRUE, TRUE]; 3 => SVError.Append[Rope.Cat["z = 0 plane of ", planeAssem.name, " now selected."], TRUE, TRUE]; ENDCASE => ERROR; IF planeAssem.showAs = tool OR planeAssem.showAs = both THEN SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene]; }; DropPerpendicular: PROC = TRUSTED { sourceSel, planeSel: Selection; toolData: ToolData; planeAssem: Assembly; scene: Scene; camera: Camera; viewerToolData: ViewerToolData; selectionMat, sourcePlane: Matrix4by4; interceptPlane, originPlane: Point3d; sourceSel _ SVSelections.TopMovee[]; IF sourceSel = NIL THEN RETURN; planeSel _ SVSelections.TopPlane[]; IF planeSel = NIL THEN RETURN; planeAssem _ planeSel.coincident; viewerToolData _ planeSel.viewerToolData; camera _ viewerToolData.camera; scene _ viewerToolData.scene; IF planeAssem.toolMasterObject = NIL OR planeAssem.toolMasterObject.mainBody = NIL THEN DisplayList3d.AddOrResizeToolToAssembly[planeAssem, scene]; toolData _ NARROW[planeAssem.toolMasterObject.mainBody]; sourcePlane _ CoordSys.FindAInTermsOfB[sourceSel.coincident.coordSys, planeSel.coincident.coordSys]; originPlane _ Matrix3d.OriginOfMatrix[sourcePlane]; interceptPlane _ originPlane; SELECT toolData.plane FROM 1 => interceptPlane[1] _ 0.0; 2 => interceptPlane[2] _ 0.0; 3 => interceptPlane[3] _ 0.0; ENDCASE => ERROR; SVViewerInput.ComplementSkitter[]; -- erase any old skitter selectionMat _ CoordSys.FindInTermsOfWorld[planeSel.coincident.coordSys]; selectionMat _ Matrix3d.LocalTranslate[selectionMat, interceptPlane[1], interceptPlane[2], interceptPlane[3]]; SVSelections.UpdateSkitter[NIL, NIL, viewerToolData]; SVSelections.PositionSkitter[[0,0], selectionMat]; -- update skitterWORLD SVSelections.SetModeSkitter[tightrope]; SVViewerInput.ComplementSkitter[]; -- draw new skitter SVViewerInput.SkitterMakes[]; -- sceneAssembly will be the parent of the new jack. }; END. nFile: SVViewerInputImplA.mesa Last edited by Bier on August 1, 1985 6:02:20 pm PDT Copyright c 1984 by Xerox Corporation. All rights reserved. Contents: Procedures for responding to button clicks made in a solidviewer. Self is a viewer picture. Convert to camera coordinates. Depending on the mode of the skitter, we either create a hook, a floater, or nothing. First do a SkitterMakes. Take the coordinate system of the resulting assembly and select it as a movee. This requires creating a new selection object, pointing it at the selected object, and adding the selection to the appropriate list. Will draw the new Jack (if any) into the given viewer. First do a SkitterMakes. Take the coordinate system of the resulting assembly and select it as a target. This requires creating a new selection object, pointing it at the selected object, and adding the selection to the appropriate list. The current skitter assembly should now become a plane selection. Plane selections draw themselves as a square aligned with the plane of the selected object. Will draw the new Jack (if any) into the given viewer. Like SkitterMakesSource, except that we expect the skitter mode to be "coordframe", and we don't make any Jacks. Instead, we look to see if the skitterAssembly is sitting on another assembly. If so, we create a hook movee selection. If any of these conditions fail, complain and do nothing. Like SkitterMakesTarget, except that we expect the skitter mode to be "coordframe", and we don't make any Jacks. Instead, we look to see if the skitterAssembly is sitting on another assembly. If so, we create a hook target selection. If any of these conditions fail, complain and do nothing. Like SkitterMakesSource, except that we don't make any Jacks. Instead, we make a source selection on the skitterAssembly. Like SkitterMakesTarget, except that we don't make any Jacks for surface skitters. Instead, we make a target selection on the skitterAssembly. Like SkitterMakesPlane, except that we don't make any Jacks for surface skitters. Instead, we make a plane selection on the skitterAssembly. Move the distinguished source to the distinguished target. There may be more than one new scene, but for now we'll just repaint the last one. Take the distinguished movee object. Make a copy at the exact same place for each target. Perform a TugRotX[180], etc. to make movee-copy tangent to target-referee at target. Each copy becomes attached to the parent of the target object. If moveeOriginal is the sceneAssembly, then use the sceneAssembly as the new parent as well. There may be more than one new scene, but for now we'll just repaint the last one. Copy the distinguished source to a set of positions in a circle whose center is the origin of the distinguished target and whose cicumference includes the origin of the source. There may be more than one new scene, but for now we'll just repaint the last one. Just like CopyToAllTargets except that we always use the parent of the target as the parent of each copy (good for making tree structures). There may be more than one new scene, but for now we'll just repaint the last one. Returns an angle evenly distributed in [0..360). Returns a scalar evenly distributed in [min..max). Just like CopyToAllTargets except that a random rotation and scaling is applied to each copy with respect to the dock coordsys. There may be more than one new scene, but for now we'll just repaint the last one. ComplementBoundBox: PUBLIC PROC [boundBox: BoundBox, viewerToolData: ViewerToolData] = TRUSTED { camera: Camera _ viewerToolData.camera; screen: CoordSystem _ camera.screenCS; DoComplementBoundBox: SAFE PROC [dc: Imager.Context] = TRUSTED { SVBoundBox.ComplementBoundBox[dc, boundBox, screen]; }; SVViewerUser.Painter[DoComplementBoundBox, viewerToolData]; }; Find parent of skitter.assembly if any. Set skitter.assembly to this value. Indicate the selection by changing the name in the "Current:" slot of the edittool. Find parent of skitter.assembly if any. Set skitter.assembly to this value. Indicate the selection by changing the name in the "Current:" slot of the edittool. The current movee selection assembly is now a tool. It will appear as a simple rectangle and ray traces as a simple rectangle. The current movee selection assembly is now a non-tool. It will once again appear as its regular shape. Cycle through the 3 planes of the tool. Change the appearance of the plane selection and output a description of the current plane, as feedback. Indicate the currently selected plane in the message window. 4 => SVError.Append[Rope.Cat["All planes of ", planeAssem.name, " now selected."], TRUE, TRUE]; 4 => Who knows. ส"บ˜Iheadšœ™Jšœ4™4Jšœ ฯmœ1™˜>Jšœ.˜.Jšœ˜J˜Jšœ˜Jšœ˜Jšœ˜J˜Jšœ.˜.Jšœ:˜:Jšœ6˜6J˜Jšœ ˜ Jšœ:˜:Jšœ:˜:Jšœ8˜8JšœJ˜JJšœJ˜JJšœR˜RJšœR˜RJšœP˜Pšžœ˜ Jšœ1žœžœ˜=Jšœ˜J˜—J˜—Jšœ ˜—Jšœ˜šŸ œžœ%˜8Jšœ$˜$Jšœ6˜6J˜J˜—šŸœžœ%˜=Jšœ'˜'Jšœžœ˜J˜—šŸœžœ%˜;Jšœ'˜'Jšœ#žœ˜(J˜—šŸ œžœ%˜7Jšœ'˜'Jšœžœ˜Jšœ#žœ˜)J˜—J˜šŸœžœžœ˜%Jšœ˜J˜šŸœžœ˜2Jšœ.˜.J˜—Jšžœžœžœžœ˜1Jšœ œ œ1˜;Jšžœžœžœžœ˜#Jšœ˜Jšœ:˜:J˜J˜—J˜šŸ œž œ˜ Jšœ˜J˜Jšœ*Ÿœ˜;Jšœ%˜%Jšœ)˜)Jšœ6˜6J˜J˜—šŸœžœ"žœ˜YJ™UJšœ$˜$Jšœ'˜'Jšœ9˜9Jšžœ ž˜šœ ˜ Jšœ/˜/JšœM˜MJ˜—šœ˜Jšœ2˜2JšœP˜PJ˜—šœ˜Jšœ  œ œ"˜7J˜—Jšžœžœ˜J˜J˜—J˜šŸœžœ%˜=Jšœ๎™๎Jšœ9˜9Jšœ$˜$Jšœ'˜'Jšœ˜J˜šŸœžœ˜.JšœV˜VJšœY˜YJ˜J˜—Jšœ-˜-šžœžœžœžœ˜ J™6—Jšžœ ž˜šœ ˜ J˜Jšœ œ œ"˜9JšœO˜OJšœ˜J˜—šœ˜JšœE˜EJšœ˜J˜—šœ˜JšœE˜EJšœ˜Jšœ˜—Jšžœžœ˜Jšœ˜Jšœ6˜6Jšœ6˜6J˜J˜—šŸœžœ%˜=Jšœ๏™๏Jšœ9˜9Jšœ$˜$Jšœ'˜'Jšœ˜J˜šŸœžœ˜/Jšœ>˜>Jšœ?˜?J˜J˜—Jšœ กœ-˜IJšžœžœžœžœ˜ Jšžœ ž˜šœ ˜ J˜Jšœ œ œ"˜9JšœQ˜QJšœ ˜ J˜—šœ˜JšœG˜GJšœ ˜ J˜—šœ˜JšœG˜GJšœ ˜ Jšœ˜—Jšžœžœ˜Jšœ)˜)Jšœ6˜6Jšœ7˜7J˜J˜—šŸœžœ%˜ ˜VJšœ? ˜YJ˜J˜—Jšžœ ž˜šœ ˜ J˜Jšœ œ œ"˜9Jšœกœ˜GJšœ˜J˜—šœ˜Jšœ2˜2Jšœ= ˜PJšœE˜EJšœ˜J˜—šœ˜Jšœ  œ œ"˜7JšœE˜EJšœ˜Jšœ˜—Jšžœžœ˜Jšœ˜Jšœ6˜6Jšœ6˜6J˜Jšœ™—šŸœžœ%˜IJšœ™Jšœ9˜9Jšœ$˜$Jšœ'˜'Jšœ˜J˜šŸœžœ˜.JšœB ˜ZJšœC ˜]J˜J˜—Jšžœ ž˜šœ ˜ J˜Jšœ œ œ"˜9Jšœกœ˜LJšœ#˜#J˜—šœ˜Jšœ2˜2Jšœ= ˜PJšœJ˜JJšœ#˜#J˜—šœ˜Jšœ  œ œ"˜7JšœJ˜JJšœ#˜#Jšœ˜—Jšžœžœ˜Jšœ˜Jšœ6˜6Jšœ6˜6J˜Jšœ™—šŸœžœ%˜HJšœ™Jšœ9˜9Jšœ$˜$Jšœ'˜'Jšœ˜J˜šŸœžœ˜.JšœA ˜YJšœB ˜\J˜J˜—Jšžœ ž˜šœ ˜ J˜Jšœ œ œ"˜9JšœŸœ˜KJšœ!˜!J˜—šœ˜Jšœ2˜2Jšœ= ˜PJšœŸœ˜IJšœ!˜!J˜—šœ˜Jšœ  œ œ"˜7JšœŸœ˜IJšœ!˜!Jšœ˜—Jšžœžœ˜Jšœ˜Jšœ6˜6Jšœ6˜6J˜Jšœ™—šŸ œžœ%˜7J™:Jšœ˜J˜J˜J˜Jšœ9˜9Jšœ$˜$J˜J˜#Jšžœ žœžœžœ˜J˜%Jšžœ žœžœžœ˜šžœ4žœ˜Jšžœž˜Jšœ;˜;Jšœกœ"˜;Jšœกœ"˜>Jšžœžœ˜—Jšžœ˜Jšœ+˜+šœX˜XJ™R—J˜J™—šŸœžœ%˜?J™‹Jšœ8˜8J˜Jšœ9˜9Jšœ˜J˜J˜J˜Jšœžœ˜J˜Jšกœ˜#Jšžœ žœžœžœ˜Jšœ)˜)J˜šžœž˜!Jšœก œ˜*Jšœ ก œ˜0Jšžœžœ˜J˜—Jšœก œE˜WJ˜JšœE˜Ešžœžœžœ˜Jšœ7žœžœ˜CJšœ˜Jšžœ˜J˜—šžœažœ žœž˜|Jšœ*˜*J˜šœกœก œ5˜IJ˜—Jšกœ!˜'J˜Jšœกœก)œ˜dJ˜Jšœ ก œ-˜CJšžœž˜!JšœกœH˜nJšœก œ*˜LJšžœžœ˜—Jšžœ˜Jšœ,˜,Jšœ+˜+šœ[˜[J™R—J˜J˜—˜J™—š Ÿœžœžœ3žœก œ˜‰Jšœ˜Jšžœž˜"šœ ˜ Jšœ กœJ˜YJšžœžœžœ˜*šžœž˜!Jšœก œ! ˜IJšœ ก œ ˜CJšžœžœ˜—J˜—šœ ˜ Jšœ กœL˜[Jšžœ8žœžœกœ˜cJšžœžœžœ˜,šžœž˜!Jšœก œ;˜NJšœ ก œ˜.Jšžœžœ˜—J˜—Jšžœžœ˜J˜J˜—š Ÿ œžœžœžœ žœ˜8J™0Jšœ žœ"˜0J˜$J˜J˜—š Ÿ œžœžœ žœžœ žœ˜FJ™2Jšœ žœ"˜0Jšœ+˜+J˜J˜—J˜J˜šŸœž œ%˜HJšœ™Jšœ8˜8J˜Jšœ9˜9Jšœ˜J˜J˜J˜Jšœžœ˜J˜,J˜Jšกœ˜#Jšžœ žœžœžœ˜Jšœ)˜)JšœW˜WJ˜šžœž˜!Jšœก œ˜*Jšœ ก œ˜0Jšžœžœ˜J˜—Jšœก œE˜WJ˜JšœE˜Ešžœžœžœ˜Jšœ7žœžœ˜CJšœ˜Jšžœ˜J˜—šžœažœ žœž˜|Jšœ*˜*J˜šžœžœ˜Jšกœ˜Jšœ œก œ5˜GJ˜—šžœกœก œ5˜NJ˜—Jšกœ!˜'J˜Jšœกœก)œ˜dJ˜Jšžœž˜!JšœกœH˜nJšœก œ*˜LJšžœžœ˜J˜JšœŸ œ˜JšœŸ œ ˜&Jšœ Ÿœกœ˜@Jšœ Ÿ œ กœ˜8J˜—šžœ˜J˜—Jšœ,˜,Jšœ+˜+šœ[˜[J™R—J˜J˜—šŸœžœžœ8žœ™`Jšœ'™'Jšœ&™&šŸœžœžœžœ™@Jšœ4™4Jšœ™—Jšœ;™;Jšœ™—J˜šŸ œžœžœ$žœ˜GJšœก™กJšœ˜Jšœ ˜ Jšœ˜J˜Jšœžœ˜Jšœ žœ˜J˜Jšœ+˜+Jšœ˜JšœA˜AJšžœ žœžœžœ˜Jšœ˜J˜JšœS˜Sšžœžœ žœ˜JšœRžœžœ˜^Jšœ˜Jšžœ˜J˜—Jšœ9˜9Jšœ˜J˜—šŸœžœžœ˜$Jšœก™กJ˜Jšœ˜Jšœ ˜ Jšœ)˜)J˜JšœE˜EJšœ+˜+Jšœ˜J˜Jšžœžœžœžœ˜"JšœR˜RJšžœžœžœ˜&Jšžœžœžœกœ˜LJšœ˜J˜—šŸœžœžœžœ˜ Jšœ™Jšœ˜Jšœ˜Jšœ˜J˜J˜ J˜J˜#šœžœžœ˜Jšœ8žœžœ˜DJšœ˜Jšžœ˜J˜—Jšœ!˜!Jšœ)˜)Jšœ˜Jšœžœ˜3J˜Jšœ˜Jšœ;˜;LšœX˜XJšœ˜J˜—šŸ œžœžœžœ˜"Jšœh™hJšœ˜Jšœ˜Jšœ˜J˜J˜ J˜J˜#šžœ žœžœ˜Jšœ:žœžœ˜FJšœ˜Jšžœ˜J˜—Jšœ!˜!Jšœ)˜)Jšœ˜Jšœžœ˜3J˜Jšก˜Lšœ+˜+LšœX˜XJšœ˜J˜—šŸ œžœžœžœ˜"J™‘Jšœ˜Jšœ˜Jšœ˜J˜J˜ J˜Jšœ˜˜+JšœA˜AJ˜—J˜J˜#šžœ žœžœ˜Jšœ:žœžœ˜FJšœ˜Jšžœ˜J˜—Jšœ!˜!Jšœ)˜)Jšœ˜Jšœ˜Jšœžœ˜3š žœžœžœ(žœž˜WLšœ;˜;—Lšœ žœ'˜8Lšœ3˜3Lšกะbkกขกขก˜Fšœ3˜3L™<—Lšžœกœž˜LšœTžœžœ˜`LšœTžœžœ˜`LšœTžœžœ˜`LšœSžœžœ™_Lšžœžœ˜šžœžœž˜