DIRECTORY AIS, CastRays, CoordSys, CSG, CSGGraphics, DisplayList3d, DisplayListToTree, Graphics, GraphicsColor, InputFocus, IO, Matrix3d, Preprocess3d, Real, SV2d, SV3d, SVArtworkUser, SVError, SVInterfaceTypes, SVLines2d, SVMatrix2d, SVModelTypes, SVRayTypes, SVSceneTypes, SVSelections, SVVector3d, SVViewerInput, SVViewerUser, TIPUser, ViewerClasses; SVViewerInputImplB: PROGRAM IMPORTS AIS, CastRays, CoordSys, CSG, CSGGraphics, DisplayList3d, DisplayListToTree, Graphics, GraphicsColor, InputFocus, --IO, --Matrix3d, Preprocess3d, Real, SVArtworkUser, SVError, SVLines2d, SVMatrix2d, SVSelections, SVViewerInput, SVViewerUser, SVVector3d EXPORTS SVViewerInput = BEGIN Artwork: TYPE = SVModelTypes.Artwork; ArtworkToolData: TYPE = SVInterfaceTypes.ArtworkToolData; Assembly: TYPE = SVSceneTypes.Assembly; AssemblyList: TYPE = SVSceneTypes.AssemblyList; BoundBox: TYPE = SVModelTypes.BoundBox; Camera: TYPE = SVModelTypes.Camera; Classification: TYPE = SVRayTypes.Classification; Color: TYPE = GraphicsColor.Color; CoordSystem: TYPE = SVModelTypes.CoordSystem; 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; SurfacePointAndNormalAtSearchDepth: PROC [class: Classification, rayWorld: Ray, searchDepth: SearchDepth, root: Assembly] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector] = { SELECT searchDepth FROM first => [surfacePtWorld, normalWorld] _ CastRays.NthSurfacePointAndNormal[class, rayWorld, 1]; lastOfFirst => [surfacePtWorld, normalWorld] _ CastRays.LastOfFirstPointAndNormal[class, rayWorld]; last => IF class.count = 0 THEN ERROR ELSE [surfacePtWorld, normalWorld] _ CastRays.NthSurfacePointAndNormal[class, rayWorld, class.count]; lastOfLevel1 => [surfacePtWorld, normalWorld] _ CastRays.LastTopLevelPointAndNormal[class, rayWorld, root]; ENDCASE => ERROR; }; AssemblyAndPrimitiveAtSearchDepth: PROC [class: Classification, searchDepth: SearchDepth, root: Assembly] RETURNS [assembly: Assembly, primitive: Primitive] = { SELECT searchDepth FROM first => [assembly, primitive] _ CastRays.NthAssemblyAndPrimitive[class, 1]; lastOfFirst => [assembly, primitive] _ CastRays.NthAssemblyAndPrimitive[class, 1]; last => [assembly, primitive] _ CastRays.NthAssemblyAndPrimitive[class, class.count]; lastOfLevel1 => [assembly, primitive] _ CastRays.LastTopLevelAssemAndPrim[class, root]; ENDCASE => ERROR; }; StartTightRope: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { planeSel: Selection; planeAssem: Assembly; scene: Scene _ viewerToolData.scene; planeSel _ SVSelections.TopPlane[]; SVSelections.SetModeSkitter[tightrope]; IF planeSel = NIL THEN { SVError.Append["Please make a plane selection to specify tightrope.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; planeAssem _ planeSel.coincident; IF planeAssem.toolMasterObject = NIL OR planeAssem.toolMasterObject.mainBody = NIL THEN DisplayList3d.AddOrResizeToolToAssembly[planeAssem, scene]; DuringTightRope[viewerToolData, cameraPoint]; }; TightRopeAux: PRIVATE PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d, target: Assembly] RETURNS [skitterWORLD: Matrix4by4] = { skitterTarget: Matrix4by4; newOriginCamera, newOriginTarget: Point3d; plane: NAT; toolData: ToolData; cameraDir: Vector; camera1, camera2: Point3d; screen1, screen2, q: Point2d; ropeShadow, normalLine: TrigLine; parallel: BOOL; camera: Camera _ viewerToolData.camera; targetCS: CoordSystem _ target.coordSys; worldCS: CoordSystem _ viewerToolData.scene.coordSysRoot; cameraCS: CoordSystem _ camera.coordSys; camera1 _ Matrix3d.OriginOfMatrix[targetCS.wrtCamera]; toolData _ NARROW[target.toolMasterObject.mainBody]; plane _ toolData.plane; plane _ IF plane > 3 THEN 3 ELSE plane; SELECT plane FROM 1 => cameraDir _ Matrix3d.XAxisOfMatrix[targetCS.wrtCamera]; 2 => cameraDir _ Matrix3d.YAxisOfMatrix[targetCS.wrtCamera]; 3 => cameraDir _ Matrix3d.ZAxisOfMatrix[targetCS.wrtCamera]; ENDCASE => ERROR; camera2 _ SVVector3d.Add[camera1, cameraDir]; screen1 _ CSGGraphics.DoProjection[camera1, camera]; screen2 _ CSGGraphics.DoProjection[camera2, camera]; ropeShadow _ SVLines2d.TrigLineFromPoints[screen1, screen2]; normalLine _ SVLines2d.TrigLineNormalToTrigLineThruPoint[ropeShadow, cameraPoint]; [q, parallel] _ SVLines2d.TrigLineMeetsTrigLine[ropeShadow, normalLine]; IF parallel THEN ERROR; BEGIN p: Point3d; d: Vector; t: REAL; p _ camera1; d _ cameraDir; SELECT camera.projection FROM orthogonal => { IF ABS[d[1]] > ABS[d[2]] THEN t _ (q[1]-p[1])/d[1] ELSE t _ (q[2]-p[2])/d[2]; newOriginCamera[1] _ p[1] + t*d[1]; newOriginCamera[2] _ p[2] + t*d[2]; newOriginCamera[3] _ p[3] + t*d[3]; }; perspective => { denom1, denom2: REAL; f: REAL _ camera.focalLength; denom1 _ (d[1]*f + d[3]*q[1]); denom2 _ (d[2]*f + d[3]*q[2]); IF ABS[denom1] > ABS[denom2] THEN t _ ((f-p[3])*q[1] - (p[1]*f))/denom1 ELSE t _ ((f-p[3])*q[2] - (p[2]*f))/denom2; newOriginCamera[1] _ p[1] + t*d[1]; newOriginCamera[2] _ p[2] + t*d[2]; newOriginCamera[3] _ p[3] + t*d[3]; }; ENDCASE => ERROR; END; newOriginTarget _ CoordSys.FromCSToCS[newOriginCamera, cameraCS, targetCS]; skitterTarget _ Matrix3d.MakeTranslateMat[newOriginTarget[1], newOriginTarget[2], newOriginTarget[3]]; skitterWORLD _ CoordSys.FromCSToCSMat[skitterTarget, targetCS, worldCS]; }; DuringTightRope: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { planeAssem: Assembly; planeSel: Selection; skitterWORLD: Matrix4by4; camera: Camera _ viewerToolData.camera; planeSel _ SVSelections.TopPlane[]; IF planeSel = NIL THEN RETURN; planeAssem _ planeSel.coincident; skitterWORLD _ TightRopeAux[viewerToolData, cameraPoint, planeAssem]; SVViewerInput.ComplementSkitter[]; -- erase any old skitter SVSelections.UpdateSkitter[NIL, NIL, viewerToolData]; SVSelections.PositionSkitter[cameraPoint, skitterWORLD]; SVViewerInput.ComplementSkitter[]; -- draw new skitter }; EndTightRope: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { DuringTightRope[viewerToolData, cameraPoint]; }; StartWallWalk: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { planeSel: Selection; planeAssem: Assembly; scene: Scene _ viewerToolData.scene; planeSel _ SVSelections.TopPlane[]; SVSelections.SetModeSkitter[tightrope]; IF planeSel = NIL THEN { SVError.Append["Please make a plane selection to specify walk wall.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; planeAssem _ planeSel.coincident; IF planeAssem.toolMasterObject = NIL OR planeAssem.toolMasterObject.mainBody = NIL THEN DisplayList3d.AddOrResizeToolToAssembly[planeAssem, scene]; DuringWallWalk[viewerToolData, cameraPoint]; }; DuringWallWalk: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { planeAssem: Assembly; planeSel: Selection; targetWORLD, skitterWORLD: Matrix4by4; hitPointWORLD: Point3d; camera: Camera _ viewerToolData.camera; scene: Scene _ viewerToolData.scene; worldCS: CoordSystem _ scene.coordSysRoot; toolData: ToolData; parallel: BOOL; planeSel _ SVSelections.TopPlane[]; IF planeSel = NIL THEN RETURN; planeAssem _ planeSel.coincident; toolData _ NARROW[planeAssem.toolMasterObject.mainBody]; IF toolData = NIL THEN { SVError.Append["Wall walk plane is not defined.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; [hitPointWORLD, parallel] _ RayMeetsTopPlane[cameraPoint, planeAssem, 0, toolData.plane, camera]; IF parallel THEN { SVError.Append["DuringWallWalk: plane is parallel to ray.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; targetWORLD _ planeAssem.coordSys.wrtWorld; skitterWORLD _ Matrix3d.Translate[targetWORLD, hitPointWORLD[1], hitPointWORLD[2], hitPointWORLD[3]]; SVViewerInput.ComplementSkitter[]; -- erase any old skitter SVSelections.UpdateSkitter[NIL, NIL, viewerToolData]; SVSelections.PositionSkitter[cameraPoint, skitterWORLD]; SVViewerInput.ComplementSkitter[]; -- draw new skitter }; EndWallWalk: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { DuringWallWalk[viewerToolData, cameraPoint]; }; Sign: PRIVATE PROC [r: REAL] RETURNS [INT] = { IF r = 0.0 THEN RETURN[2]; IF r < 0.0 THEN RETURN[-1] ELSE RETURN[1]; }; AntiParallel: PRIVATE PROC [v1, v2: Vector] RETURNS [BOOL] = { RETURN[Sign[v1[1]] = -Sign[v2[1]] OR Sign[v1[2]] = -Sign[v2[2]] OR Sign[v1[3]] = -Sign[v2[3]] ]; }; MakeAlignedMat: PRIVATE PROC [worldNormal: Vector, surfacePtInWorld: Point3d, cs: CoordSystem] RETURNS [mat: Matrix4by4] = TRUSTED { yAxisOfCS: Vector _ Matrix3d.YAxisOfMatrix[cs.wrtWorld]; xAxis: Vector; IF SVVector3d.Parallel[yAxisOfCS, worldNormal] THEN { xAxis _ Matrix3d.XAxisOfMatrix[cs.wrtWorld]; IF AntiParallel[yAxisOfCS, worldNormal] THEN xAxis _ SVVector3d.Negate[xAxis]; } ELSE xAxis _ SVVector3d.CrossProduct[yAxisOfCS, worldNormal]; mat _ Matrix3d.MakeMatFromZandXAxis[worldNormal, xAxis, surfacePtInWorld]; }; RayMeetsTopPlane: PRIVATE PROC [cameraPoint: Point2d, target: Assembly, depth: REAL, plane: NAT, camera: Camera] RETURNS [planePtWorld: Point3d, parallel: BOOL] = TRUSTED { newRay: Ray; newRay _ CSG.GetRayFromPool[]; CSG.StuffWorldRayFromCamera[newRay, cameraPoint, camera]; [planePtWorld, parallel] _ CastRays.RayMeetsPlaneOfCoordSystem[target.coordSys, newRay, plane, depth]; CSG.ReturnRayToPool[newRay]; }; StartSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d, searchDepth: SearchDepth] = TRUSTED { selectionMat: Matrix4by4; surfacePtWorld: Point3d; normalWorld: Vector; assembly: Assembly; primitive: Primitive; class: Classification; rayWorld: Ray; scene: Scene _ viewerToolData.scene; camera: Camera _ viewerToolData.camera; IF viewerToolData.treeOutOfDate THEN { viewerToolData.tree _ DisplayListToTree.AssemblyToTree[viewerToolData.scene.assembly, scene, viewerToolData.camera]; [] _ Preprocess3d.PreprocessForInteraction[viewerToolData.tree, viewerToolData.camera]; viewerToolData.treeOutOfDate _ FALSE; }; [class, rayWorld] _ CastRays.SingleRay2[cameraPoint, viewerToolData.tree, viewerToolData.camera]; [assembly, primitive] _ AssemblyAndPrimitiveAtSearchDepth[class, searchDepth, scene.assembly]; IF class.count > 0 THEN [surfacePtWorld, normalWorld] _ SurfacePointAndNormalAtSearchDepth[class, rayWorld, searchDepth, scene.assembly]; CSG.ReturnRayToPool[rayWorld]; CastRays.ReturnClassToPool[class]; SVViewerInput.ComplementSkitter[]; -- erase any old skitter IF assembly # NIL THEN { selectionMat _ MakeAlignedMat[normalWorld, surfacePtWorld, assembly.coordSys]; SVSelections.UpdateSkitter[assembly, primitive, viewerToolData]; SVSelections.PositionSkitter[cameraPoint, selectionMat]; }; SVSelections.SetModeSkitter[surface]; SVViewerInput.ComplementSkitter[]; -- draw new skitter SVViewerUser.Selected[NIL, viewerToolData, red, FALSE, FALSE]; InputFocus.SetInputFocus[viewerToolData.viewerPicture]; }; -- end of StartSkitter DuringSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d, searchDepth: SearchDepth] = TRUSTED { surfacePtWorld: Point3d; normalWorld: Vector; assembly: Assembly; primitive: Primitive; selectionMat: Matrix4by4; camera: Camera _ viewerToolData.camera; scene: Scene _ viewerToolData.scene; class: Classification; rayWorld: Ray; [class, rayWorld] _ CastRays.SingleRay2[cameraPoint, viewerToolData.tree, camera]; [assembly, primitive] _ AssemblyAndPrimitiveAtSearchDepth[class, searchDepth, scene.assembly]; IF class.count > 0 THEN [surfacePtWorld, normalWorld] _ SurfacePointAndNormalAtSearchDepth[class, rayWorld, searchDepth, scene.assembly]; CSG.ReturnRayToPool[rayWorld]; CastRays.ReturnClassToPool[class]; SVViewerInput.ComplementSkitter[]; -- erase any old skitter IF assembly # NIL THEN { editToolData: EditToolData _ viewerToolData.editToolData; selectionMat _ MakeAlignedMat[normalWorld, surfacePtWorld, assembly.coordSys]; SVSelections.UpdateSkitter[assembly, primitive, viewerToolData]; SVSelections.PositionSkitter[cameraPoint, selectionMat]; } ELSE SVSelections.UpdateSkitter[NIL, NIL, viewerToolData]; SVViewerInput.ComplementSkitter[]; -- draw new skitter }; -- end DuringSkitter EndSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d, searchDepth: SearchDepth] = TRUSTED { DuringSkitter[viewerToolData, cameraPoint, searchDepth]; -- set the skitter to the final point. }; ExtendSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d, searchDepth: SearchDepth] = TRUSTED { oldAssembly, assem, commonAncestor: Assembly; oldPrimitive, prim: Primitive; oldViewerToolData, vtd: ViewerToolData; scene: Scene; scene _ viewerToolData.scene; [oldAssembly, oldPrimitive, oldViewerToolData] _ SVSelections.GetSkitterData[]; DuringSkitter[viewerToolData, cameraPoint, searchDepth]; [assem, prim, vtd] _ SVSelections.GetSkitterData[]; IF vtd # oldViewerToolData THEN { SVError.Append["Can't extend across viewers.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; IF assem = NIL THEN SVSelections.UpdateSkitter[oldAssembly, oldPrimitive, vtd] ELSE { commonAncestor _ DisplayListToTree.CommonAncestor[assem, oldAssembly, scene.assembly]; SVSelections.UpdateSkitter[commonAncestor, prim, vtd]; }; }; ExtendCoordSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { oldAssembly, assem, commonAncestor: Assembly; oldPrimitive, prim: Primitive; oldViewerToolData, vtd: ViewerToolData; scene: Scene; scene _ viewerToolData.scene; [oldAssembly, oldPrimitive, oldViewerToolData] _ SVSelections.GetSkitterData[]; DuringCoordSkitter[viewerToolData, cameraPoint]; [assem, prim, vtd] _ SVSelections.GetSkitterData[]; IF vtd # oldViewerToolData THEN { SVError.Append["Can't extend across viewers.", TRUE, TRUE]; SVError.Blink[]; RETURN; }; IF assem = NIL THEN SVSelections.UpdateSkitter[oldAssembly, oldPrimitive, vtd] ELSE { commonAncestor _ DisplayListToTree.CommonAncestor[assem, oldAssembly, scene.assembly]; SVSelections.UpdateSkitter[commonAncestor, prim, vtd]; }; }; NearestAssemblyToRay: PRIVATE PROC [cameraRay: Ray, root: Assembly] RETURNS [nearest: Assembly, dSquared: REAL] = { sonD: REAL; sonA: Assembly; origin: Point3d; WITH root.shape SELECT FROM shape: Shape => { -- A primitive. Just compute distance. nearest _ root; origin _ Matrix3d.OriginOfMatrix[root.coordSys.wrtCamera]; dSquared _ RayToPoint[cameraRay, origin]; }; alist: AssemblyList => { -- Take the minimum of myself and my subtrees, giving preference to the subtrees nearest _ root; origin _ Matrix3d.OriginOfMatrix[root.coordSys.wrtCamera]; dSquared _ RayToPoint[cameraRay, origin]; FOR sons: LIST OF Assembly _ alist.list, sons.rest UNTIL sons = NIL DO [sonA, sonD] _ NearestAssemblyToRay[cameraRay, sons.first]; IF sonD <= dSquared THEN { nearest _ sonA; dSquared _ sonD; }; ENDLOOP; }; ENDCASE => ERROR; }; RayToPoint: PUBLIC PROC [cameraRay: Ray, cameraPt: Point3d] RETURNS [dSquared: REAL] = TRUSTED { magRaySquared, dotProd, dotProdSquared, rCosThetaSquared, rSquared: REAL; screenToPoint: Vector; basePt: Point3d; direction: Vector; [basePt, direction] _ CSG.GetCameraRay[cameraRay]; magRaySquared _ SVVector3d.MagnitudeSquared[direction]; screenToPoint _ SVVector3d.Sub[cameraPt, basePt]; rSquared _ SVVector3d.MagnitudeSquared[screenToPoint]; dotProd _ SVVector3d.DotProduct[direction, screenToPoint]; dotProdSquared _ dotProd*dotProd; rCosThetaSquared _ dotProdSquared/magRaySquared; dSquared _ rSquared - rCosThetaSquared; -- Pythagorean Theorem }; StartCoordSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = { SVViewerUser.Selected[NIL, viewerToolData, red, FALSE, FALSE]; InputFocus.SetInputFocus[viewerToolData.viewerPicture]; DuringCoordSkitter[viewerToolData, cameraPoint]; }; DuringCoordSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = { cameraRay: Ray _ CSG.GetRayFromPool[]; camera: Camera _ viewerToolData.camera; scene: Scene _ viewerToolData.scene; nearest: Assembly; CSG.StuffCameraRay[cameraRay, cameraPoint, camera]; [nearest, ----] _ NearestAssemblyToRay[cameraRay, scene.assembly]; CSG.ReturnRayToPool[cameraRay]; SVViewerInput.ComplementSkitter[]; -- erase any old skitter SVSelections.UpdateSkitter[nearest, NIL, viewerToolData]; SVSelections.PositionSkitter[cameraPoint, nearest.coordSys.wrtWorld]; SVSelections.SetModeSkitter[coordframe]; SVViewerInput.ComplementSkitter[]; -- draw new skitter }; EndCoordSkitter: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = {}; Paint: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = { editToolData: EditToolData _ viewerToolData.editToolData; artworkToolData: ArtworkToolData _ NARROW[editToolData.artworkTool.data]; camera: Camera _ viewerToolData.camera; artwork: Artwork _ artworkToolData.artwork; assembly: Assembly; skitterWORLD, assemWORLD, skitterassem, worldCamera: Matrix4by4; imagePoint: Point2d; skitterPoint, surfPtassem: Point3d; normal: Vector; paintColor: Color _ artworkToolData.paintColor; path: Graphics.Path _ Graphics.NewPath[4]; DoDrawBrush: PROC [dc: Graphics.Context] = { Graphics.SetColor[dc, artworkToolData.paintColor]; CSGGraphics.DrawStroke[dc, path, 1, TRUE]; }; DuringSkitter[viewerToolData, cameraPoint, first]; [assembly, ----, viewerToolData] _ SVSelections.GetSkitterData[]; [----, skitterWORLD] _ SVSelections.GetPositionSkitter[]; assemWORLD _ assembly.coordSys.wrtWorld; skitterassem _ Matrix3d.WorldToLocal[assemWORLD, skitterWORLD]; normal _ Matrix3d.ZAxisOfMatrix[skitterassem]; FOR i: INT IN [-2..2] DO FOR j: INT IN [-2..2] DO skitterPoint _ [i, j, 0.0]; surfPtassem _ Matrix3d.Update[skitterassem, skitterPoint]; imagePoint _ SVArtworkUser.GetImagePointFromSurfacePoint[artwork, surfPtassem, normal]; SetImageColorAtPoint[artwork, imagePoint, paintColor]; ENDLOOP; ENDLOOP; worldCamera _ CoordSys.FindWorldInTermsOf[camera.coordSys]; CSGGraphics.MoveToAbsolute[path, Matrix3d.Update[worldCamera, Matrix3d.Update[skitterWORLD, [-2, -2, 0]]], camera]; CSGGraphics.LineToAbsolute[path, Matrix3d.Update[worldCamera, Matrix3d.Update[skitterWORLD, [-2, 2, 0]]], camera]; CSGGraphics.LineToAbsolute[path, Matrix3d.Update[worldCamera, Matrix3d.Update[skitterWORLD, [2, 2, 0]]], camera]; CSGGraphics.LineToAbsolute[path, Matrix3d.Update[worldCamera, Matrix3d.Update[skitterWORLD, [2, -2, 0]]], camera]; SVViewerUser.Painter[DoDrawBrush, viewerToolData]; }; SetImageColorAtPoint: PROC [artwork: Artwork, imagePoint: Point2d, paintColor: Color] = { artworkPoint: Point2d; IF artwork.source = NIL THEN RETURN; BEGIN uAIS, vAIS: REAL; -- u and v in AIS dots at this ais file's resolution uInch, vInch: REAL; -- u and v in inches artworkPoint _ SVMatrix2d.Update[artwork.artWRTPad.padWRTLocal, imagePoint]; -- in screen dots uInch _ artworkPoint[1]/72.0; vInch _ artworkPoint[2]/72.0; uAIS _ uInch*artwork.resolution; vAIS _ vInch*artwork.resolution; IF artwork.isColorFile THEN { redValue, greenValue, blueValue: CARDINAL; realRedValue, realGreenValue, realBlueValue: REAL; [realRedValue, realGreenValue, realBlueValue] _ GraphicsColor.ColorToRGB[paintColor]; IF uInch <= - artwork.halfWidth OR uInch >= artwork.halfWidth OR vInch <= -artwork.halfHeight OR vInch >= artwork.halfHeight THEN RETURN; redValue _ Real.Fix[realRedValue*255.0]; AIS.WriteSample[artwork.redWindow, redValue, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]]; greenValue _ Real.Fix[realGreenValue*255.0]; AIS.WriteSample[artwork.greenWindow, greenValue, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]]; blueValue _ Real.Fix[realBlueValue*255.0]; AIS.WriteSample[artwork.blueWindow, blueValue, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]]; } ELSE {-- artwork is a black and white file blackValue: CARDINAL; realBlackValue: REAL; realBlackValue _ GraphicsColor.ColorToIntensity[paintColor]; IF uInch <= - artwork.halfWidth OR uInch >= artwork.halfWidth OR vInch <= -artwork.halfHeight OR vInch >= artwork.halfHeight THEN RETURN; blackValue _ Real.Fix[realBlackValue*255.0]; AIS.WriteSample[artwork.blackWindow, blackValue, Real.FixC[-vAIS + artwork.halfHeightDots], Real.FixC[uAIS + artwork.halfWidthDots]]; }; END; }; -- end of SetImageColorAtPoint FrameUpLeft: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { camera: Camera _ viewerToolData.camera; oldMode: Graphics.PaintMode; DoDrawFrame: SAFE PROC [dc: Graphics.Context] = TRUSTED { Graphics.SetColor[dc, GraphicsColor.black]; oldMode _ Graphics.SetPaintMode[dc, invert]; CSGGraphics.DrawFrame [dc, camera]; [] _ Graphics.SetPaintMode[dc, oldMode]; }; SVViewerUser.Painter[DoDrawFrame, viewerToolData]; -- erase old frame camera.frame.fullScreen _ FALSE; camera.frame.downLeft[1] _ cameraPoint[1]; camera.frame.upRight[2] _ cameraPoint[2]; camera.frame.downLeft[2] _ cameraPoint[2] - 50.0; -- Just to give the frame an initial size. camera.frame.upRight[1] _ cameraPoint[1] + 50.0; SVViewerUser.Painter[DoDrawFrame, viewerToolData]; }; FrameDownRightMove: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { camera: Camera _ viewerToolData.camera; oldMode: Graphics.PaintMode; DoDrawFrame: SAFE PROC [dc: Graphics.Context] = TRUSTED { Graphics.SetColor[dc, GraphicsColor.black]; oldMode _ Graphics.SetPaintMode[dc, invert]; CSGGraphics.DrawFrame [dc, camera]; [] _ Graphics.SetPaintMode[dc, oldMode]; }; SVViewerUser.Painter[DoDrawFrame, viewerToolData]; camera.frame.downLeft[2] _ cameraPoint[2]; camera.frame.upRight[1] _ cameraPoint[1]; SVViewerUser.Painter[DoDrawFrame, viewerToolData]; }; FrameDownRightEnd: PUBLIC PROC [viewerToolData: ViewerToolData, cameraPoint: Point2d] = TRUSTED { camera: Camera _ viewerToolData.camera; fileCamera: FileCamera; success: BOOL; FrameDownRightMove[viewerToolData, cameraPoint]; [fileCamera, success] _ DisplayList3d.FindFileCameraFromName[camera.viewName, viewerToolData.scene]; IF success THEN { fileCamera.frame.downLeft _ camera.frame.downLeft; fileCamera.frame.upRight _ camera.frame.upRight; fileCamera.frame.fullScreen _ FALSE; }; }; DeleteFrame: PUBLIC PROC [viewerToolData: ViewerToolData] = TRUSTED { camera: Camera _ viewerToolData.camera; frame: FrameBox _ camera.frame; oldMode: Graphics.PaintMode; DoDrawFrame: SAFE PROC [dc: Graphics.Context] = TRUSTED { Graphics.SetColor[dc, GraphicsColor.black]; oldMode _ Graphics.SetPaintMode[dc, invert]; CSGGraphics.DrawFrame [dc, camera]; [] _ Graphics.SetPaintMode[dc, oldMode]; }; SVViewerUser.Painter[DoDrawFrame, viewerToolData]; frame.fullScreen _ TRUE; }; END. κFile: SVViewerInputImplB.mesa Last edited by Bier on May 23, 1985 5:48:16 pm PDT Copyright c 1984 by Xerox Corporation. All rights reserved. Contents: Procedures for responding to button clicks made in a solidviewer. Use the distinguished target assembly's coordinate system as the platform for each tight rope step. We key off of the plane of the target's tool. If plane = 1, we stay along the x-axis, 2 the y-axis, 3 the z-axis. 4 currently works as the x-axis, but might someday compute the nearest axis. Compute the new position of the skitter given the mouse position in CAMERA coordinates. This is somewhat tricky. The effect I would like is this: We are constraining the skitter to move along an axis (a line) in 3-space. This line projects onto a line on the screen (using the current camera projection). If we drop a perpendicular from the mousept to this 2d line, that is where the skitter should appear in 2-space. Compute the corresponding point in 3-space and we are done. DoDrawIntersection: PROC [dc: Graphics.Context] = { SVDraw3d.DrawX[dc, q, camera]; SVDraw3d.DrawX[dc, cameraPoint, camera]; }; For debugging... SVViewerUser.Painter[DoDrawIntersection, viewerToolData]; Now for the hard part. If we represent the tightrope parametrically as: R = p + t*d. x = p1 + t*d1. y = p2 + t*d2. z = p3 + t*d3. Then we wish to find the value of t so that CSGGraphics.DoProjection[R, camera] = skitterScreenPt (call it q); Let R = [x, y, z] then we wish, for perspective: xf/(f-z) = q1. and yf/(f-z) = q2. Using the first equation: (p1 + t*d1)f = (f - p3 - t*d3)*q1. t(d1*f + d3*q1) = (f-p3)*q1 - (p1*f). For orthogonal projection, we wish: x = q1, y = q2. (p1 + t*d1) = q1. t*d1 = q1-p1. t _ (q1-p1)/d1; The new skitter coordinate frame is the old target frame translated by newOriginCamera. We then express the results in WORLD coordinates. First find the cameraPoint in the coordinate system of the target. Use only the plane-th component of the resulting point in 3-space. Draw a line from the target origin to the new skitter origin. Cast a ray at the target plane (like for dragging). Use the intersection point as the new skitter origin. Cast a ray at the wall walk plane. 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 Allows positioning code to distinguish between top surfaces and bottom surfaces. targetPlanePt is in CAMERA coords. 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 (SetTargetSelection). 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. Using the previous skitter assembly as one node and the current value as another, find the common root and set the skitter assembly to this value. If current is NIL, leave the skitter assembly as it is. Set skitter assembly to the new value. Using the previous skitter assembly as one node and the current value as another, find the common root and set the skitter assembly to this value. If current is NIL, leave the skitter assembly as it is. Set skitter assembly to the new value. Use dot products to find the distance from the ray to this point. The user is trying to point at an existing coordinate frame. The skitter will highlight the frame which is nearest (in Euclidean distance) to the ray from eyepoint thru mouse point. Move the skitter as usual. Compute the corresponding artwork point as the artwork "Position" operation. Find the corresponding ais pixels as in ray tracing. Color in a block of them with the current artworkToolData.paintColor. Our paint brush is the set of points [{-2,-1,0,1,2}, {-2,-1,0,1,2}] in the coordinate system of the skitter. We convert them to master object coordinates and then to image points. SVError.AppendTypescript[IO.PutFR["%g, %g", [real[imagePoint[1]]], [real[imagePoint[2]]] ]]; Assume for now that artwork.file is an 8 bit-per-pixel ais file with rd scanning with origin in its lower left corner. imagePoint is in screen dots. Find the bounding box of the AIS file. If [u,v] is outside the AIS image, do nothing. Controlpoint is in camera coordinates. Controlpoint is in camera coordinates. Erase the old frame Draw the new frame. Once last update with the final position. Tell the appropriate file camera about the new frame. Erase the old frame. Κ€˜Iheadšœ™Jšœ2™2Jšœ Οmœ1™Jšœ˜Jšžœ˜Jšœ˜J˜Jšœ"™"—Jšœ ‘œ œ5˜ašžœ žœž˜Jšœ<žœžœ˜HJšœ˜Jšžœ˜Jšœ˜—J˜Jšœ‘œ ˜+Jš œ‘œ‘œ ‘œ ‘œ ‘œ˜eJ˜Jšœ’œ€˜;Jšœ5˜5Jšœ1‘œ˜8Jšœ’œ€˜6Jšœ˜J˜—š  œžœžœ:žœ˜[Jš œ˜,J˜J˜—J˜š  œžœžœžœžœžœ˜.Jšžœ žœžœ˜Jšžœ žœžœ˜Jšžœžœ˜J˜J˜—š   œžœžœžœžœ˜>šžœž˜$Jšœž˜Jšœ˜—J˜—J˜š  œžœžœCžœžœ˜„Jšœή™ήJšœ8˜8Jšœ˜šžœ-žœ˜5Jšœ,˜,Jšžœ&žœ"˜NJ™PJ˜—Jšžœ9˜=JšœJ˜JJšœ˜J˜—š œžœžœ1žœ žœžœ ‘œžœ ˜¬Jšœ"™"Jšœ ˜ Jšœ žœ˜Jšžœ6˜9Jšœ‘œ’œ(˜fJšžœ˜J˜J˜—š  œžœžœTžœ˜vJšœ–™–Jšœ˜Jšœ ‘œ ˜Jšœ‘œ ˜Jšœ˜Jšœ˜Jšœ˜Jšœ‘œ˜Jšœ$˜$Jšœ'˜'J˜šžœžœ˜&Jšœ(’œ>˜tJšœ’œ-˜WJšœžœ˜%J˜—Jšœ ‘œ ’ œ:˜aJšœŸ  œ%˜^šžœž˜Jš œ ‘œ‘œ’œ‘œ˜q—Jšœ‘œ˜Jšœ"˜"J˜Jšœ’œ€˜;šžœ žœžœ˜Jšœ’œ‘œ ‘œ˜NJšœ ’ œ&˜@Jšœ ’œ˜8Jšœ˜—Jšœ ’œ ˜%Jšœ œ€˜6Jš œ ’œžœžœžœ˜>Jšœ ’ œ˜7Jšœ€˜J˜—š  œžœžœTžœ˜wJšœ―™―Jšœ ‘œ ˜Jšœ‘œ ˜Jšœ˜Jšœ˜Jšœ˜Jšœ'˜'Jšœ$˜$Jšœ˜Jšœ‘œ˜J˜Jšœ ‘œ ’ œ+˜RJšœŸ  œ%˜^šžœž˜Jšœ ‘œ‘œ˜Jš’"œ ‘œ˜Q—Jšœ‘œ˜Jšœ"˜"J˜Jšœ’œ€˜;šžœ žœžœ˜Jšœ9˜9Jšœ’œ‘œ ‘œ˜NJšœ ’ œ&˜@Jšœ ’œ˜8Jšœ˜—Jšžœ’ œžœžœ˜:Jšœ œ€˜6Jšœ€˜J˜—š  œžœžœTžœ˜tJš’ œ+€'˜_J˜J˜—š  œžœžœTžœ˜wJ™σJšœ-˜-Jšœ˜Jšœ'˜'J˜ J˜Jšœ˜Jšœ> œ˜OJš’ œ+˜8Jšœ" œ˜3šœ!˜!Jšœ;˜;Jšœ˜J˜J˜—Jšœ!  œ ˜N˜Jšœ# œ%˜VJšœ   œ˜6J˜—J˜J˜—š œžœžœ:žœ˜bJ™σJšœ-˜-Jšœ˜Jšœ'˜'J˜ J˜Jšœ˜JšœO˜OJš’œ˜0Jšœ3˜3šžœžœ˜!Jšœ/žœžœ˜;Jšœ˜Jšžœ˜J˜—Jšžœ žœžœ;˜Nšžœ˜JšœV˜VJšœ6˜6J˜—J˜J˜—J˜š  œžœžœ"žœžœ˜sJšœžœ˜ J˜J˜Jšžœ žœž˜šœ€'˜9J˜Jšœ:˜:Jšœ)˜)J˜—šœ€P˜iJ˜Jšœ:˜:Jšœ)˜)š žœžœžœ"žœžœž˜FJ˜;šžœžœ˜J˜Jšœ˜J˜——Jšžœ˜J˜—Jšžœžœ˜J˜J˜—š   œžœžœ%žœ žœžœ˜`™ALšœDžœ˜IL˜L˜L˜L˜Lšœ2˜2Lšœ7˜7Lšœ1˜1Lšœ7˜7Lšœ:˜:Lšœ!˜!Lšœ0˜0Lšœ(€˜>Lšœ˜L˜——š œžœžœ;˜YJš œ ’œžœžœžœ˜>Jšœ ’ œ˜7Jš’œ˜0J˜J˜—š œž œ;˜ZJ™ΆJšœžœ˜&Jšœ'˜'Jšœ$˜$Jšœ˜J˜Jšœ3˜3Jšœ €œ4˜BJšžœ˜J˜Jšœ’œ€˜;Jšœ ’ œ˜9Jšœ ’œ)˜EJ˜Jšœ ’œ ˜(Jšœ œ€˜6J˜J˜—Jš œž œ=˜YJ˜š œžœžœ;˜MJ™εJšœ9˜9Jšœ#žœ ˜IJšœ'˜'Jšœ+˜+J˜Jš œ‘œ‘œ ‘œ‘œ ˜@Jšœ˜Jšœ‘œ ˜#J˜Jšœ/˜/J˜*š  œžœ˜,Jšœ2˜2Jšœ$žœ˜*J˜—J˜Jšœ2˜2Jšœ0’œ˜AJšœ€œ ‘œ&˜9J˜Jšœ‘œ˜(Jšœ‘œ‘œ ‘œ˜?Jšœ'‘œ˜.J˜J™΄šžœžœžœ ž˜šžœžœžœ ž˜J˜Jšœ‘œ‘œ˜:JšœH‘œ ˜WJšœžœA™\Jšœ6˜6—Jšžœ˜—Jšžœ˜Jšœ‘œ0˜;Jšœ6‘œ‘œ˜sJšœ6‘œ‘œ˜rJšœ6‘œ‘œ˜qJšœ6‘œ‘œ˜rJšœ2˜2Jšœ˜J˜—š œžœ?˜YJšœv™vJšœ™Jšœ&™&Jšœ˜Jšžœžœžœžœ˜$šž˜Jšœ žœ€4˜FJšœžœ€˜(JšœM€˜^Jšœ<˜