DIRECTORY Atom USING [PutPropOnList], CADTypes USING [VertexSequence, TriangleSequence], FS USING [StreamOpen], Imager USING [black, Context, MaskFill, MaskStroke, PathProc, SetColor, SetStrokeEnd, SetStrokeJoint, SetStrokeWidth, StrokeEnd, StrokeJoint], ImagerColor USING [RGB], IO USING [Close, int, PutF, real, STREAM, RopeFromROS, ROS], RealFns USING [SqRt], Rope USING [ROPE], SceneUtilities USING [NewShape, ReadShape], ShapeUtilities USING [XfmPtToDisplay, XfmPtToEyeSpace], ThreeDBasics USING [Context, GetSurfaceType, ImagerProc, ImagerProcRec, NatSequence, PatchProc, PtrPatch, PtrPatchSequence, PutShading, RegisterSurfaceType, ShadingValue, ShadingSequence, ShapeClass, ShapeInstance, ShapeProc, Vertex, VertexSequence], ThreeDHacks USING [], ThreeDViewer USING [DrawInViewer], Geometry3dVector USING [Triple, TripleSequence]; ThreeDHacksImpl: CEDAR PROGRAM IMPORTS Atom, FS, Imager, IO, RealFns, SceneUtilities, ShapeUtilities, ThreeDBasics, ThreeDViewer EXPORTS ThreeDHacks ~ BEGIN RegisterNewClasses: PUBLIC PROC [context3d: REF ThreeDBasics.Context] ~ BEGIN standardClass: ThreeDBasics.ShapeClass _ ThreeDBasics.GetSurfaceType[$Bezier]; standardClass.type _ $FatPoint; standardClass.display _ NIL; standardClass.displayPatch _ FatPointPatchDisplayProc; ThreeDBasics.RegisterSurfaceType[standardClass, $FatPoint]; standardClass.type _ $FatSeg; standardClass.displayPatch _ FatSegPatchDisplayProc; ThreeDBasics.RegisterSurfaceType[standardClass, $FatSeg]; END; FatPointPatchDisplayProc: ThreeDBasics.PatchProc ~ BEGIN dataList: LIST OF REAL; coordinates, eyespaceCoordinates, screenCoordinates: Geometry3dVector.Triple; coordinates _ [ x: patch.vtx[0].coord.x, y: patch.vtx[0].coord.y, z: patch.vtx[0].coord.z]; [eyespaceCoordinates] _ ShapeUtilities.XfmPtToEyeSpace[context, coordinates]; screenCoordinates _ ShapeUtilities.XfmPtToDisplay[context, eyespaceCoordinates]; dataList _ LIST[screenCoordinates.x, screenCoordinates.y]; ThreeDViewer.DrawInViewer[context, NEW[ThreeDBasics.ImagerProcRec _ [proc: FatPointImagerProc, data: dataList]]]; RETURN[NIL]; END; FatPointImagerProc: ThreeDBasics.ImagerProc _ BEGIN dataList: LIST OF REAL _ NARROW[data]; screenX: REAL _ dataList.first; screenY: REAL _ dataList.rest.first; Path: Imager.PathProc ~ BEGIN moveTo[[screenX+10, screenY]]; arcTo[[screenX-10, screenY], [screenX+10, screenY]]; END; Imager.SetColor[imagerCtx, Imager.black]; --Fill in the outline, colored black Imager.MaskFill[imagerCtx, Path]; END; FatSegPatchDisplayProc: ThreeDBasics.PatchProc ~ BEGIN dataList: LIST OF REAL; p0Coordinates, p0EyespaceCoordinates, p0ScreenCoordinates, p1Coordinates, p1EyespaceCoordinates, p1ScreenCoordinates: Geometry3dVector.Triple; p0Coordinates _ [ x: patch.vtx[0].coord.x, y: patch.vtx[0].coord.y, z: patch.vtx[0].coord.z]; [p0EyespaceCoordinates] _ ShapeUtilities.XfmPtToEyeSpace[context, p0Coordinates]; p0ScreenCoordinates _ ShapeUtilities.XfmPtToDisplay[context, p0EyespaceCoordinates]; p1Coordinates _ [ x: patch.vtx[1].coord.x, y: patch.vtx[1].coord.y, z: patch.vtx[1].coord.z]; [p1EyespaceCoordinates] _ ShapeUtilities.XfmPtToEyeSpace[context, p1Coordinates]; p1ScreenCoordinates _ ShapeUtilities.XfmPtToDisplay[context, p1EyespaceCoordinates]; dataList _ LIST[p0ScreenCoordinates.x, p0ScreenCoordinates.y, p1ScreenCoordinates.x, p1ScreenCoordinates.y]; ThreeDViewer.DrawInViewer[context, NEW[ThreeDBasics.ImagerProcRec _ [proc: FatSegImagerProc, data: dataList]]]; IF patch.clipState = clipped THEN RETURN[NIL]; RETURN[NIL]; END; FatSegImagerProc: ThreeDBasics.ImagerProc _ BEGIN dataList: LIST OF REAL _ NARROW[data]; firstScreenX: REAL _ dataList.first; firstScreenY: REAL _ dataList.rest.first; secondScreenX: REAL _ dataList.rest.rest.first; secondScreenY: REAL _ dataList.rest.rest.rest.first; Path: Imager.PathProc ~ BEGIN moveTo[[firstScreenX, firstScreenY]]; lineTo[[secondScreenX, secondScreenY]]; END; Imager.SetColor[imagerCtx, Imager.black]; Imager.SetStrokeWidth[imagerCtx, 5]; Imager.SetStrokeEnd[imagerCtx, round]; Imager.SetStrokeJoint[imagerCtx, round]; Imager.MaskStroke[imagerCtx, Path]; END; MakeFatPoint: PUBLIC PROC [name: Rope.ROPE, position: Geometry3dVector.Triple] RETURNS [newFatPoint: REF ThreeDBasics.ShapeInstance] ~ BEGIN nullVertex: ThreeDBasics.Vertex; nullShade: ThreeDBasics.ShadingValue; surface: REF ThreeDBasics.PtrPatchSequence; newFatPoint _ SceneUtilities.NewShape[name]; newFatPoint.fileName _ ""; newFatPoint.numSurfaces _ 1; newFatPoint.class^ _ ThreeDBasics.GetSurfaceType[$FatPoint]; newFatPoint.insideVisible _ TRUE; newFatPoint.vertex _ NEW[ThreeDBasics.VertexSequence[3]]; newFatPoint.vertex.length _ 3; newFatPoint.shade _ NEW[ThreeDBasics.ShadingSequence[3]]; newFatPoint.shade.length _ 3; FOR i: NAT IN [0..3) DO newFatPoint.vertex[i] _ NEW[ThreeDBasics.Vertex _ nullVertex]; newFatPoint.shade[i] _ NEW[ThreeDBasics.ShadingValue _ nullShade]; ENDLOOP; ThreeDBasics.PutShading[newFatPoint, $Color, NEW[ImagerColor.RGB _ [0.7, 0.7, 0.7]]]; newFatPoint.vertex[0].x _ position.x; newFatPoint.vertex[0].y _ position.y; newFatPoint.vertex[0].z _ position.z; newFatPoint.vertex[1].x _ position.x + 0.10; newFatPoint.vertex[1].y _ position.y; newFatPoint.vertex[1].z _ position.z; newFatPoint.vertex[2].x _ position.x; newFatPoint.vertex[2].y _ position.y + 0.01; newFatPoint.vertex[2].z _ position.z; newFatPoint.surface _ NEW[ThreeDBasics.PtrPatchSequence[1]]; surface _ NARROW[newFatPoint.surface, REF ThreeDBasics.PtrPatchSequence]; surface[0] _ NEW[ThreeDBasics.PtrPatch]; surface[0].vtxPtr _ NEW[ThreeDBasics.NatSequence[3]]; surface[0].vtxPtr.length _ 3; surface[0].nVtces _ 3; surface[0].type _ $FatPoint; surface[0].oneSided _ FALSE; surface[0].vtxPtr[0] _ 0; surface[0].vtxPtr[1] _ 1; surface[0].vtxPtr[2] _ 2; surface[0].props _ Atom.PutPropOnList[NIL, $ShapeName, name]; newFatPoint.centroid.x _ position.x; newFatPoint.centroid.y _ position.y; newFatPoint.centroid.z _ position.z; newFatPoint.boundingRadius _ 0.1; END; MakeFatSeg: PUBLIC PROC [name: Rope.ROPE, points: Geometry3dVector.TripleSequence] RETURNS [newFatSeg: REF ThreeDBasics.ShapeInstance] ~ BEGIN nullVertex: ThreeDBasics.Vertex; nullShade: ThreeDBasics.ShadingValue; surface: REF ThreeDBasics.PtrPatchSequence; radius: REAL; newFatSeg _ SceneUtilities.NewShape[name]; IF points.length < 2 THEN RETURN; newFatSeg.fileName _ ""; newFatSeg.numSurfaces _ points.length - 1; newFatSeg.class^ _ ThreeDBasics.GetSurfaceType[$FatSeg]; newFatSeg.insideVisible _ TRUE; newFatSeg.vertex _ NEW[ThreeDBasics.VertexSequence[points.length]]; newFatSeg.shade _ NEW[ThreeDBasics.ShadingSequence[points.length]]; FOR i: NAT IN [0..points.length) DO newFatSeg.vertex[i] _ NEW[ThreeDBasics.Vertex _ nullVertex]; newFatSeg.shade[i] _ NEW[ ThreeDBasics.ShadingValue _ nullShade]; ENDLOOP; ThreeDBasics.PutShading[newFatSeg, $Color, NEW[ImagerColor.RGB _ [0.7, 0.7, 0.7]]]; FOR i: NAT IN [0..points.length) DO newFatSeg.vertex[i].x _ points[i].x; newFatSeg.vertex[i].y _ points[i].y; newFatSeg.vertex[i].z _ points[i].z; ENDLOOP; newFatSeg.surface _ NEW[ThreeDBasics.PtrPatchSequence[points.length - 1]]; surface _ NARROW[newFatSeg.surface, REF ThreeDBasics.PtrPatchSequence]; FOR i: NAT IN [0..points.length - 1) DO surface[i] _ NEW[ThreeDBasics.PtrPatch]; surface[i].vtxPtr _ NEW[ThreeDBasics.NatSequence[3]]; surface[i].vtxPtr.length _ 3; surface[i].nVtces _ 3; surface[i].type _ $FatSeg; surface[i].oneSided _ FALSE; surface[i].vtxPtr[0] _ i; surface[i].vtxPtr[1] _ i + 1; surface[i].vtxPtr[2] _ i; ENDLOOP; newFatSeg.centroid.x _ newFatSeg.vertex[0].x; newFatSeg.centroid.y _ newFatSeg.vertex[0].y; newFatSeg.centroid.z _ newFatSeg.vertex[0].z; newFatSeg.boundingRadius _ 0; FOR i: NAT IN [0..points.length) DO radius _ RealFns.SqRt[ Sqr[newFatSeg.vertex[i].x - newFatSeg.centroid.x] + Sqr[newFatSeg.vertex[i].y - newFatSeg.centroid.y] + Sqr[newFatSeg.vertex[i].z - newFatSeg.centroid.z]]; IF radius > newFatSeg.boundingRadius THEN newFatSeg.boundingRadius _ radius; ENDLOOP; END; MakeTwoCell: PUBLIC PROC [name: Rope.ROPE, vertices: REF CADTypes.VertexSequence, triangles: REF CADTypes.TriangleSequence] RETURNS [newTwoCell: REF ThreeDBasics.ShapeInstance] ~ BEGIN shapeOutStream: IO.STREAM; shapeFileRope: Rope.ROPE; tempFileName: Rope.ROPE ~ "[]<>Foo>TemporaryTwoCellFile"; tempFileOutStream: IO.STREAM; shapeOutStream _ IO.ROS[]; IO.PutF[shapeOutStream, "TemporaryTwoCellFile\n"]; IO.PutF[shapeOutStream, "\nSurfaceType ~ ConvexPolygon, InsideVisible, CountFromOne\n"]; IO.PutF[shapeOutStream, "\nVertices ~ xyz: triple\n"]; FOR i: NAT IN [0..vertices.nVertices) DO IO.PutF[ shapeOutStream, "\t%g\t%g\t%g\n", IO.real[vertices[i].x], IO.real[vertices[i].y], IO.real[vertices[i].z]]; ENDLOOP; IO.PutF[shapeOutStream, "\nPolygons ~ index: integer vertices: nats\n"]; FOR i: NAT IN [0..triangles.nTriangles) DO IO.PutF[ shapeOutStream, "\t%g\t%g\t%g\t%g\n", IO.int[3], IO.int[triangles[i].firstVertex], IO.int[triangles[i].secondVertex], IO.int[triangles[i].thirdVertex]]; ENDLOOP; shapeFileRope _ IO.RopeFromROS[shapeOutStream]; tempFileOutStream _ FS.StreamOpen[tempFileName, $create]; IO.PutF[tempFileOutStream, shapeFileRope]; IO.Close[tempFileOutStream]; newTwoCell _ SceneUtilities.NewShape[name]; IF triangles.nTriangles > 0 THEN SceneUtilities.ReadShape[newTwoCell, tempFileName]; -- 9/22/86 - test put in for empty shapes END; AnotherMakeTwoCell: PROC [name: Rope.ROPE, vertices: REF CADTypes.VertexSequence, triangles: REF CADTypes.TriangleSequence] RETURNS [newTwoCell: REF ThreeDBasics.ShapeInstance] ~ BEGIN min, max: Geometry3dVector.Triple; nullVertex: ThreeDBasics.Vertex; nullShade: ThreeDBasics.ShadingValue; surface: REF ThreeDBasics.PtrPatchSequence; newTwoCell _ SceneUtilities.NewShape[name]; newTwoCell.fileName _ ""; newTwoCell.numSurfaces _ triangles.nTriangles; newTwoCell.insideVisible _ TRUE; newTwoCell.vertex _ NEW[ThreeDBasics.VertexSequence[vertices.nVertices]]; newTwoCell.shade _ NEW[ThreeDBasics.ShadingSequence[vertices.nVertices]]; FOR i: NAT IN [0..vertices.nVertices) DO newTwoCell.vertex[i] _ NEW[ThreeDBasics.Vertex _ nullVertex]; newTwoCell.shade[i] _ NEW[ ThreeDBasics.ShadingValue _ nullShade]; ENDLOOP; ThreeDBasics.PutShading[newTwoCell, $Color, NEW[ImagerColor.RGB _ [0.2, 0.8, 0.8]]]; FOR i: NAT IN [0..vertices.nVertices) DO newTwoCell.vertex[i].x _ vertices[i].x; newTwoCell.vertex[i].y _ vertices[i].y; newTwoCell.vertex[i].z _ vertices[i].z; ENDLOOP; newTwoCell.surface _ NEW[ThreeDBasics.PtrPatchSequence[triangles.nTriangles]]; surface _ NARROW[newTwoCell.surface, REF ThreeDBasics.PtrPatchSequence]; FOR i: NAT IN [0..triangles.nTriangles) DO surface[i] _ NEW[ThreeDBasics.PtrPatch]; surface[i].vtxPtr _ NEW[ThreeDBasics.NatSequence[3]]; surface[i].vtxPtr.length _ 3; surface[i].nVtces _ 3; surface[i].type _ $ConvexPolygon; surface[i].oneSided _ FALSE; surface[i].vtxPtr[0] _ triangles[i].firstVertex; surface[i].vtxPtr[1] _ triangles[i].secondVertex; surface[i].vtxPtr[2] _ triangles[i].thirdVertex; ENDLOOP; min _ max _ [newTwoCell.vertex[0].x, newTwoCell.vertex[0].y, newTwoCell.vertex[0].z]; FOR i: NAT IN (0..newTwoCell.vertex.length) DO IF newTwoCell.vertex[i] # NIL THEN BEGIN IF newTwoCell.vertex[i].x < min.x THEN min.x _ newTwoCell.vertex[i].x ELSE IF newTwoCell.vertex[i].x > max.x THEN max.x _ newTwoCell.vertex[i].x; IF newTwoCell.vertex[i].y < min.y THEN min.y _ newTwoCell.vertex[i].y ELSE IF newTwoCell.vertex[i].y > max.y THEN max.y _ newTwoCell.vertex[i].y; IF newTwoCell.vertex[i].z < min.z THEN min.z _ newTwoCell.vertex[i].z ELSE IF newTwoCell.vertex[i].x > max.z THEN max.z _ newTwoCell.vertex[i].z; END; ENDLOOP; newTwoCell.centroid.x _ (min.x + max.x) / 2; newTwoCell.centroid.y _ (min.y + max.y) / 2; newTwoCell.centroid.z _ (min.z + max.z) / 2; newTwoCell.boundingRadius _ 0.; FOR i: NAT IN [0..newTwoCell.vertex.length) DO radius: REAL _ RealFns.SqRt[ Sqr[newTwoCell.vertex[i].x - newTwoCell.centroid.x] + Sqr[newTwoCell.vertex[i].y - newTwoCell.centroid.y] + Sqr[newTwoCell.vertex[i].z - newTwoCell.centroid.z] ]; IF radius > newTwoCell.boundingRadius THEN newTwoCell.boundingRadius _ radius; ENDLOOP; newTwoCell _ SceneUtilities.NewShape[name]; SceneUtilities.ReadShape[newTwoCell, "[]<>Users>Rauen.pa>AlgebraicSurfaces>ChampagneGlass.shape"]; END; Sqr: PROC [number: REAL] RETURNS [result: REAL] ~ BEGIN result _ number * number; END; END. ThreeDHacksImpl.mesa James Rauen, August 21, 1986 9:28:24 pm PDT Last edited by: James Rauen January 14, 1988 2:06:47 pm PST MessageWindow USING [Append, Blink], Note: This is modeled after InitClasses in ThreeDWorld's StandardPatchProcs I'm not sure yet what the validate proc is for, so it probably does the wrong thing now. standardClass.validate _ StandardPatchProcs.ValidatePatchShape; standardClass.validate _ StandardPatchProcs.ValidatePatchShape; This procedure is called when ThreeDWorld wants to render the polygon comprising the FatPoint. (This procedure was inspired, in part, by Tilers.ConstantTiler) Arguments: context: REF Context, patch: REF Patch, data: REF ANY _ NIL Get the screen coordinates of the first vertex in the patch. Draw a black circle, radius 10 pixels, centered at the screen coordinates of the first vertex. Receives three arguments: context (ThreeDBasics.Context), imagerCtx (Imager.Context), and data (REF ANY). The data is narrowed to a list of two elements: screenX (REAL) and screenY (REAL). Arguments: context: REF Context, patch: REF Patch, data: REF ANY _ NIL Get the screen coordinates of the first two vertices in the patch, which will be the endpoints of the section of the FatSeg being drawn. Transform the coordinates of the segment's endpoints to screen coordinates. Draw a rounded, thick black line between the two points. Bail out if the patch is clipped. A FatPoint is, ideally, a single point located at position. To force ThreeDWorld to call the drawing procedure, it is necessary to have FatPoints contain a polygonal patch. So a FatPoint is composed of three vertices, the first one located at position and the others nearby, and one triangular patch defined by the three vertices. Scratch variables. Begin creating the newFatPoint. Initialize the vertex and shade sequences. Put in the coordinates of the vertices. Build the patch. Do the centroid and bounding radius. Scratch variables. Begin creating the newFatSeg. -- new version 9/22/86, for empty objects There must be at least two points to make the FatSeg. There must be at least two points to make the FatSeg. -- old version Error: SIGNAL = CODE; IF points.length < 2 THEN SIGNAL Error; Begin creating the newFatSeg. newFatSeg _ ThreeDScenes.NewShape[name]; Initialize the vertex and shade sequences. Put in the coordinates of the vertices. Build the patches. Do the centroid and bounding radius. Streams and other variables Open a rope output stream to write the shape file to. Write some keylines. Write the vertices, ignoring the first one (it's garbage). Write the polygons. Close up the stream, get it as a rope, and write it to a temporary file. Feed the file to ThreeDWorld constructors. ThreeDSurfaces.ReadShape[newTwoCell, tempFileName]; -- old version Scratch variables. Begin creating the newTwoCell. newTwoCell.type _ $ConvexPolygon; What about its class? Initialize the vertex and shade sequences. Put in the coordinates of the vertices. Build the patches. Find approximation to the bounding sphere. (Shamelessly stolen from ThreeDSurfacesImpl) Κ l˜™J™+Icode™;J™—šΟk ˜ Kšœœ˜Kšœ œ$˜2Kšœœ˜Kšœœ‚˜ŽKšœ œœ˜Kšœœœœ˜œœ™ΏJš œ œœœœ˜&Jšœ œ˜Jšœ œ˜$šŸœ˜K˜K˜4Kšœ˜—Kšœ+Οc$˜OKšœ!˜!Jšœ˜J˜J˜—šŸœ˜6Kš œœœœœ™F™ˆKšœ œœœ˜K˜ŽK˜—™KK˜]K˜RK˜UK˜]K˜RK˜UKšœ œ]˜lK˜—™8šœ$œI˜pK™——™!Kšœœœœ˜.K˜—Mšœœ˜ Kšœ˜K˜K˜—šŸœ˜1Jš œ œœœœ˜&Jšœœ˜$Jšœœ˜)Jšœœ˜/Jšœœ!˜4šŸœ˜Kšœ%˜%Kšœ'˜'Kšœ˜—Kšœ)˜)Kšœ$˜$Kšœ&˜&Kšœ(˜(Kšœ#˜#Jšœ˜J˜—K˜š Ÿ œ œ œ%œœ˜ŒK˜K™ΜK™™K˜ K˜%Kšœ œ˜+K˜—™Kšœ,˜,K˜K˜K˜Kšœœ(˜BLšœ˜—Lšœ-œ œ˜UL˜—™'L˜%L˜%L˜%L˜,L˜%L˜%L˜%L˜,L˜%L˜—™Lšœœ#˜