File: SVViewerInputImpl.mesa
Last edited by Bier on August 11, 1983 11:09 am
Contents: Procedures for responding to button clicks made in a solidviewer.
DIRECTORY
CastRays,
CoordSys,
CSG,
CSGGraphics,
DisplayList3d,
Graphics,
GraphicsColor,
Matrix3d,
Preprocess3d,
SV2d,
SVBoundBox,
SVEditUser,
SVInputMonitor,
SVVector3d,
SVViewerInput,
SVViewerUser,
TIPUser,
ViewerClasses;
SVViewerInputImpl: PROGRAM
IMPORTS CastRays, CoordSys, CSGGraphics, DisplayList3d, Graphics, Matrix3d, Preprocess3d, SVBoundBox, SVEditUser, SVInputMonitor, SVViewerUser, SVVector3d
EXPORTS SVViewerInput =
BEGIN
Assembly: TYPE = DisplayList3d.Assembly;
BoundBox: TYPE = SVBoundBox.BoundBox;
Camera: TYPE = CSGGraphics.Camera;
Classification: TYPE = CSG.Classification;
Color: TYPE = GraphicsColor.Color;
CoordSystem: TYPE = CoordSys.CoordSystem;
FileCamera: TYPE = DisplayList3d.FileCamera;
FrameBox: TYPE = CSGGraphics.FrameBox;
Matrix4by4: TYPE = Matrix3d.Matrix4by4;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = Matrix3d.Point3d;
Primitive: TYPE = CSG.Primitive;
Selection: TYPE = SVEditUser.Selection;
Vector: TYPE = SVVector3d.Vector;
ViewerToolData: TYPE = SVViewerUser.ViewerToolData;
ViewerPictureData: TYPE = SVViewerUser.ViewerPictureData;
InputNotify: PUBLIC SAFE PROCEDURE [self: ViewerClasses.Viewer, input: LIST OF REF ANY] = TRUSTED {
Self is a viewer picture.
IF ISTYPE[input.first, TIPUser.TIPScreenCoords] THEN {
controlPoint: Point2d;
viewerPictureData: ViewerPictureData ← NARROW[self.data];
viewerToolData: ViewerToolData ← viewerPictureData.viewerToolData;
camera: Camera ← viewerPictureData.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
$SingleRay => {
SVViewerUser.SingleRay[viewerToolData, controlPoint];
};
$FrameUpLeft => PositionUpLeft[viewerToolData, controlPoint];
$FrameDownRightMove => {
PositionDownRight[viewerToolData, controlPoint];
};
$FrameDownRightEnd => {
PositionDownRight[viewerToolData, controlPoint];
};
$DeleteFrame => DeleteFrame[viewerToolData];
$StartPrimarySelection => StartPrimarySelection[viewerToolData, controlPoint];
$StartSecondarySelection => StartSecondarySelection[viewerToolData, controlPoint];
$SetPrimarySelection => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData];
$EndPrimarySelection => {};
$SetSecondarySelection => SVInputMonitor.NewMotion[controlPoint, NARROW[input.rest.first], viewerToolData];
$EndSecondarySelection => EndSecondarySelection[viewerToolData, controlPoint];
ENDCASE;
}; -- is a Mousepoint
}; -- end of InputNotify
MakeAlignedMat: PRIVATE PROC [worldNormal: Vector, surfacePtInWorld: Point3d, cs: CoordSystem] RETURNS [mat: Matrix4by4] = TRUSTED {
Create a Matrix4by4 with origin at surfacePtInWorld whose z axis is parallel to worldNormal and whose x zxis is orthogonal to both worldNormal and the y axis of cs in WORLD coordinates. Assume that cs.wrtWorld is accurate
yAxisOfCS: Vector ← Matrix3d.YAxisOfMatrix[cs.wrtWorld];
xAxis: Vector;
IF SVVector3d.Parallel[yAxisOfCS, worldNormal] THEN xAxis ← Matrix3d.XAxisOfMatrix[cs.wrtWorld]
ELSE xAxis ← SVVector3d.CrossProduct[yAxisOfCS, worldNormal];
mat ← Matrix3d.MakeMatFromZandXAxis[worldNormal, xAxis, surfacePtInWorld];
};
StartPrimarySelection: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Compute the ray tracing tree for the current scene here so we don't have to recompute it each time the mouse position is sampled (SetPrimarySelection).
selectionMat: Matrix4by4;
surfacePtInWorld: Point3d;
worldNormal: Vector;
assembly: Assembly;
primitive: Primitive;
class: Classification;
selection, oldSelection: Selection;
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
viewerPictureData.tree ← DisplayList3d.SceneToTree[viewerPictureData.scene, viewerPictureData.camera];
[] ← Preprocess3d.Preprocess[viewerPictureData.tree, viewerPictureData.camera];
class ← CastRays.SingleRay2[cameraPoint, viewerPictureData.tree, viewerPictureData.scene.lightSources, viewerPictureData.camera];
[surfacePtInWorld, worldNormal] ← DisectClassification1[class, viewerPictureData.camera, cameraPoint];
[assembly, primitive] ← DisectClassification2[class, viewerPictureData.camera, cameraPoint];
IF assembly # NIL THEN {
selectionMat ← MakeAlignedMat[worldNormal, surfacePtInWorld, assembly.coordSys];
oldSelection ← SVEditUser.GetPrimarySelection[];
ComplementOldSelection[viewerToolData, oldSelection, GraphicsColor.black];
selection ← SVEditUser.SetPrimarySelection[cameraPoint, assembly, primitive, selectionMat, viewerToolData];
ComplementSelection[viewerToolData, selection, GraphicsColor.black]; -- draw new selection into complement mode
};
CastRays.ReturnClassToPool[class];
};
ComplementOldSelection: PROC [viewerToolData: ViewerToolData, selection: Selection, color: Color] = TRUSTED {
If selection is in this viewer then just complement it normally. If it is in another viewer, then have that viewer complement it. If there it is a null selection, forget it.
IF selection = NIL THEN RETURN; -- null selection
IF selection.assembly = NIL THEN RETURN; -- null selection
IF selection.viewerToolData = viewerToolData
THEN ComplementSelection[viewerToolData, selection, color]
ELSE ComplementSelection[selection.viewerToolData, selection, color];
};
DrawSelectionOpaque: PROC [viewerToolData: ViewerToolData, selection: Selection, color: Color] = TRUSTED {
DoDrawSelectionOpaque: SAFE PROC [dc: Graphics.Context] = TRUSTED {
[] ← Graphics.SetPaintMode[dc, opaque];
Graphics.SetColor[dc, color];
SVViewerUser.DrawOneCS[dc, viewerToolData, selection.coordSys];
};
CoordSys.TellAboutParent[selection.coordSys];
SVViewerUser.Painter[DoDrawSelectionOpaque, viewerToolData];
};
ComplementSelection: PROC [viewerToolData: ViewerToolData, selection: Selection, color: Color] = TRUSTED {
DoComplementSelection: SAFE PROC [dc: Graphics.Context] = TRUSTED {
[] ← Graphics.SetPaintMode[dc, invert];
Graphics.SetColor[dc, color];
SVViewerUser.DrawOneCS[dc, viewerToolData, selection.coordSys];
};
CoordSys.TellAboutParent[selection.coordSys];
SVViewerUser.Painter[DoComplementSelection, viewerToolData];
};
SetPrimarySelection: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Cast a ray into the scene from this point. If it hits anything, use the surface normal at that point to derive a coordinate system whose z axis is the parallel to the normal. Tell the editTool that a new selection has been made.
selection: Selection;
surfacePtInWorld: Point3d;
worldNormal: Vector;
assembly: Assembly;
primitive: Primitive;
selectionMat: Matrix4by4;
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
class: Classification ←
CastRays.SingleRay2[cameraPoint, viewerPictureData.tree,
viewerPictureData.scene.lightSources, viewerPictureData.camera];
[surfacePtInWorld, worldNormal] ←
DisectClassification1[class, viewerPictureData.camera, cameraPoint];
[assembly, primitive] ← DisectClassification2[class, viewerPictureData.camera, cameraPoint];
IF assembly # NIL THEN {
selectionMat ← MakeAlignedMat[worldNormal, surfacePtInWorld, assembly.coordSys];
selection ← SVEditUser.GetPrimarySelection[];
ComplementSelection[viewerToolData, selection, GraphicsColor.black];-- erase old one by complementing
selection ← SVEditUser.SetPrimarySelection[cameraPoint, assembly, primitive, selectionMat, viewerToolData];
ComplementSelection[viewerToolData, selection, GraphicsColor.black];-- paint new one by complementing
};
CastRays.ReturnClassToPool[class];
};
There are two Disect Classifications because Cedar can't handle a return record which both contains a pointer (assembly) and returns 6 REALS (long pointer-containing return record is unsafe)
DisectClassification1: PROC [class: Classification, camera: Camera, cameraPoint: Point2d] RETURNS [surfacePtInWorld: Point3d, worldNormal: Vector] = TRUSTED {
worldBasePt: Point3d;
primitive: Primitive;
primitiveNormal, worldDirection: Vector;
t: REAL;
IF class.count = 0 THEN RETURN;
t ← class.params[1];-- the parameter of the ray intersection
primitiveNormal ← class.normals[1];
primitive ← class.primitives[1];
worldNormal ← Matrix3d.UpdateVectorWithInverse[primitive.worldWRTPrim, primitiveNormal];
express the ray which was cast in world coordinates
worldBasePt ← Matrix3d.Update[camera.coordSys.mat,
[cameraPoint[1], cameraPoint[2], 0]];
worldDirection ← Matrix3d.UpdateVectorEvenScaling[camera.coordSys.mat, [cameraPoint[1], cameraPoint[2], -camera.focalLength]];
Use this ray to find the surface point in WORLD coordinates. This will be the origin of our coordinate system.
surfacePtInWorld[1] ← worldBasePt[1] + t*worldDirection[1];
surfacePtInWorld[2] ← worldBasePt[2] + t*worldDirection[2];
surfacePtInWorld[3] ← worldBasePt[3] + t*worldDirection[3];
}; -- end of DisectClassification1
DisectClassification2: PROC [class: Classification, camera: Camera, cameraPoint: Point2d] RETURNS [assembly: Assembly, primitive: Primitive] = TRUSTED {
IF class.count = 0 THEN RETURN[NIL, NIL];
primitive ← class.primitives[1];
assembly ← NARROW[primitive.assembly];
}; -- end of DisectClassification2
StartSecondarySelection: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Compute the ray tracing tree for the current scene here so we don't have to recompute it each time the mouse position is sampled (SetSecondarySelection).
selectionMat: Matrix4by4;
surfacePtInWorld: Point3d;
worldNormal: Vector;
assembly: Assembly;
primitive: Primitive;
class: Classification;
selection, oldSelection: Selection;
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
viewerPictureData.tree ← DisplayList3d.SceneToTree[viewerPictureData.scene, viewerPictureData.camera];
[] ← Preprocess3d.Preprocess[viewerPictureData.tree, viewerPictureData.camera];
class ← CastRays.SingleRay2[cameraPoint, viewerPictureData.tree, viewerPictureData.scene.lightSources, viewerPictureData.camera];
[surfacePtInWorld, worldNormal] ← DisectClassification1[class, viewerPictureData.camera, cameraPoint];
[assembly, primitive] ← DisectClassification2[class, viewerPictureData.camera, cameraPoint];
IF assembly # NIL THEN {
selectionMat ← MakeAlignedMat[worldNormal, surfacePtInWorld, assembly.coordSys];
oldSelection ← SVEditUser.GetSecondarySelection[];
ComplementOldSelection[viewerToolData, oldSelection, GraphicsColor.black];
selection ← SVEditUser.SetSecondarySelection[cameraPoint, assembly, primitive, selectionMat, viewerToolData];
ComplementSelection[viewerToolData, selection, GraphicsColor.black]; -- draw new selection into complement mode
};
CastRays.ReturnClassToPool[class];
};
SetSecondarySelection: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED {
Cast a ray into the scene from this point. If it hits anything, use the surface normal at that point to derive a coordinate system whose z axis is the parallel to the normal. Tell the editTool that a new selection has been made.
selection: Selection;
surfacePtInWorld: Point3d;
worldNormal: Vector;
assembly: Assembly;
primitive: Primitive;
selectionMat: Matrix4by4;
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
class: Classification ←
CastRays.SingleRay2[cameraPoint, viewerPictureData.tree,
viewerPictureData.scene.lightSources, viewerPictureData.camera];
[surfacePtInWorld, worldNormal] ←
DisectClassification1[class, viewerPictureData.camera, cameraPoint];
[assembly, primitive] ← DisectClassification2[class, viewerPictureData.camera, cameraPoint];
IF assembly#NIL THEN {
selectionMat ← MakeAlignedMat[worldNormal, surfacePtInWorld, assembly.coordSys];
selection ← SVEditUser.GetSecondarySelection[];
ComplementSelection[viewerToolData, selection, GraphicsColor.black];-- erase old one by complementing
selection ← SVEditUser.SetSecondarySelection[cameraPoint, assembly, primitive, selectionMat, viewerToolData];
ComplementSelection[viewerToolData, selection, GraphicsColor.black];-- paint new one by complementing
fake a button press to draw scene
};
CastRays.ReturnClassToPool[class];
};
EndSecondarySelection: PUBLIC PROC [viewerToolData: ViewerToolData, controlPoint: Point2d] = TRUSTED {
oldSelection, secondarySelection: Selection;
oldSelection ← SVEditUser.GetFinalSecondary[];
SetSecondarySelection[viewerToolData, controlPoint];-- set the selection to the final point
secondarySelection ← SVEditUser.GetSecondarySelection[];
[] ← SVEditUser.SetFinalSecondary[secondarySelection.cameraPoint, secondarySelection.assembly, secondarySelection.primitive, secondarySelection.coordSys.wrtWorld, secondarySelection.viewerToolData];
Is there an old selection in this viewer to complement?
IF oldSelection # NIL THEN {
IF oldSelection.viewerToolData = viewerToolData AND oldSelection.assembly # NIL
THEN ComplementBoundBox[oldSelection.primitive.boundBox, viewerToolData];
};
IF secondarySelection.assembly # NIL THEN
ComplementBoundBox[secondarySelection.primitive.boundBox, viewerToolData];
};
ComplementBoundBox: PUBLIC PROC [boundBox: BoundBox, viewerToolData: ViewerToolData] = TRUSTED {
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
camera: Camera ← viewerPictureData.camera;
screen: CoordSystem ← camera.screenCS;
DoComplementBoundBox: SAFE PROC [dc: Graphics.Context] = TRUSTED {
SVBoundBox.ComplementBoundBox[dc, boundBox, screen];
};
SVViewerUser.Painter[DoComplementBoundBox, viewerToolData];
};
PositionUpLeft: PUBLIC PROC [viewerToolData: ViewerToolData, controlPoint: Point2d] = TRUSTED {
Controlpoint is in camera coordinates.
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
camera: Camera ← viewerPictureData.camera;
frame: FrameBox ← camera.frame;
frame.fullScreen ← FALSE;
frame.downLeft[1] ← controlPoint[1];
frame.upRight[2] ← controlPoint[2];
};
PositionDownRight: PUBLIC PROC [viewerToolData: ViewerToolData, controlPoint: Point2d] = TRUSTED {
Controlpoint is in camera coordinates.
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
camera: Camera ← viewerPictureData.camera;
frame: FrameBox ← camera.frame;
fileCamera: FileCamera;
success: BOOL;
frame.downLeft[2] ← controlPoint[2];
frame.upRight[1] ← controlPoint[1];
DrawCameraFrame[viewerToolData];
Tell the appropriate file camera about the new frame.
[fileCamera, success] ← DisplayList3d.FindFileCameraFromName[camera.viewName, viewerPictureData.scene];
IF success THEN {
fileCamera.frame.downLeft ← frame.downLeft;
fileCamera.frame.upRight ← frame.upRight;
fileCamera.frame.fullScreen ← FALSE;
};
};
DeleteFrame: PROC [viewerToolData: ViewerToolData] = TRUSTED {
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
camera: Camera ← viewerPictureData.camera;
frame: FrameBox ← camera.frame;
frame.fullScreen ← TRUE;
};
DrawCameraFrame: PROC [viewerToolData: ViewerToolData] = TRUSTED {
viewerPictureData: ViewerPictureData ← NARROW[viewerToolData.viewerPicture.data];
camera: Camera ← viewerPictureData.camera;
DoDrawFrame: SAFE PROC [dc: Graphics.Context] = TRUSTED {
Graphics.SetColor[dc, GraphicsColor.black];
CSGGraphics.DrawFrame [dc, camera];
};
SVViewerUser.Painter[DoDrawFrame, viewerToolData];
};
END.