File: SVStretchImpl.mesa
Last edited by: Eric Bier on May 23, 1985 3:29:34 pm PDT
Copyright © 1984 by Xerox Corporation. All rights reserved.
Contents: Interactive solidviews operations like dragging and stretching objects.
DIRECTORY
CastRays,
CoordSys,
CSG,
DisplayList3d,
Graphics,
Matrix3d,
SV2d,
SV3d,
SVEditUser,
SVError,
SVInterfaceTypes,
SVModelTypes,
SVRayTypes,
SVSceneTypes,
SVSelections,
SVStretch,
SVTransforms,
SVVector3d,
SVViewerUser;
SVStretchImpl: CEDAR PROGRAM
IMPORTS CastRays, CoordSys, CSG, DisplayList3d, Matrix3d, SVEditUser, SVError, SVSelections, SVTransforms, SVVector3d, SVViewerUser
EXPORTS SVStretch =
BEGIN
Assembly: TYPE = SVSceneTypes.Assembly;
Camera: TYPE = SVModelTypes.Camera;
Classification: TYPE = SVRayTypes.Classification;
EditToolData: TYPE = SVEditUser.EditToolData;
Matrix4by4: TYPE = SV3d.Matrix4by4;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
Primitive: TYPE = SVRayTypes.Primitive;
Ray: TYPE = SVRayTypes.Ray;
Scene: TYPE = SVSceneTypes.Scene;
Selection: TYPE = SVInterfaceTypes.Selection;
ToolData: TYPE = SVSceneTypes.ToolData;
Vector: TYPE = SV3d.Vector;
ViewerToolData: TYPE = SVInterfaceTypes.ViewerToolData;
First cast a ray to grab hold of a primitive.
viewerToolData.tree ← DisplayListToTree.AssemblyToTree[viewerToolData.scene.assembly, viewerToolData.scene, camera];
[] ← Preprocess3d.PreprocessForInteraction[viewerToolData.tree, camera];
class ← CastRays.SingleRay2[cameraPoint, viewerToolData.tree, camera];
[surfacePtInWorld, worldNormal] ← CastRays.FirstSurfacePointAndNormal[class, viewerToolData.camera, cameraPoint];
[assembly, primitive] ← CastRays.FirstAssemblyAndPrimitive[class];
IF success THEN {
worldWRTCamera ← Matrix3d.Inverse[CoordSys.FindInTermsOfWorld[camera.coordSys]];
surfacePtInCamera ← Matrix3d.Update[worldWRTCamera, surfacePtInWorld];
viewerToolData.dragAssembly ← assembly;
viewerToolData.dragPlaneDepth ← surfacePtInCamera[3];
SVTransforms.TellAboutParent[assembly.coordSys];
originInCamera ← Matrix3d.OriginOfMatrix[assembly.coordSys.wrtCamera];
viewerToolData.dragCameraVector ← SVVector3d.Sub[originInCamera, surfacePtInCamera];
SVViewerUser.Painter[DoDrawBoundBox, viewerToolData];
};
StartDragAux: PRIVATE PROC [viewerToolData: ViewerToolData] RETURNS [drageeSel: Selection, planeAssem: Assembly, success: BOOL] = TRUSTED {
scene: Scene ← viewerToolData.scene;
success ← TRUE;
drageeSel ← SVSelections.TopMovee[];
IF drageeSel = NIL THEN {
viewerToolData.dragAssembly ← NIL;
SVError.Append["Please select a source to drag.", TRUE, TRUE];
SVError.Blink[];
success ← FALSE;
RETURN;
};
viewerToolData.dragAssembly ← drageeSel.coincident;
planeAssem ← SVSelections.TopPlaneCoincident[];
viewerToolData.dragTarget ← planeAssem;
IF planeAssem = NIL THEN {
SVError.Append["Please select a dragging plane.", TRUE, TRUE];
SVError.Blink[];
success ← FALSE;
RETURN;
};
Make sure the target has a working toolData.
DisplayList3d.AddOrResizeToolToAssembly[planeAssem, scene];
};
DoDrawCoordFrame: PROC [dc: Graphics.Context] = TRUSTED {
oldMode: Graphics.PaintMode;
oldMode ← Graphics.SetPaintMode[dc, invert];
SVDraw3d.DrawCoordSys[dc, dragee.coordSys.wrtCamera, camera];
[] ← Graphics.SetPaintMode[dc, oldMode];
};
StartCameraDrag: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Drag the source assembly. The origin of this assembly defines a plane parallel to the plane of the screen. We compute this plane. We cast a single ray at this plane and compute the current displacement between the assembly origin and this point. As we drag, we maintain this displacement.
editToolData: EditToolData ← viewerToolData.editToolData;
camera: Camera ← viewerToolData.camera;
scene: Scene ← viewerToolData.scene;
originCamera, hitPointCAMERA: Point3d;
dragee: Assembly;
drageeSel: Selection;
parallel, success: BOOL;
DoEraseSelection: PROC [dc: Graphics.Context] = TRUSTED {
SVSelections.ComplementSelectionDC[dc, drageeSel, viewerToolData];
};
success ← TRUE;
drageeSel ← SVSelections.TopMovee[];
IF drageeSel = NIL THEN RETURN;
dragee ← drageeSel.coincident;
IF dragee = NIL THEN {
viewerToolData.dragAssembly ← NIL;
SVError.Append["Please select a source to drag.", TRUE, TRUE];
SVError.Blink[];
success ← FALSE;
RETURN;
};
viewerToolData.dragAssembly ← dragee;
IF NOT success THEN RETURN;
Find the origin of assembly in terms of camera.
originCamera ← Matrix3d.OriginOfMatrix[CoordSys.FindInTermsOfCamera[dragee.coordSys, camera.coordSys]];
Compute the dragging plane.
viewerToolData.dragPlaneDepth ← originCamera[3];
Cast a ray at the target plane. Returns result in CAMERA coordinates.
[hitPointCAMERA, parallel] ← RayMeetsCameraPlane[cameraPoint, viewerToolData.dragPlaneDepth, camera];
IF parallel THEN {
SVError.Append["StartCameraDrag: Dragging plane is parallel to ray.", TRUE, TRUE];
SVError.Blink[];
viewerToolData.dragTarget ← NIL;
RETURN;
};
Compute in CAMERA the displacement from hitPoint to origin.
viewerToolData.dragCameraVector ← SVVector3d.Sub[originCamera, hitPointCAMERA];
Draw a coordinate frame at the current spot (as a form of highlighting).
SVViewerUser.Painter[DoEraseSelection, viewerToolData];
};
StartDrag: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Drag the source assembly. The origin of this assembly defines a plane parallel to the plane of target. We compute this plane. We cast a single ray at this plane and compute the current displacement between the assembly origin and this point. As we drag, we maintain this displacement.
editToolData: EditToolData ← viewerToolData.editToolData;
camera: Camera ← viewerToolData.camera;
originCamera, hitPointCAMERA, originTarget: Point3d;
plane: NAT;
drageeSel: Selection;
dragee, planeAssem: Assembly;
parallel, success: BOOL;
DoEraseSelection: PROC [dc: Graphics.Context] = TRUSTED {
SVSelections.ComplementSelectionDC[dc, drageeSel, viewerToolData];
};
[drageeSel, planeAssem, success] ← StartDragAux[viewerToolData];
IF NOT success THEN RETURN;
dragee ← drageeSel.coincident;
Find the origin of assembly in terms of target.
originCamera ← Matrix3d.OriginOfMatrix[dragee.coordSys.wrtCamera];
originTarget ← CoordSys.FromCSToCS[originCamera, camera.coordSys, planeAssem.coordSys];
Compute the dragging plane.
[viewerToolData.dragPlaneDepth, plane] ← DepthFromTarget[planeAssem, originTarget];
Cast a ray at the target plane. Returns result in CAMERA coordinates.
[hitPointCAMERA, parallel] ← RayMeetsTargetPlane[cameraPoint, planeAssem, viewerToolData.dragPlaneDepth, plane, camera];
IF parallel THEN {
SVError.Append["StartDrag: Dragging plane is parallel to ray.", TRUE, TRUE];
SVError.Blink[];
viewerToolData.dragTarget ← NIL;
RETURN;
};
Compute in CAMERA the displacement from hitPoint to origin.
viewerToolData.dragCameraVector ← SVVector3d.Sub[originCamera, hitPointCAMERA];
Draw a coordinate frame at the current spot (as a form of highlighting).
SVViewerUser.Painter[DoEraseSelection, viewerToolData];
}; -- end of StartDrag
DepthFromTarget: PRIVATE PROC [target: Assembly, targetPt: Point3d] RETURNS [depth: REAL, plane: NAT] = {
toolData: ToolData;
toolData ← NARROW[target.toolMasterObject.mainBody];
IF toolData.plane > 3 THEN depth ← targetPt[3]
ELSE depth ← targetPt[toolData.plane];
plane ← toolData.plane;
};
RayMeetsTargetPlane: PRIVATE PROC [cameraPoint: Point2d, planeA: Assembly, depth: REAL, plane: NAT, camera: Camera] RETURNS [planePtCamera: Point3d, parallel: BOOL] = TRUSTED {
targetPlanePt is in CAMERA coords.
rayWorld: Ray;
worldCamera: Matrix4by4;
planePtWorld: Point3d;
rayWorldCSG.GetRayFromPool[];
CSG.StuffWorldRayFromCamera[rayWorld, cameraPoint, camera];
[planePtWorld, parallel] ← CastRays.RayMeetsPlaneOfCoordSystem[planeA.coordSys, rayWorld, plane, depth];
worldCamera ← CoordSys.FindAInTermsOfB[camera.coordSys.parent, camera.coordSys];
planePtCamera ← Matrix3d.Update[worldCamera, planePtWorld];
CSG.ReturnRayToPool[rayWorld];
};
RayMeetsCameraPlane: PRIVATE PROC [cameraPoint: Point2d, depth: REAL, camera: Camera] RETURNS [planePtCamera: Point3d, parallel: BOOL] = TRUSTED {
rayWorld: Ray;
worldCamera: Matrix4by4;
planePtWorld: Point3d;
rayWorldCSG.GetRayFromPool[];
CSG.StuffWorldRayFromCamera[rayWorld, cameraPoint, camera];
[planePtWorld, parallel] ← CastRays.RayMeetsPlaneOfCoordSystem[camera.coordSys, rayWorld, 3, depth];
worldCamera ← CoordSys.FindAInTermsOfB[camera.coordSys.parent, camera.coordSys];
planePtCamera ← Matrix3d.Update[worldCamera, planePtWorld];
CSG.ReturnRayToPool[rayWorld];
};
SetDrag: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Cast a ray at the dragging plane. Move the dragee so as to maintain the displacement between the dragee origin and the ray tracing point.
camera: Camera ← viewerToolData.camera;
scene: Scene ← viewerToolData.scene;
hitPointCAMERA, newOriginPoint: Point3d;
dragee, target: Assembly;
toolData: ToolData;
parallel: BOOL;
DoDrawAssembly: PROC [dc: Graphics.Context] = TRUSTED {
SVViewerUser.DrawAssemblyXOR[dc, viewerToolData, dragee];
};
dragee ← viewerToolData.dragAssembly;
IF dragee = NIL THEN RETURN;
target ← viewerToolData.dragTarget;
IF target = NIL THEN RETURN;
toolDataNARROW[target.toolMasterObject.mainBody];
IF toolData = NIL THEN {
SVError.Append["Dragging plane is not defined", TRUE, TRUE];
SVError.Blink[];
RETURN;
};
Cast a ray at the dragging plane.
[hitPointCAMERA, parallel] ← RayMeetsTargetPlane[cameraPoint, viewerToolData.dragTarget, viewerToolData.dragPlaneDepth, toolData.plane, camera];
IF parallel THEN {
SVError.Append["SetDrag: Dragging plane is parallel to ray.", TRUE, TRUE];
SVError.Blink[];
RETURN;
};
newOriginPoint ← SVVector3d.Add[hitPointCAMERA, viewerToolData.dragCameraVector];
Erase the old assembly coordsys, and body.
SVViewerUser.Painter[DoDrawAssembly, viewerToolData];
Place the assembly's coordinate systems at this new point.
SVTransforms.Abut[dragee.coordSys, camera.coordSys];
SVTransforms.Translate[dragee.coordSys, camera.coordSys, newOriginPoint[1], newOriginPoint[2], newOriginPoint[3]];
SVTransforms.TellAboutParent[dragee.coordSys];
Draw a coordinate frame and assembly at the new spot.
SVViewerUser.Painter[DoDrawAssembly, viewerToolData];
Update the ray tracing tree for this node.
To be implemented.
}; -- end of SetDrag
Cast a ray at the dragging plane.
newRay ← CSG.GetRayFromPool[];
CSG.StuffCameraRay[newRay, cameraPoint, camera];
[cameraWallPoint, parallel] ← CastRays.RayMeetsPlaneOfCoordSystem[newRay, camera.coordSys, 3, viewerToolData.dragPlaneDepth];
CSG.ReturnRayToPool[newRay];
newOriginPoint ← SVVector3d.Add[cameraWallPoint, viewerToolData.dragCameraVector];
IF parallel THEN ERROR;
SetCameraDrag: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Cast a ray at the dragging plane. Move the dragee so as to maintain the displacement between the dragee origin and the ray tracing point.
camera: Camera ← viewerToolData.camera;
scene: Scene ← viewerToolData.scene;
hitPointCAMERA, newOriginPoint: Point3d;
dragee: Assembly;
parallel: BOOL;
DoDrawAssembly: PROC [dc: Graphics.Context] = TRUSTED {
SVViewerUser.DrawAssemblyXOR[dc, viewerToolData, dragee];
};
dragee ← viewerToolData.dragAssembly;
IF dragee = NIL THEN RETURN;
Cast a ray at the dragging plane.
[hitPointCAMERA, parallel] ← RayMeetsCameraPlane[cameraPoint, viewerToolData.dragPlaneDepth, camera];
IF parallel THEN {
SVError.Append["SetCameraDrag: Dragging plane is parallel to ray.", TRUE, TRUE];
SVError.Blink[];
RETURN;
};
newOriginPoint ← SVVector3d.Add[hitPointCAMERA, viewerToolData.dragCameraVector];
Erase the old assembly, coordsys and body.
SVViewerUser.Painter[DoDrawAssembly, viewerToolData];
Place the assembly's coordinate systems at this new point.
SVTransforms.Abut[dragee.coordSys, camera.coordSys];
SVTransforms.Translate[dragee.coordSys, camera.coordSys, newOriginPoint[1], newOriginPoint[2], newOriginPoint[3]];
SVTransforms.TellAboutParent[dragee.coordSys];
Draw a coordinate frame at the new spot.
SVViewerUser.Painter[DoDrawAssembly, viewerToolData];
Update the ray tracing tree for this node.
To be implemented.
};
EndDrag: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = {
editToolData: EditToolData ← NARROW[viewerToolData.editToolData];
camera: Camera ← viewerToolData.camera;
scene: Scene ← viewerToolData.scene;
drageeSel: Selection;
assembly: Assembly ← NARROW[viewerToolData.dragAssembly];
DoDrawAssembly: PROC [dc: Graphics.Context] = TRUSTED {
SVViewerUser.DrawAssemblyXOR[dc, viewerToolData, assembly];
};
DoRedrawSelection: PROC [dc: Graphics.Context] = TRUSTED {
SVSelections.ComplementSelectionDC[dc, drageeSel, viewerToolData];
};
assembly ← NARROW[viewerToolData.dragAssembly];
IF assembly = NIL THEN RETURN;
drageeSel ← SVSelections.TopMovee[];
SetDrag[viewerToolData, cameraPoint];
SVViewerUser.Painter[DoDrawAssembly, viewerToolData];
SVViewerUser.Painter[DoRedrawSelection, viewerToolData];
Redraw the scene and show that it has been edited.
SVEditUser.SceneNewVersion[viewerToolData];
SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene];
};
EndCameraDrag: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = {
editToolData: EditToolData ← NARROW[viewerToolData.editToolData];
camera: Camera ← viewerToolData.camera;
scene: Scene ← viewerToolData.scene;
drageeSel: Selection;
assembly: Assembly;
DoDrawAssembly: PROC [dc: Graphics.Context] = TRUSTED {
SVViewerUser.DrawAssemblyXOR[dc, viewerToolData, assembly];
};
DoRedrawSelection: PROC [dc: Graphics.Context] = TRUSTED {
SVSelections.ComplementSelectionDC[dc, drageeSel, viewerToolData];
};
assembly ← NARROW[viewerToolData.dragAssembly];
IF assembly = NIL THEN RETURN;
drageeSel ← SVSelections.TopMovee[];
SetCameraDrag[viewerToolData, cameraPoint];
SVViewerUser.Painter[DoDrawAssembly, viewerToolData];
SVViewerUser.Painter[DoRedrawSelection, viewerToolData];
Redraw the scene and show that it has been edited.
SVEditUser.SceneNewVersion[viewerToolData];
SVEditUser.PaintSceneAllViewers[SVViewerUser.EraseAndDrawSceneEtc, editToolData, scene];
};
END.