File: SVViewerInputImplA.mesa
Last edited by Bier on January 27, 1987 4:16:33 pm PST
Copyright © 1984 by Xerox Corporation. All rights reserved.
Contents: Procedures for responding to button clicks made in a solidviewer.
DIRECTORY
BasicObject3d, CoordSys, SVScene, 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, SVScene, 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 {
Self is a viewer picture.
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];
Convert to camera coordinates.
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] = {
Depending on the mode of the skitter, we either create a hook, a floater, or nothing.
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] = {
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.
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;
Will draw the new Jack (if any) into the given viewer.
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] = {
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.
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] = {
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.
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;
Will draw the new Jack (if any) into the given viewer.
planeSel ← SVSelections.CreatePlaneSelection[coincident, viewerToolData];
SVSelections.PushPlane[planeSel];
ComplementSkitter[];
SVSelections.KillSkitter[viewerToolData.editToolData];
SVViewerUser.Painter[DrawLatestPlane, viewerToolData];
};
SkitterMakesSourceIndirect: PROC [viewerToolData: ViewerToolData] = {
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.
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] = {
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.
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] = {
Like SkitterMakesSource, except that we don't make any Jacks. Instead, we make a source selection on the skitterAssembly.
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] = {
Like SkitterMakesTarget, except that we don't make any Jacks for surface skitters. Instead, we make a target selection on the skitterAssembly.
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] = {
Like SkitterMakesPlane, except that we don't make any Jacks for surface skitters. Instead, we make a plane selection on the skitterAssembly.
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] = {
Move the distinguished source to the distinguished target.
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];
There may be more than one new scene, but for now we'll just repaint the last one.
};
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] = {
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.
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] ← SVScene.FindAssemblyFromName[moveeOriginal.name, oldScene];
IF moveeParent = NIL THEN moveeParent ← moveeOriginal;
If moveeOriginal is the sceneAssembly, then use the sceneAssembly as the new parent as well.
[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 ← SVScene.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];
There may be more than one new scene, but for now we'll just repaint the last one.
};
CopyRotate: PROC [] = {
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.
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] ← SVScene.FindAssemblyFromName[moveeOriginal.name, scene];
deltaDegrees ← 360/numberOfCopiesReal;
FOR i: NAT IN [1..numberOfCopies-1] DO
realI ← i;
degrees ← i*deltaDegrees;
copy ← SVScene.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];
There may be more than one new scene, but for now we'll just repaint the last one.
}; -- end of CopyRotate
CopyToAllTargetsTree: PROC [viewerToolData: ViewerToolData] = {
Just like CopyToAllTargets except that we always use the parent of the target as the parent of each copy (good for making tree structures).
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] ← SVScene.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 ← SVScene.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];
There may be more than one new scene, but for now we'll just repaint the last one.
};
ParentAndPosition: PRIVATE PROC [moveeSel, targetSel: Selection, newScene: Scene] RETURNS [parent: Assembly, relativeMat: Matrix4by4] = {
target: Assembly;
SELECT targetSel.referentType FROM
hook => {
[target, parent] ← SVScene.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] ← SVScene.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] = {
Returns an angle evenly distributed in [0..360).
randomNat: NAT ← Random.ChooseInt[NIL, 0, 9999];
degrees ← (randomNat/10000.0)*360.0;
};
RandomScalar: PRIVATE PROC [min, max: REAL] RETURNS [scalar: REAL] = {
Returns a scalar evenly distributed in [min..max).
randomNat: NAT ← Random.ChooseInt[NIL, 0, 9999];
scalar ← (randomNat/10000.0)*(max-min)+min;
};
CopyRandomToAllTargets: PUBLIC PROC [viewerToolData: ViewerToolData] = {
Just like CopyToAllTargets except that a random rotation and scaling is applied to each copy with respect to the dock coordsys.
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] ← SVScene.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 ← SVScene.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];
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];
};
ExtendCurrent: PUBLIC PROC [viewerToolData: ViewerToolData] = TRUSTED {
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.
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 {
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.
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] ← SVScene.FindAssemblyFromName[realAssembly.name, scene];
IF assembly # realAssembly THEN ERROR;
IF parent#NIL THEN SVSelections.UpdateSkitter[parent, prim, viewerToolData];
};
SetTool: PUBLIC PROC = TRUSTED {
The current movee selection assembly is now a tool. It will appear as a simple rectangle and ray traces as a simple rectangle.
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;
SVScene.AddOrResizeToolToAssembly[planeAssem, scene];
SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene];
}; -- end of SetTool
ResetTool: PUBLIC PROC = TRUSTED {
The current movee selection assembly is now a non-tool. It will once again appear as its regular shape.
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 {
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.
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
SVScene.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];
Indicate the currently selected plane in the message window.
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];
4 => SVError.Append[Rope.Cat["All planes 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
SVScene.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;
4 => Who knows.
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.