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];
};