<> <> <> <> DIRECTORY CoordSys, Imager, IO, Matrix3d, SVObjectCast, PredefSweeps, Real, Rope, SV2d, SV3d, SVAssembly, SVBasicTypes, SVBoundBox, SVFaces, SVGraphics, SVLines3d, SVMasterObject, SVMasterObjectTypes, SVModelTypes, SVPolygon3d, SVRayTypes, SVScene, SVSceneTypes, SVVector3d, SweepCast, SweepGeometry, TFI3d; SVMasterObjectImplC: CEDAR PROGRAM IMPORTS CoordSys, IO, Matrix3d, SVObjectCast, PredefSweeps, Rope, SVAssembly, SVBoundBox, SVGraphics, SVLines3d, SVMasterObject, SVPolygon3d, SVScene, SVVector3d, SweepGeometry, TFI3d EXPORTS SVMasterObject = BEGIN OPEN SVMasterObject; <> Slice: TYPE = SVSceneTypes.Slice; Scene: TYPE = SVSceneTypes.Scene; BoundBox: TYPE = SVBasicTypes.BoundBox; BoundHedron: TYPE = SVBasicTypes.BoundHedron; Camera: TYPE = SVModelTypes.Camera; Classification: TYPE = SVRayTypes.Classification; Composite: TYPE = SVRayTypes.Composite; CoordSystem: TYPE = SVModelTypes.CoordSystem; Edge3d: TYPE = SV3d.Edge3d; LightSourceList: TYPE = SVModelTypes.LightSourceList; LinearMesh: TYPE = REF LinearMeshRecord; LinearMeshArray: TYPE = SweepGeometry.LinearMeshArray; LinearMeshRecord: TYPE = SweepGeometry.LinearMeshRecord; Line3d: TYPE = SV3d.Line3d; MasterObject: TYPE = SVSceneTypes.MasterObject; MasterObjectClass: TYPE = SVSceneTypes.MasterObjectClass; MasterObjectClassList: TYPE = SVSceneTypes.MasterObjectClassList; MasterObjectClassObj: TYPE = SVSceneTypes.MasterObjectClassObj; MasterObjectList: TYPE = SVSceneTypes.MasterObjectList; Matrix4by4: TYPE = SV3d.Matrix4by4; Path: TYPE = SV2d.Path; PlanarSurface: TYPE = SVSceneTypes.PlanarSurface; PlanarSurfaceObj: TYPE = SVSceneTypes.PlanarSurfaceObj; PlanarSurfaceList: TYPE = SVSceneTypes.PlanarSurfaceList; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; PointAndDone: TYPE = SVSceneTypes.PointAndDone; PointGenerator: TYPE = REF PointGeneratorObj; PointGeneratorObj: TYPE = SVSceneTypes.PointGeneratorObj; Poly3d: TYPE = SV3d.Poly3d; Polygon: TYPE = SV2d.Polygon; Primitive: TYPE = SVRayTypes.Primitive; Ray: TYPE = SVRayTypes.Ray; RectSurface: TYPE = REF RectSurfaceObj; RectSurfaceObj: TYPE = SVObjectCast.RectSurfaceObj; RevoFace: TYPE = SweepCast.RevoFace; SelectMode: TYPE = SVSceneTypes.SelectMode; SelectionClass: TYPE = SVSceneTypes.SelectionClass; Shape: TYPE = SVSceneTypes.Shape; SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor; SliceParts: TYPE = SVSceneTypes.SliceParts; SubBoxesBody: TYPE = REF SubBoxesBodyObj; SubBoxesBodyObj: TYPE = SweepCast.SubBoxesBodyObj; SubSpheresBody: TYPE = REF SubSpheresBodyObj; SubSpheresBodyObj: TYPE = SweepCast.SubSpheresBodyObj; SurfaceArray: TYPE = REF SurfaceArrayObj; SurfaceArrayObj: TYPE = SVRayTypes.SurfaceArrayObj; Vector3d: TYPE = SV3d.Vector3d; GetHedronProc: TYPE = SVSceneTypes.GetHedronProc; LineDrawProc: TYPE = SVSceneTypes.LineDrawProc; CountSurfProc: TYPE = SVSceneTypes.CountSurfProc; GetSurfProc: TYPE = SVSceneTypes.GetSurfProc; NormalsDrawProc: TYPE = SVSceneTypes.NormalsDrawProc; PreprocessProc: TYPE = SVSceneTypes.PreprocessProc; RayCastProc: TYPE = SVSceneTypes.RayCastProc; RayCastNoBBoxesProc: TYPE = SVSceneTypes.RayCastNoBBoxesProc; RayCastBoundingSpheresProc: TYPE = SVSceneTypes.RayCastBoundingSpheresProc; DrawPlanarSurfaceProc: TYPE = SVSceneTypes.DrawPlanarSurfaceProc; DrawSubBoxesProc: TYPE = SVSceneTypes.DrawSubBoxesProc; DrawSubSpheresProc: TYPE = SVSceneTypes.DrawSubSpheresProc; FileinProc: TYPE = SVSceneTypes.FileinProc; FileoutProc: TYPE = SVSceneTypes.FileoutProc; FileoutPolyProc: TYPE = SVSceneTypes.FileoutPolyProc; PointsInDescriptorProc: TYPE = SVSceneTypes.PointsInDescriptorProc; NextPointProc: TYPE = SVSceneTypes.NextPointProc; UpdateProc: TYPE = SVSceneTypes.UpdateProc; BuildBlockClass: PUBLIC PROC [] RETURNS [class: MasterObjectClass] = { class _ NEW[MasterObjectClassObj _ [ name: "block", <> getHedron: BlockBoundHedron, copy: BlockCopy, <> lineDraw: BlockLineDraw, lineDrawTransform: BlockLineDrawTransform, countSurf: BlockCountSurf, getSurf: BlockGetSurf, getSurfTransform: BlockGetSurfTransform, normalsDraw: BlockDrawNormals, preprocess: NoOpPreprocess, rayCast: BlockRayCast, rayCastNoBBoxes: BlockRayCastNoBBoxes, rayCastBoundingSpheres: BlockRayCastBoundingSpheres, drawSurf: BlockDrawSurf, drawSubBoxes: NoOpDrawSubBoxes, drawSubSpheres: NoOpDrawSubSpheres, <> transform: BlockTransform, <> describe: BlockDescribe, describeHit: BlockDescribeHit, filein: BlockFilein, fileout: BlockFileout, fileoutPoly: BlockFileoutPoly, <> emptyParts: BlockEmptyParts, newParts: BlockNewParts, unionParts: BlockUnionParts, differenceParts: BlockDifferenceParts, movingParts: BlockMovingParts, augmentParts: BlockAugmentParts, <> pointsInDescriptor: BlockPointsInDescriptor, nextPoint: BlockNextPoint, <> closestPointToPoint: BlockClosestPointToPoint, closestPointToLine: BlockClosestPointToLine, closestSegmentToLine: BlockClosestSegmentToLine, <> update: BlockUpdate ]]; }; BlockData: TYPE = REF BlockDataObj; BlockDataObj: TYPE = SVMasterObjectTypes.BlockDataObj; BlockCopy: PROC [mo: MasterObject, newName: Rope.ROPE] RETURNS [newMO: MasterObject] = { blockData: BlockData _ NARROW[mo.mainBody]; box: Box3d _ blockData.box; newMO _ BlockMakeMasterObject[newName, box.loX, box.loY, box.loZ, box.hiX, box.hiY, box.hiZ]; }; BlockBody: PROC [loX, loY, loZ, hiX, hiY, hiZ: REAL] RETURNS [blockData: BlockData] = { blockData _ NEW[BlockDataObj]; blockData.box.loX _ loX; blockData.box.loY _ loY; blockData.box.loZ _ loZ; blockData.box.hiX _ hiX; blockData.box.hiY _ hiY; blockData.box.hiZ _ hiZ; FOR i: NAT IN [0..12) DO blockData.segments[i] _ NEW[SegmentObj]; blockData.segments[i].edge _ SVLines3d.CreateEmptyEdge[]; ENDLOOP; }; BlockMakeMasterObject: PUBLIC PROC [name: Rope.ROPE, loX, loY, loZ: REAL _ -1.0, hiX, hiY, hiZ: REAL _ 1.0] RETURNS [mo: MasterObject] = { mainBody: BlockData _ BlockBody[loX, loY, loZ, hiX, hiY, hiZ]; lineBody: REF ANY _ mainBody; shadeBody: REF ANY _ PredefSweeps.GetUnitCube[]; rayCastBody: REF ANY _ BlockGetRayCastBody[]; mo _ SVScene.CreateMasterObject[name, blockClass, mainBody, lineBody, shadeBody, rayCastBody]; }; BlockGetRayCastBody: PROC [] RETURNS [surfaceArray: SurfaceArray] = { surfaceArray _ NEW[SurfaceArrayObj]; FOR i: NAT IN [0..5] DO surfaceArray[i+1] _ NEW[BlockHitDataObj _ [face: i]]; ENDLOOP; }; -- end of BlockGetRayCastBody <<>> <> BlockBoundHedron: PUBLIC PROC [mo: MasterObject] RETURNS [hedron: BoundHedron] = { blockData: BlockData _ NARROW[mo.mainBody]; box: Box3d _ blockData.box; hedron _ SVBoundBox.RectangularBoundHedron2[box.loX, box.hiX, box.loY, box.hiY, box.loZ, box.hiZ]; }; <<>> <> Box3d: TYPE = SVMasterObjectTypes.Box3d; GetBox3dPoint: PROC [box: Box3d, vert: NAT] RETURNS [point: Point3d] = { point _ SELECT vert FROM 0 => [box.loX, box.hiY, box.hiZ], 1 => [box.loX, box.hiY, box.loZ], 2 => [box.hiX, box.hiY, box.loZ], 3 => [box.hiX, box.hiY, box.hiZ], 4 => [box.loX, box.loY, box.hiZ], 5 => [box.loX, box.loY, box.loZ], 6 => [box.hiX, box.loY, box.loZ], 7 => [box.hiX, box.loY, box.hiZ], ENDCASE => ERROR }; GetBox3dCentroid: PROC [box: Box3d] RETURNS [point: Point3d] = { point[1] _ (box.loX+box.hiX)/2.0; point[2] _ (box.loY+box.hiY)/2.0; point[3] _ (box.loZ+box.hiZ)/2.0; }; AverageDepthInCamera: PROC [poly: Poly3d, localCS, cameraCS: CoordSystem] RETURNS [avgDepth: REAL] = { sum: REAL _ 0; realLen: REAL _ poly.len; localPoint: Point3d; FOR i: NAT IN[0..poly.len) DO localPoint _ poly[i]; localPoint _ SVGraphics.LocalToCamera[localPoint, localCS, cameraCS]; sum _ sum + localPoint[3]; ENDLOOP; avgDepth _ sum/realLen; }; BoxSurface: TYPE = REF BoxSurfaceObj; BoxSurfaceObj: TYPE = RECORD [ poly: Poly3d, localWorld, localCamera: Matrix4by4 ]; GetSurfFromBox: PROC [box: Box3d, slice: Slice, cameraCS: CoordSystem] RETURNS [psl: PlanarSurfaceList] = { BuildSurf: PROC [slice: Slice, shapeCS: CoordSystem, mo: MasterObject, cameraCS: CoordSystem, normal: Vector3d, box: Box3d, v: ARRAY[0..3] OF NAT] RETURNS [ps: PlanarSurface] = { poly: Poly3d _ SVPolygon3d.CreatePoly[4]; avgDepth: REAL; boxSurface: BoxSurface; poly _ SVPolygon3d.AddPolyPoint[poly, GetBox3dPoint[box, v[0]]]; poly _ SVPolygon3d.AddPolyPoint[poly, GetBox3dPoint[box, v[1]]]; poly _ SVPolygon3d.AddPolyPoint[poly, GetBox3dPoint[box, v[2]]]; poly _ SVPolygon3d.AddPolyPoint[poly, GetBox3dPoint[box, v[3]]]; avgDepth _ AverageDepthInCamera[poly, shapeCS, cameraCS]; boxSurface _ NEW[BoxSurfaceObj _ [poly, CoordSys.WRTWorld[shapeCS], CoordSys.WRTCamera[shapeCS, cameraCS]]]; ps _ NEW[PlanarSurfaceObj _ [ whichSurface: boxSurface, assembly: slice, normal: normal, mo: mo, depth: avgDepth]]; }; verts: ARRAY[0..3] OF NAT; shape: Shape _ NARROW[slice.shape]; shapeCS: CoordSystem _ shape.coordSys; mo: MasterObject _ shape.mo; normal: Vector3d; psl _ NIL; FOR i: NAT IN [0..5] DO verts _ CornersOfFace[i]; normal _ blockNormals[i]; psl _ CONS[BuildSurf[slice, shapeCS, mo, cameraCS, normal, box, verts], psl]; ENDLOOP; }; GetSurfFromBoxTransform: PROC [box: Box3d, slice: Slice, cameraCS: CoordSystem, transform: Matrix4by4] RETURNS [psl: PlanarSurfaceList] = { BuildSurfTransform: PROC [slice: Slice, shapeCS: CoordSystem, mo: MasterObject, cameraCS: CoordSystem, normal: Vector3d, box: Box3d, v: ARRAY[0..3] OF NAT, t: Matrix4by4] RETURNS [ps: PlanarSurface] = { poly: Poly3d _ SVPolygon3d.CreatePoly[4]; avgDepth: REAL; boxSurface: BoxSurface; poly _ SVPolygon3d.AddPolyPoint[poly, Matrix3d.Update[GetBox3dPoint[box, v[0]], t]]; poly _ SVPolygon3d.AddPolyPoint[poly, Matrix3d.Update[GetBox3dPoint[box, v[1]], t]]; poly _ SVPolygon3d.AddPolyPoint[poly, Matrix3d.Update[GetBox3dPoint[box, v[2]], t]]; poly _ SVPolygon3d.AddPolyPoint[poly, Matrix3d.Update[GetBox3dPoint[box, v[3]], t]]; avgDepth _ AverageDepthInCamera[poly, shapeCS, cameraCS]; boxSurface _ NEW[BoxSurfaceObj _ [poly, CoordSys.WRTWorld[shapeCS], CoordSys.WRTCamera[shapeCS, cameraCS]]]; ps _ NEW[PlanarSurfaceObj _ [ whichSurface: boxSurface, assembly: slice, normal: normal, mo: mo, depth: avgDepth]]; }; verts: ARRAY[0..3] OF NAT; shape: Shape _ NARROW[slice.shape]; shapeCS: CoordSystem _ shape.coordSys; mo: MasterObject _ shape.mo; normal: Vector3d; psl _ NIL; FOR i: NAT IN [0..5] DO verts _ CornersOfFace[i]; normal _ blockNormals[i]; psl _ CONS[BuildSurfTransform[slice, shapeCS, mo, cameraCS, normal, box, verts, transform], psl]; ENDLOOP; }; DrawBoxSurf: PROC [dc: Imager.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = { boxSurface: BoxSurface _ NARROW[ps.whichSurface]; poly: Poly3d _ boxSurface.poly; SVGraphics.DrawAreaNormalAbsolute[dc, ps.normal, poly, ps.assembly.artwork, lightSources, camera, boxSurface.localWorld, boxSurface.localCamera]; }; DrawWireBox3d: PROC [dc: Imager.Context, box: Box3d, camera: Camera, localCamera: Matrix4by4] = { DrawRect: PROC [dc: Imager.Context, box: Box3d, v: ARRAY[0..3] OF NAT] = { SVGraphics.SetCP[dc, GetBox3dPoint[box, v[0]], camera, localCamera]; SVGraphics.DrawTo[dc, GetBox3dPoint[box, v[1]], camera, localCamera]; SVGraphics.DrawTo[dc, GetBox3dPoint[box, v[2]], camera, localCamera]; SVGraphics.DrawTo[dc, GetBox3dPoint[box, v[3]], camera, localCamera]; SVGraphics.DrawTo[dc, GetBox3dPoint[box, v[0]], camera, localCamera]; }; verts: ARRAY[0..3] OF NAT; FOR i: NAT IN [0..5] DO verts _ CornersOfFace[i]; DrawRect[dc, box, verts]; ENDLOOP; }; BlockLineDraw: PUBLIC PROC [slice: Slice, dc: Imager.Context, camera: Camera] = { shape: Shape _ NARROW[slice.shape]; localCS: CoordSystem _ shape.coordSys; mo: MasterObject _ shape.mo; blockData: BlockData _ NARROW[mo.lineBody]; localCamera: Matrix4by4 _ CoordSys.WRTCamera[localCS, camera.coordSys]; DrawWireBox3d[dc, blockData.box, camera, localCamera]; }; BlockLineDrawTransform: PUBLIC PROC [sliceD: SliceDescriptor, dc: Imager.Context, camera: Camera, transform: Matrix4by4] = { slice: Slice _ sliceD.slice; shape: Shape _ NARROW[slice.shape]; shapeCS: CoordSystem _ shape.coordSys; localCamera: Matrix4by4 _ CoordSys.WRTCamera[shapeCS, camera.coordSys]; localWorld: Matrix4by4 _ CoordSys.WRTWorld[shapeCS]; worldCamera: Matrix4by4 _ CoordSys.FindWorldInTermsOf[camera.coordSys]; mo: MasterObject _ NARROW[slice.shape, Shape].mo; blockData: BlockData _ NARROW[mo.lineBody]; tempBox: Box3d; BEGIN fullTransform: BOOL _ FALSE; IF IsComplete[sliceD] THEN GOTO FullTransform; [tempBox, fullTransform] _ TransformedBox[sliceD, blockData, localWorld, transform]; IF fullTransform THEN GOTO FullTransform ELSE DrawWireBox3d[dc, tempBox, camera, localCamera]; EXITS FullTransform => { DrawWireBox3d[dc, blockData.box, camera, Matrix3d.Cat[localWorld, transform, worldCamera]]; }; END; }; TranslationInShape: PROC [transform, worldShape: Matrix4by4] RETURNS [tShape: Vector3d] = { tWorld: Vector3d; tWorld _ Matrix3d.OriginOfMatrix[transform]; tShape _ Matrix3d.UpdateDisplacement[worldShape, tWorld]; }; TransformedBox: PROC [sliceD: SliceDescriptor, blockData: BlockData, shapeWorld: Matrix4by4, transform: Matrix4by4] RETURNS [tBox: Box3d, fullTransform: BOOL _ FALSE] = { <> blockParts: BlockParts _ NARROW[sliceD.parts]; faceCount, faceNum, edgeCount, edgeNum, cornerCount, cornerNum: INTEGER; thisP, opP: Point3d; worldShape: Matrix4by4 _ Matrix3d.Inverse[shapeWorld]; shapeShape: Matrix4by4 _ Matrix3d.Cat[shapeWorld, transform, worldShape]; BEGIN [faceCount, faceNum] _ CountFaces[blockParts.faces]; [edgeCount, edgeNum] _ CountEdges[blockParts.edges]; [cornerCount, cornerNum] _ CountCorners[blockParts.corners]; IF faceCount > 1 OR edgeCount > 4 OR cornerCount > 4 THEN GOTO FullTransform; IF faceCount = 0 AND edgeCount = 0 AND cornerCount = 1 THEN { <> thisP _ GetBox3dPoint[blockData.box, cornerNum]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[cornerNum]]; thisP _ Matrix3d.Update[thisP, shapeShape]; } ELSE IF faceCount = 0 AND edgeCount = 1 AND cornerCount = 2 THEN { tShape: Vector3d _ TranslationInShape[transform, worldShape]; lo, hi: NAT; [lo, hi] _ CornersOfEdge[edgeNum]; thisP _ GetBox3dPoint[blockData.box, lo]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[lo]]; SELECT edgeNum FROM 0, 2, 6, 4 => -- front to back -- thisP _ [thisP[1] + tShape[1], thisP[2] + tShape[2], thisP[3]]; 3, 1, 5, 7 => -- left to right -- thisP _ [thisP[1], thisP[2] + tShape[2], thisP[3] + tShape[3]]; 8, 9, 10, 11 => -- top to bottom -- thisP _ [thisP[1] + tShape[1], thisP[2], thisP[3] + tShape[3]]; ENDCASE => ERROR; } ELSE IF faceCount = 1 AND edgeCount = 4 AND cornerCount = 4 THEN { tShape: Vector3d _ TranslationInShape[transform, worldShape]; corners: ARRAY[0..3] OF NAT; corners _ CornersOfFace[faceNum]; thisP _ GetBox3dPoint[blockData.box, corners[0]]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[corners[0]]]; SELECT faceNum FROM 0, 1 => -- top and bottom -- thisP _ [thisP[1], thisP[2] + tShape[2], thisP[3]]; 2, 4 => -- left and right -- thisP _ [thisP[1] + tShape[1], thisP[2], thisP[3]]; 3, 5 => -- top and bottom -- thisP _ [thisP[1], thisP[2], thisP[3] + tShape[3]]; ENDCASE => ERROR; } ELSE GOTO FullTransform; EXITS FullTransform => { fullTransform _ TRUE; thisP _ GetBox3dPoint[blockData.box, 0]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[0]]; thisP _ Matrix3d.Update[thisP, shapeShape]; opP _ Matrix3d.Update[opP, shapeShape]; }; END; tBox.loX _ MIN[thisP[1], opP[1]]; tBox.hiX _ MAX[thisP[1], opP[1]]; tBox.loY _ MIN[thisP[2], opP[2]]; tBox.hiY _ MAX[thisP[2], opP[2]]; tBox.loZ _ MIN[thisP[3], opP[3]]; tBox.hiZ _ MAX[thisP[3], opP[3]]; }; BlockCountSurf: PUBLIC PROC [masterObject: MasterObject] RETURNS [len: NAT] = { linMesh: LinearMesh _ NARROW[masterObject.shadeBody]; len _ SweepGeometry.CountPlanarSurfacesLinearSweep[linMesh]; }; BlockCountVert: PUBLIC PROC [masterObject: MasterObject] RETURNS [len: NAT] = { linMesh: LinearMesh _ NARROW[masterObject.shadeBody]; len _ SweepGeometry.CountVerticesLinearSweep[linMesh]; }; BlockGetSurf: PUBLIC PROC [slice: Slice, camera: CoordSystem] RETURNS [psl: PlanarSurfaceList] = { shape: Shape _ NARROW[slice.shape]; mo: MasterObject _ shape.mo; blockData: BlockData _ NARROW[mo.mainBody]; psl _ GetSurfFromBox[blockData.box, slice, camera]; }; BlockGetSurfTransform: PUBLIC PROC [sliceD: SliceDescriptor, camera: CoordSystem, transform: Matrix4by4] RETURNS [psl: PlanarSurfaceList] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; blockData: BlockData _ NARROW[mo.mainBody]; shapeWorld: Matrix4by4 _ CoordSys.WRTWorld[shape.coordSys]; tBox: Box3d; fullTransform: BOOL _ TRUE; [tBox, fullTransform] _ TransformedBox[sliceD, blockData, shapeWorld, transform]; IF fullTransform THEN { worldShape: Matrix4by4 _ Matrix3d.Inverse[shapeWorld]; shapeShape: Matrix4by4 _ Matrix3d.Cat[shapeWorld, transform, worldShape]; psl _ GetSurfFromBoxTransform[blockData.box, sliceD.slice, camera, shapeShape]; } ELSE psl _ GetSurfFromBox[tBox, sliceD.slice, camera]; }; BlockDrawNormals: PUBLIC PROC[dc: Imager.Context, data: REF ANY, camera: Camera, localCS: CoordSystem] = { linMesh: LinearMesh; IF ISTYPE[data, LinearMesh] THEN linMesh _ NARROW[data] ELSE SIGNAL SVMasterObject.WrongTypeOfData; SweepGeometry.DrawNormalsLinearSweep[dc, linMesh, camera, localCS]; }; BlockRayCast: PUBLIC PROC [cameraPoint: Point2d, localRay: Ray, masterObject: REF ANY, prim: Primitive] RETURNS [class: Classification] = { mo: MasterObject _ NARROW[masterObject]; blockData: BlockData _ NARROW[mo.mainBody]; RETURN[SVObjectCast.BlockCast[localRay, prim, blockData, NARROW[mo.rayCastBody]]]; }; BlockRayCastNoBBoxes: PUBLIC PROC [localRay: Ray, masterObject: REF ANY, prim: Primitive] RETURNS [class: Classification] = { mo: MasterObject _ NARROW[masterObject]; blockData: BlockData _ NARROW[mo.mainBody]; RETURN[SVObjectCast.BlockCast[localRay, prim, blockData, NARROW[mo.rayCastBody]]]; }; BlockRayCastBoundingSpheres: PUBLIC PROC [localRay: Ray, masterObject: REF ANY, prim: Primitive] RETURNS [class: Classification] = { mo: MasterObject _ NARROW[masterObject]; blockData: BlockData _ NARROW[mo.mainBody]; RETURN[SVObjectCast.BlockCast[localRay, prim, blockData, NARROW[mo.rayCastBody]]]; }; BlockDrawSurf: PUBLIC PROC [dc: Imager.Context, ps: PlanarSurface, lightSources: LightSourceList, camera: Camera] = { DrawBoxSurf[dc, ps, lightSources, camera]; }; <<>> <> BlockTransform: PROC [sliceD: SliceDescriptor, scene: Scene, transform: Matrix4by4] = { slice: Slice _ sliceD.slice; shape: Shape _ NARROW[slice.shape]; thisP, opP: Point3d; shapeCS: CoordSystem _ shape.coordSys; shapeWorld: Matrix4by4 _ CoordSys.WRTWorld[shapeCS]; mo: MasterObject _ NARROW[slice.shape, Shape].mo; blockData: BlockData _ NARROW[mo.mainBody]; blockParts: BlockParts _ NARROW[sliceD.parts]; faceCount, faceNum, edgeCount, edgeNum, cornerCount, cornerNum: INTEGER; BEGIN IF IsComplete[sliceD] THEN GOTO FullTransform; [faceCount, faceNum] _ CountFaces[blockParts.faces]; [edgeCount, edgeNum] _ CountEdges[blockParts.edges]; [cornerCount, cornerNum] _ CountCorners[blockParts.corners]; IF faceCount > 1 OR edgeCount > 4 OR cornerCount > 4 THEN GOTO FullTransform; IF faceCount = 0 AND edgeCount = 0 AND cornerCount = 1 THEN { <> worldShape: Matrix4by4 _ Matrix3d.Inverse[shapeWorld]; shapeShape: Matrix4by4 _ Matrix3d.Cat[shapeWorld, transform, worldShape]; thisP _ GetBox3dPoint[blockData.box, cornerNum]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[cornerNum]]; thisP _ Matrix3d.Update[thisP, shapeShape]; } ELSE IF faceCount = 0 AND edgeCount = 1 AND cornerCount = 2 THEN { worldShape: Matrix4by4 _ Matrix3d.Inverse[shapeWorld]; tShape: Vector3d _ TranslationInShape[transform, worldShape]; lo, hi: NAT; [lo, hi] _ CornersOfEdge[edgeNum]; thisP _ GetBox3dPoint[blockData.box, lo]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[lo]]; SELECT edgeNum FROM 0, 2, 6, 4 => -- front to back -- thisP _ [thisP[1] + tShape[1], thisP[2] + tShape[2], thisP[3]]; 3, 1, 5, 7 => -- left to right -- thisP _ [thisP[1], thisP[2] + tShape[2], thisP[3] + tShape[3]]; 8, 9, 10, 11 => -- top to bottom -- thisP _ [thisP[1] + tShape[1], thisP[2], thisP[3] + tShape[3]]; ENDCASE => ERROR; } ELSE IF faceCount = 1 AND edgeCount = 4 AND cornerCount = 4 THEN { worldShape: Matrix4by4 _ Matrix3d.Inverse[shapeWorld]; tShape: Vector3d _ TranslationInShape[transform, worldShape]; corners: ARRAY[0..3] OF NAT; corners _ CornersOfFace[faceNum]; thisP _ GetBox3dPoint[blockData.box, corners[0]]; opP _ GetBox3dPoint[blockData.box, OppositeCorner[corners[0]]]; SELECT faceNum FROM 0, 1 => -- top and bottom -- thisP _ [thisP[1], thisP[2] + tShape[2], thisP[3]]; 2, 4 => -- left and right -- thisP _ [thisP[1] + tShape[1], thisP[2], thisP[3]]; 3, 5 => -- top and bottom -- thisP _ [thisP[1], thisP[2], thisP[3] + tShape[3]]; ENDCASE => ERROR; } ELSE GOTO FullTransform; blockData.box.loX _ MIN[thisP[1], opP[1]]; blockData.box.hiX _ MAX[thisP[1], opP[1]]; blockData.box.loY _ MIN[thisP[2], opP[2]]; blockData.box.hiY _ MAX[thisP[2], opP[2]]; blockData.box.loZ _ MIN[thisP[3], opP[3]]; blockData.box.hiZ _ MAX[thisP[3], opP[3]]; EXITS FullTransform => { assemblyWorld: Matrix4by4 _ CoordSys.WRTWorld[slice.coordSys]; newAssemblyWorld: Matrix4by4 _ Matrix3d.Mult[assemblyWorld, transform]; SVAssembly.AbsTransf[slice, scene, newAssemblyWorld]; }; END; }; CountCorners: PROC [a: CornerArray] RETURNS [count: INTEGER, cornerNum: INTEGER] = { <> count _ 0; cornerNum _ -1; FOR corner: INTEGER IN [0..8) DO IF a[corner] THEN {count _ count+1; cornerNum _ corner}; ENDLOOP; }; CountCenters: PROC [a: CenterArray] RETURNS [count: INTEGER, centerNum: INTEGER] = { <> count _ 0; centerNum _ -1; FOR center: INTEGER IN [0..6) DO IF a[center] THEN {count _ count+1; centerNum _ center}; ENDLOOP; }; CountEdges: PROC [a: EdgeArray] RETURNS [count: INTEGER, edgeNum: INTEGER] = { <> count _ 0; edgeNum _ -1; FOR edge: INTEGER IN [0..12) DO IF a[edge] THEN {count _ count+1; edgeNum _ edge}; ENDLOOP; }; CountFaces: PROC [a: FaceArray] RETURNS [count: INTEGER, faceNum: INTEGER] = { <> count _ 0; faceNum _ -1; FOR face: INTEGER IN [0..6) DO IF a[face] THEN {count _ count+1; faceNum _ face}; ENDLOOP; }; blockNormals: ARRAY [0..6) OF Vector3d = [ [0,1,0], [0,-1,0], [-1,0,0], [0,0,-1], [1,0,0], [0,0,1] ]; blockCornerRopes: ARRAY [0..8) OF Rope.ROPE = [ "top front left", "top back left", "top back right", "top front right", "bottom front left", "bottom back left", "bottom back right", "bottom front right" ]; blockEdgeRopes: ARRAY [0..12) OF Rope.ROPE = [ "top left", "top back", "top right", "top front", "bottom left", "bottom back", "bottom right", "bottom front", "front left", "back left", "back right", "front right" ]; blockCenterRopes: ARRAY [0..6) OF Rope.ROPE = [ "top", "bottom", "left", "back", "right", "front" ]; <> BlockDescribeHit: PROC [mo: MasterObject, hitData: REF ANY] RETURNS [rope: Rope.ROPE] = { blockHitData: BlockHitData; prefix: Rope.ROPE; IF hitData = NIL THEN RETURN["a BLOCK"]; blockHitData _ NARROW[hitData]; IF blockHitData.corner#-1 THEN prefix _ blockCornerRopes[blockHitData.corner] ELSE IF blockHitData.center#-1 THEN prefix _ blockCenterRopes[blockHitData.center] ELSE IF blockHitData.centroid#-1 THEN prefix _ "centroid" ELSE IF blockHitData.edge#-1 THEN prefix _ blockEdgeRopes[blockHitData.edge] ELSE IF blockHitData.face#-1 THEN prefix _ blockCenterRopes[blockHitData.face] ELSE ERROR; rope _ Rope.Concat[prefix, " of a block"]; }; BlockDescribe: PROC [sliceD: SliceDescriptor] RETURNS [rope: Rope.ROPE] = { prefix: Rope.ROPE; blockParts: BlockParts _ NARROW[sliceD.parts]; cornerCount, edgeCount, centerCount, cornerIndex, edgeIndex, centerIndex: INTEGER; [cornerCount, cornerIndex] _ CountCorners[blockParts.corners]; [edgeCount, edgeIndex] _ CountEdges[blockParts.edges]; [centerCount, centerIndex] _ CountCenters[blockParts.centers]; IF cornerCount+centerCount+edgeCount>1 THEN RETURN["multiple parts of a Box slice"] ELSE { centroidOnly: BOOL _ blockParts.centroid AND edgeCount=0 AND cornerCount=0 AND centerCount=0; oneEdge: BOOL _ NOT blockParts.centroid AND edgeCount=1 AND cornerCount=0 AND centerCount=0; oneCorner: BOOL _ NOT blockParts.centroid AND edgeCount=0 AND cornerCount=1 AND centerCount=0; oneCenter: BOOL _ NOT blockParts.centroid AND edgeCount=0 AND cornerCount=0 AND centerCount=1; noParts: BOOL _ NOT blockParts.centroid AND edgeCount=0 AND cornerCount=0 AND centerCount=0; SELECT TRUE FROM oneCorner => prefix _ blockCornerRopes[cornerIndex]; oneCenter => prefix _ blockCenterRopes[centerIndex]; oneEdge => prefix _ blockEdgeRopes[edgeIndex]; centroidOnly => prefix _ "centroid"; noParts => prefix _ "NO parts"; ENDCASE => ERROR; rope _ Rope.Concat[prefix, " of a Block"]; }; }; BlockFilein: PUBLIC PROC [f: IO.STREAM, name: Rope.ROPE, version: REAL] RETURNS [mo: MasterObject] = { IF version >= 7.02 THEN { loX, loY, loZ, hiX, hiY, hiZ: REAL; TFI3d.ReadRope[f, "["]; loX _ TFI3d.ReadBlankAndReal[f]; loY _ TFI3d.ReadBlankAndReal[f]; loZ _ TFI3d.ReadBlankAndReal[f]; hiX _ TFI3d.ReadBlankAndReal[f]; hiY _ TFI3d.ReadBlankAndReal[f]; hiZ _ TFI3d.ReadBlankAndReal[f]; TFI3d.ReadBlankAndRope[f, "]"]; TFI3d.ReadBlank[f]; mo _ BlockMakeMasterObject[name, loX, loY, loZ, hiX, hiY, hiZ]; } ELSE { TFI3d.ReadRope[f, "data: procedural"]; TFI3d.ReadBlank[f]; mo _ BlockMakeMasterObject[name]; }; }; BlockFileout: PUBLIC PROC [f: IO.STREAM, mo: MasterObject] = { blockData: BlockData _ NARROW[mo.mainBody]; f.PutF["[%g %g %g ", [real[blockData.box.loX]], [real[blockData.box.loY]], [real[blockData.box.loZ]]]; f.PutF["%g %g %g]", [real[blockData.box.hiX]], [real[blockData.box.hiY]], [real[blockData.box.hiZ]]]; }; BlockFileoutPoly: PUBLIC PROC [f: IO.STREAM, mo: MasterObject] = { linMesh: LinearMesh _ NARROW[mo.shadeBody]; SweepGeometry.PolyListLinear[f, linMesh]; }; <<>> <> BlockHitData: TYPE = REF BlockHitDataObj; BlockHitDataObj: TYPE = RECORD [ corner: [-1..7] _ -1, center: [-1..5] _ -1, centroid: [-1..0] _ -1, edge: [-1..11] _ -1, face: [-1..5] _ -1, hitPoint: Point3d _ [0,0,0] ]; BlockParts: TYPE = REF BlockPartsObj; BlockPartsObj: TYPE = RECORD [ corners: CornerArray, -- which corners of box are selected. centers: CenterArray, -- is the middle joint selected? centroid: BOOL, edges: EdgeArray, -- which edges of box are selected. faces: FaceArray ]; CornerArray: TYPE = ARRAY [0..8) OF BOOL; -- top (lf, lb, rb, rf), bottom (lf, lb, rb, rf) CenterArray: TYPE = ARRAY [0..6) OF BOOL; EdgeArray: TYPE = ARRAY [0..12) OF BOOL; FaceArray: TYPE = ARRAY [0..6) OF BOOL; MakeComplete: PROC [parts: SliceParts] = { WITH parts SELECT FROM blockParts: BlockParts => { blockParts.corners _ ALL[TRUE]; blockParts.centers _ ALL[TRUE]; blockParts.centroid _ TRUE; blockParts.edges _ ALL[TRUE]; blockParts.faces _ ALL[TRUE]; }; ENDCASE => ERROR; }; IsComplete: PROC [sliceD: SliceDescriptor] RETURNS [BOOL] = { blockParts: BlockParts _ NARROW[sliceD.parts]; RETURN[blockParts.corners=ALL[TRUE] AND blockParts.centers=ALL[TRUE] AND blockParts.centroid = TRUE AND blockParts.edges=ALL[TRUE] AND blockParts.faces = ALL[TRUE]]; }; BlockEmptyParts: PROC [sliceD: SliceDescriptor] RETURNS [BOOL] = { blockParts: BlockParts _ NARROW[sliceD.parts]; RETURN[blockParts.corners=ALL[FALSE] AND blockParts.centers=ALL[FALSE] AND blockParts.centroid = FALSE AND blockParts.edges=ALL[FALSE] AND blockParts.faces = ALL[FALSE]]; }; BlockNewParts: PROC [slice: Slice, hitData: REF ANY, hitPoint: Point3d, mode: SelectMode] RETURNS [sliceD: SliceDescriptor] = { blockHitData: BlockHitData _ NARROW[hitData]; blockParts: BlockParts; cornerIndex, centerIndex, centroid, face: INT; blockParts _ NEW[BlockPartsObj _ [corners: ALL[FALSE], centers: ALL[FALSE], centroid: FALSE, edges: ALL[FALSE], faces: ALL[FALSE]]]; SELECT mode FROM joint => { IF blockHitData.corner#-1 THEN blockParts.corners[blockHitData.corner] _ TRUE ELSE IF blockHitData.center#-1 THEN blockParts.centers[blockHitData.center] _ TRUE ELSE IF blockHitData.centroid#-1 THEN blockParts.centroid _ TRUE ELSE IF blockHitData.edge#-1 OR blockHitData.face#-1 THEN { [cornerIndex, centerIndex, centroid] _ NearestBlockPoint[slice, hitPoint]; IF centroid#-1 THEN blockParts.centroid _ TRUE ELSE IF centerIndex#-1 THEN blockParts.centers[centerIndex] _ TRUE ELSE blockParts.corners[cornerIndex] _ TRUE; }; }; segment => { IF blockHitData.centroid#-1 THEN MakeComplete[blockParts] ELSE IF blockHitData.center#-1 THEN MakeComplete[blockParts] ELSE IF blockHitData.corner#-1 THEN MakeComplete[blockParts] ELSE IF blockHitData.edge#-1 THEN blockParts.edges[blockHitData.edge] _ TRUE; }; traj => { IF blockHitData.face#-1 THEN {face _ blockHitData.face; GOTO MakeFaceParts} ELSE IF blockHitData.center#-1 THEN {face _ blockHitData.center; GOTO MakeFaceParts} ELSE MakeComplete[blockParts]; EXITS MakeFaceParts => { corners: ARRAY[0..3] OF NAT; edgeNums: ARRAY [0..3] OF NAT; blockParts.faces[face] _ TRUE; corners _ CornersOfFace[face]; FOR i: NAT IN [0..3] DO blockParts.corners[corners[i]] _ TRUE ENDLOOP; edgeNums _ EdgesOfFace[face]; FOR i: NAT IN [0..3] DO blockParts.edges[edgeNums[i]] _ TRUE ENDLOOP; }; }; topLevel, slice => MakeComplete[blockParts]; none => { MakeComplete[blockParts]; }; ENDCASE => ERROR; sliceD _ SVAssembly.DescriptorFromParts[slice, blockParts]; }; <<>> BlockUnionParts: PROC [partsA: SliceDescriptor, partsB: SliceDescriptor] RETURNS [aPlusB: SliceDescriptor] = { blockPartsA: BlockParts _ NARROW[partsA.parts]; blockPartsB: BlockParts _ NARROW[partsB.parts]; newParts: BlockParts; IF partsA = NIL OR partsB = NIL THEN ERROR; IF partsA.parts = NIL THEN RETURN[partsB]; IF partsB.parts = NIL THEN RETURN[partsA]; newParts _ NEW[BlockPartsObj _ [corners: ALL[FALSE], centers: ALL[FALSE], centroid: FALSE, edges: ALL[FALSE], faces: ALL[FALSE] ] ]; FOR i: INTEGER IN [0..8) DO newParts.corners[i] _ blockPartsA.corners[i] OR blockPartsB.corners[i]; ENDLOOP; FOR i: INTEGER IN [0..6) DO newParts.centers[i] _ blockPartsA.centers[i] OR blockPartsB.centers[i]; newParts.faces[i] _ blockPartsA.faces[i] OR blockPartsB.faces[i]; ENDLOOP; FOR i: INTEGER IN [0..12) DO newParts.edges[i] _ blockPartsA.edges[i] OR blockPartsB.edges[i]; ENDLOOP; newParts.centroid _ blockPartsA.centroid OR blockPartsB.centroid; aPlusB _ SVAssembly.DescriptorFromParts[partsA.slice, newParts]; }; BlockDifferenceParts: PROC [partsA: SliceDescriptor, partsB: SliceDescriptor] RETURNS [aMinusB: SliceDescriptor] = { blockPartsA: BlockParts _ NARROW[partsA.parts]; blockPartsB: BlockParts _ NARROW[partsB.parts]; newParts: BlockParts; IF partsA = NIL OR partsB = NIL THEN ERROR; IF partsA.parts = NIL THEN RETURN[NIL]; IF partsB.parts = NIL THEN RETURN[partsA]; newParts _ NEW[BlockPartsObj _ [corners: ALL[FALSE], centers: ALL[FALSE], centroid: FALSE, edges: ALL[FALSE], faces: ALL[FALSE] ] ]; FOR i: INTEGER IN [0..8) DO newParts.corners[i] _ IF blockPartsB.corners[i] THEN FALSE ELSE blockPartsA.corners[i]; ENDLOOP; FOR i: INTEGER IN [0..6) DO newParts.centers[i] _ IF blockPartsB.centers[i] THEN FALSE ELSE blockPartsA.centers[i]; newParts.faces[i] _ IF blockPartsB.faces[i] THEN FALSE ELSE blockPartsA.faces[i]; ENDLOOP; FOR i: INTEGER IN [0..12) DO newParts.edges[i] _ IF blockPartsB.edges[i] THEN FALSE ELSE blockPartsA.edges[i]; ENDLOOP; newParts.centroid _ IF blockPartsB.centroid THEN FALSE ELSE blockPartsA.centroid; aMinusB _ SVAssembly.DescriptorFromParts[partsA.slice, newParts]; }; << [Artwork node; type 'Artwork on' to command tool] >> OppositeCorner: PROC [corner: NAT] RETURNS [opposite: NAT] = { SELECT corner FROM IN [0..3] => opposite _ ((corner + 2) MOD 4) + 4; IN [4..7] => opposite _ ((corner + 2) MOD 4); ENDCASE => ERROR; }; CornersOfEdge: PROC [edge: NAT] RETURNS [lo, hi: NAT] = { SELECT edge FROM IN [0..3] => {lo _ edge; hi _ (edge + 1) MOD 4;}; IN [4..7] => {lo _ edge; hi _ ((edge + 1) MOD 4) + 4;}; IN [8..11] => {lo _ edge MOD 4; hi _ (edge MOD 4) + 4;}; ENDCASE => ERROR; }; CornersOfFace: PROC [face: NAT] RETURNS [corners: ARRAY[0..3] OF NAT] = { SELECT face FROM IN [0..1] => FOR i: NAT IN [0..3] DO corners[i] _ i + face*4 ENDLOOP; IN [2..5] => { corners[0] _ face-2; -- 0,1,2,3 corners[1] _ face+2; -- 4,5,6,7 corners[2] _ ((face-1) MOD 4) + 4; -- 5,6,7,4 corners[3] _ (face-1) MOD 4; -- 1,2,3,0 }; ENDCASE => ERROR; }; << [Artwork node; type 'Artwork on' to command tool] >> << [Artwork node; type 'Artwork on' to command tool] >> OppositeEdge: PROC [edge: NAT] RETURNS [opposite: NAT] = { SELECT edge FROM IN [0..3] => opposite _ ((edge + 2) MOD 4) + 4; IN [4..7] => opposite _ ((edge + 2) MOD 4); IN [8..11] => opposite _ ((edge +2) MOD 4) + 8; ENDCASE => ERROR; }; EdgesOfFace: PROC [face: NAT] RETURNS [edgeNums: ARRAY [0..3] OF NAT] = { SELECT face FROM 0, 1 => FOR i: NAT IN [0..3] DO edgeNums[i] _ face*4 + i; ENDLOOP; 2,3,4,5 => { edgeNums[0] _ face-2; -- 0,1,2,3 edgeNums[1] _ face+6; -- 8,9,10,11 edgeNums[3] _ face+2; -- 4,5,6,7 edgeNums[2] _ ((face-1 ) MOD 4) + 8; -- (1,2,3,0) + 8 = 9,10,11,8 }; ENDCASE => ERROR; }; OppositeFace: PROC [face: NAT] RETURNS [opposite: NAT] = { SELECT face FROM IN [0..1] => opposite _ ((face + 1) MOD 2); IN [2..5] => opposite _ ((face + 2) MOD 4); ENDCASE => ERROR; }; BlockMovingParts: PROC [slice: Slice, selectedParts: SliceParts] RETURNS [background, overlay, rubber, drag: SliceDescriptor] = { <> <> <> <> <> <> blockParts: BlockParts _ NARROW[selectedParts]; overlayParts: BlockParts; filled: BOOL _ TRUE; nullD: SliceDescriptor _ SVAssembly.DescriptorFromParts[slice, NIL]; newParts: BlockParts _ NEW[BlockPartsObj _ [corners: ALL[TRUE], centers: ALL[TRUE], centroid: TRUE, edges: ALL[TRUE], faces: ALL[TRUE] ] ]; cornerCount, cornerNum, centerCount, centerNum, edgeCount, edgeNum, faceCount, faceNum: INTEGER; centroidCount: INTEGER _ IF blockParts.centroid THEN 1 ELSE 0; [cornerCount, cornerNum] _ CountCorners[blockParts.corners]; [centerCount, centerNum] _ CountCenters[blockParts.centers]; [edgeCount, edgeNum] _ CountEdges[blockParts.edges]; [faceCount, faceNum] _ CountFaces[blockParts.faces]; IF (cornerCount+centerCount+edgeCount+faceCount)>1 OR centroidCount > 0 THEN { -- everything moving background _ overlay _ rubber _ nullD; drag _ SVAssembly.DescriptorFromParts[slice, newParts]; RETURN; }; IF cornerCount=1 THEN { -- all but the opposite corner newParts.corners[OppositeCorner[cornerNum]] _ FALSE; background _ drag _ nullD; rubber _ SVAssembly.DescriptorFromParts[slice, newParts]; overlayParts _ NEW[BlockPartsObj _ [corners: ALL[FALSE], centers: ALL[FALSE], centroid: FALSE, edges: ALL[FALSE], faces: ALL[FALSE] ] ]; overlayParts.corners[cornerNum] _ TRUE; overlay _ SVAssembly.DescriptorFromParts[slice, overlayParts]; IF NOT filled THEN {background _ overlay; overlay _ nullD}; } ELSE IF edgeCount=1 THEN { -- turn off the opposite edge and two corners wholeD: SliceDescriptor _ SVAssembly.NewParts[slice, NIL, [0,0,0], slice]; lo, hi, oppositeEdge: NAT; oppositeEdge _ OppositeEdge[edgeNum]; [lo, hi] _ CornersOfEdge[oppositeEdge]; newParts.edges[oppositeEdge] _ FALSE; newParts.corners[lo] _ FALSE; newParts.corners[hi] _ FALSE; background _ drag _ nullD; rubber _ SVAssembly.DescriptorFromParts[slice, newParts]; overlay _ BlockDifferenceParts[wholeD, rubber]; IF NOT filled THEN {background _ overlay; overlay _ nullD}; } ELSE { -- nothing is moving background _ SVAssembly.DescriptorFromParts[slice, newParts]; rubber _ overlay _ drag _ nullD; }; }; <<>> BlockCopyParts: PROC [blockParts: BlockParts] RETURNS [copyParts: BlockParts] = { copyParts _ NEW[BlockPartsObj]; copyParts^ _ blockParts^; }; BlockAugmentParts: PUBLIC PROC [sliceD: SliceDescriptor, selectClass: SelectionClass] RETURNS [more: SliceDescriptor] = { <> blockParts: BlockParts _ NARROW[sliceD.parts]; newParts: BlockParts; lo, hi: NAT; edgeNums: ARRAY [0..3] OF NAT; newParts _ BlockCopyParts[blockParts]; FOR i: NAT IN [0..5] DO IF newParts.faces[i] THEN { edgeNums _ EdgesOfFace[i]; FOR j: NAT IN [0..3] DO newParts.edges[edgeNums[j]] _ TRUE; ENDLOOP; }; ENDLOOP; FOR i: NAT IN [0..11] DO IF newParts.edges[i] THEN { [lo, hi] _ CornersOfEdge[i]; newParts.corners[lo] _ TRUE; newParts.corners[hi] _ TRUE; }; ENDLOOP; more _ SVAssembly.DescriptorFromParts[sliceD.slice, newParts]; }; <> <<[-1, 1, 1],>> <<[-1, 1, -1],>> <<[1, 1, -1],>> <<[1, 1, 1],>> <<[-1, -1, 1],>> <<[-1, -1, -1],>> <<[1, -1, -1],>> <<[1, -1, 1]];>> <<>> <> BlockGenData: TYPE = REF BlockGenDataObj; BlockGenDataObj: TYPE = RECORD [ blockParts: BlockParts, blockData: BlockData ]; BlockPointsInDescriptor: PROC [sliceD: SliceDescriptor] RETURNS [pointGen: PointGenerator] = { blockParts: BlockParts _ NARROW[sliceD.parts]; blockData: BlockData _ NARROW[NARROW[sliceD.slice.shape, Shape].mo.mainBody]; blockGenData: BlockGenData; cornerCount, centroidCount: INTEGER; [cornerCount, ----] _ CountCorners[blockParts.corners]; centroidCount _ IF blockParts.centroid THEN 1 ELSE 0; blockGenData _ NEW[BlockGenDataObj _ [blockParts, blockData]]; pointGen _ NEW[PointGeneratorObj _ [ sliceD: sliceD, toGo: MAX[0, cornerCount] + MAX[0, centroidCount], index: 0, classSpecific: blockGenData ]]; }; BlockNextPoint: PROC [pointGen: PointGenerator] RETURNS [pointAndDone: PointAndDone] = { IF pointGen.toGo = 0 THEN pointAndDone _ [[0,0,0], TRUE] ELSE { index: INTEGER; blockGenData: BlockGenData _ NARROW[pointGen.classSpecific]; blockParts: BlockParts _ blockGenData.blockParts; blockData: BlockData _ blockGenData.blockData; FOR index _ pointGen.index, index+1 UNTIL index >=8 DO IF blockParts.corners[index] THEN EXIT; -- index will point to next available point REPEAT FINISHED => { IF NOT blockParts.centroid THEN ERROR; }; ENDLOOP; IF index IN [0..7] THEN pointAndDone.point _ GetBox3dPoint[blockData.box, index] <> ELSE IF index = 8 THEN pointAndDone.point _ GetBox3dCentroid[blockData.box] ELSE ERROR; pointGen.toGo _ pointGen.toGo-1; pointGen.index _ IF pointGen.toGo=0 THEN 99 ELSE index+1; pointAndDone.done _ FALSE; }; }; BlockSegmentsInDescriptor: PROC [sliceD: SliceDescriptor] RETURNS [segGen: SegmentGenerator] = { blockParts: BlockParts _ NARROW[sliceD.parts]; blockData: BlockData _ NARROW[NARROW[sliceD.slice.shape, Shape].mo.mainBody]; blockGenData: BlockGenData; edgeCount: INTEGER; [edgeCount, ----] _ CountEdges[blockParts.edges]; blockGenData _ NEW[BlockGenDataObj _ [blockParts, blockData]]; segGen _ NEW[SegmentGeneratorObj _ [ toGo: MAX[0, edgeCount], index: 0, data: blockGenData ]]; }; BlockNextSegment: PROC [segGen: SegmentGenerator] RETURNS [segment: Segment] = { IF segGen.toGo = 0 THEN RETURN[NIL] ELSE { blockGenData: BlockGenData _ NARROW[segGen.data]; blockParts: BlockParts _ blockGenData.blockParts; blockData: BlockData _ blockGenData.blockData; index: INTEGER; FOR index _ segGen.index, index+1 UNTIL index >=12 DO IF blockParts.edges[index] THEN EXIT; -- index will point to next available point REPEAT FINISHED => { ERROR; }; ENDLOOP; segment _ blockData.segments[index]; segGen.toGo _ segGen.toGo - 1; segGen.index _ IF segGen.toGo=0 THEN 99 ELSE index+1; }; }; SegAndIndex: TYPE = RECORD [ seg: Segment, index: INTEGER ]; BlockNextSegmentAndIndex: PROC [segGen: SegmentGenerator] RETURNS [next: SegAndIndex] = { IF segGen.toGo = 0 THEN RETURN[[NIL, -1]] ELSE { blockGenData: BlockGenData _ NARROW[segGen.data]; blockParts: BlockParts _ blockGenData.blockParts; blockData: BlockData _ blockGenData.blockData; index: INTEGER; FOR index _ segGen.index, index+1 UNTIL index >=12 DO IF blockParts.edges[index] THEN EXIT; -- index will point to next available point REPEAT FINISHED => { ERROR; }; ENDLOOP; next.seg _ blockData.segments[index]; next.index _ index; segGen.toGo _ segGen.toGo - 1; segGen.index _ IF segGen.toGo=0 THEN 99 ELSE index+1; }; }; <<>> <> NearestBlockPoint: PROC [slice: Slice, point: Point3d] RETURNS [cornerIndex, centerIndex, centroid: INT, bestPoint: Point3d, bestDist: REAL] = { <> mo: MasterObject; pointGen: PointGenerator; wholeD: SliceDescriptor; shape: Shape; shape _ NARROW[slice.shape]; mo _ shape.mo; wholeD _ SVAssembly.NewParts[slice, NIL, [0,0,0], slice]; pointGen _ mo.class.pointsInDescriptor[wholeD]; BEGIN thisDist: REAL; thisPoint: Point3d; bestCount, thisCount: NAT; thisCount _ 0; bestDist _ Real.LargestNumber; bestCount _ LAST[NAT]; FOR pointAndDone: PointAndDone _ SVAssembly.NextPoint[pointGen], SVAssembly.NextPoint[pointGen] UNTIL pointAndDone.done DO thisPoint _ pointAndDone.point; thisDist _ SVVector3d.Distance[thisPoint, point]; IF thisDist < bestDist THEN { bestDist _ thisDist; bestPoint _ thisPoint; bestCount _ thisCount; }; thisCount _ thisCount + 1; ENDLOOP; IF bestCount IN [0..7] THEN {cornerIndex _ bestCount; centerIndex _ -1; centroid _ -1} ELSE IF bestCount = 8 THEN {cornerIndex _ -1; centerIndex _ -1; centroid _ 0} ELSE ERROR; END; }; BlockClosestPointToPoint: PROC [sliceD: SliceDescriptor, testPoint: Point3d, criticalR: REAL] RETURNS [bestDist: REAL, pointWORLD: Point3d, hitData: REF ANY, success: BOOL _ TRUE] = { cornerIndex, centerIndex, centroid: INTEGER; [cornerIndex, centerIndex, centroid, pointWORLD, bestDist] _ NearestBlockPoint[sliceD.slice, testPoint]; hitData _ NEW[BlockHitDataObj _ [corner: cornerIndex, center: centerIndex, centroid: centroid, hitPoint: pointWORLD]]; }; PointIsInBox: PROC [cameraPoint: Point2d, boundBox: SVBasicTypes.BoundBoxObj] RETURNS [BOOL] = { <> IF boundBox.infinite THEN RETURN[TRUE]; -- NIL means infinite IF boundBox.null THEN RETURN[FALSE]; RETURN[ boundBox.loX <= cameraPoint[1] AND cameraPoint[1]<=boundBox.hiX AND boundBox.loY <= cameraPoint[2] AND cameraPoint[2]<=boundBox.hiY] }; -- end of PointIsInBox useBBoxes: BOOL _ TRUE; BlockClosestPointToLine: PROC [sliceD: SliceDescriptor, cameraPoint: Point2d, line3d: Line3d, criticalR: REAL, camera: Camera] RETURNS [bestDist: REAL, pointWORLD: Point3d, hitData: REF ANY, success: BOOL _ FALSE] = { moWORLD: Matrix4by4; pointGen: PointGenerator; shape: Shape; thisDist: REAL; thisPoint: Point3d; bestCount, count: NAT _ 0; corner, centroid: INTEGER; sliceBBox: BoundBox _ SVAssembly.GetBoundBox[sliceD.slice, sliceD.parts, camera]; toleranceBox: SVBasicTypes.BoundBoxObj; toleranceBox _ [sliceBBox.loX-criticalR, sliceBBox.loY-criticalR, sliceBBox.hiX+criticalR, sliceBBox.hiY+criticalR, FALSE, FALSE]; IF NOT useBBoxes OR PointIsInBox[cameraPoint, toleranceBox] THEN { <> shape _ NARROW[sliceD.slice.shape]; moWORLD _ CoordSys.WRTWorld[shape.coordSys]; bestDist _ Real.LargestNumber; pointGen _ BlockPointsInDescriptor[sliceD]; FOR pointAndDone: PointAndDone _ BlockNextPoint[pointGen], BlockNextPoint[pointGen] UNTIL pointAndDone.done = TRUE DO thisPoint _ Matrix3d.Update[pointAndDone.point, moWORLD]; thisDist _ SVLines3d.DistancePointToLine[thisPoint, line3d]; IF thisDist < bestDist THEN { bestDist _ thisDist; pointWORLD _ thisPoint; bestCount _ count; }; count _ count + 1; ENDLOOP; IF bestCount IN [0..7] THEN {corner _ bestCount; centroid _ -1} ELSE IF bestCount = 8 THEN {corner _ -1; centroid _ 0} ELSE ERROR; success _ TRUE; hitData _ NEW[BlockHitDataObj _ [corner: corner, centroid: centroid, hitPoint: pointWORLD]]; } }; SegmentGenerator: TYPE = REF SegmentGeneratorObj; SegmentGeneratorObj: TYPE = RECORD [ data: REF ANY, index: NAT, toGo: NAT ]; Segment: TYPE = REF SegmentObj; SegmentObj: TYPE = SVMasterObjectTypes.SegmentObj; SegmentAndDone: TYPE = RECORD[ seg: Segment, done: BOOL ]; BlockClosestSegmentToLine: PROC [sliceD: SliceDescriptor, cameraPoint: Point2d, line3d: Line3d, criticalR: REAL, camera: Camera] RETURNS [bestDist: REAL, pointWORLD: Point3d, hitData: REF ANY, success: BOOL _ FALSE] = { moWORLD: Matrix4by4; segGen: SegmentGenerator; thisDist: REAL; thisPoint: Point3d; bestCount: NAT _ 0; lo, hi: NAT; sliceBBox: BoundBox _ SVAssembly.GetBoundBox[sliceD.slice, sliceD.parts, camera]; toleranceBox: SVBasicTypes.BoundBoxObj; toleranceBox _ [sliceBBox.loX-criticalR, sliceBBox.loY-criticalR, sliceBBox.hiX+criticalR, sliceBBox.hiY+criticalR, FALSE, FALSE]; IF NOT useBBoxes OR PointIsInBox[cameraPoint, toleranceBox] THEN { shape: Shape _ NARROW[sliceD.slice.shape]; blockData: BlockData _ NARROW[shape.mo.mainBody]; moWORLD _ CoordSys.WRTWorld[shape.coordSys]; bestDist _ Real.LargestNumber; segGen _ BlockSegmentsInDescriptor[sliceD]; FOR next: SegAndIndex _ BlockNextSegmentAndIndex[segGen], BlockNextSegmentAndIndex[segGen] UNTIL next.seg = NIL DO [lo, hi] _ CornersOfEdge[next.index]; SVLines3d.FillEdge[GetBox3dPoint[blockData.box, lo], GetBox3dPoint[blockData.box, hi], next.seg.edge]; SVLines3d.FillEdgeTransform[next.seg.edge, moWORLD, next.seg.edge]; [thisDist, thisPoint] _ SVLines3d.DistanceAndPointLineToEdge[line3d, next.seg.edge]; IF thisDist < bestDist THEN { bestDist _ thisDist; pointWORLD _ thisPoint; bestCount _ next.index; }; ENDLOOP; success _ TRUE; hitData _ NEW[BlockHitDataObj _ [edge: bestCount, hitPoint: pointWORLD]]; }; }; <> BlockUpdate: PUBLIC PROC [mo: MasterObject, updateData: REF ANY] = {}; BuildBoxClass: PROC RETURNS [class: MasterObjectClass] = { class _ NEW[MasterObjectClassObj _ [ name: "box", <> getHedron: BoxBoundHedron, <> lineDraw: BoxLineDraw, normalsDraw: NoOpNormalsDraw, preprocess: NoOpPreprocess, rayCast: NoOpRayCast, rayCastNoBBoxes: NoOpRayCastNoBBoxes, rayCastBoundingSpheres: NoOpRayCastBoundingSpheres, drawSurf: NoOpDrawPlanarSurface, drawSubBoxes: NoOpDrawSubBoxes, drawSubSpheres: NoOpDrawSubSpheres, <> describe: NoOpDescribe, describeHit: NoOpDescribeHit, filein: NoOpFilein, fileout: NoOpFileout, fileoutPoly: NoOpFileoutPoly, <> countSurf: NoOpCountPlanarSurfaces, getSurf: NoOpGetPlanarSurfaces, emptyParts: NoOpEmptyParts, newParts: NoOpNewParts, unionParts: NoOpUnionParts, differenceParts: NoOpDifferenceParts, movingParts: NoOpMovingParts, augmentParts: NoOpAugmentParts, <> pointsInDescriptor: NoOpPointsInDescriptor, nextPoint: NoOpNextPoint, <> closestPointToPoint: NoOpClosestPointToPoint, closestPointToLine: NoOpClosestPointToLine, closestSegmentToLine: NoOpClosestSegmentToLine, <> update: NoOpUpdate ]]; }; BoxRec: TYPE = REF BoxRecObj; BoxRecObj: TYPE = RECORD [ poly: Poly3d, bBox: BoundBox ]; BoxBody: PROC [w, h: REAL] RETURNS [boxRec: BoxRec] = { <> boxRec _ NEW[BoxRecObj]; boxRec.poly _ SVPolygon3d.CreatePoly[len: 4]; boxRec.poly _ SVPolygon3d.AddPolyPoint[boxRec.poly, [0,0,0]]; boxRec.poly _ SVPolygon3d.AddPolyPoint[boxRec.poly, [0,h,0]]; boxRec.poly _ SVPolygon3d.AddPolyPoint[boxRec.poly, [w,h,0]]; boxRec.poly _ SVPolygon3d.AddPolyPoint[boxRec.poly, [w,0,0]]; boxRec.bBox _ SVBoundBox.BoundBoxFromValues[0,0,w,h]; }; BoxMakeMasterObject: PUBLIC PROC [name: Rope.ROPE, w, h: REAL] RETURNS [mo: MasterObject] = { mainBody: BoxRec _ BoxBody[w, h]; lineBody: REF ANY _ mainBody; shadeBody: REF ANY _ mainBody; rayCastBody: REF ANY _ mainBody; mo _ SVScene.CreateMasterObject[name, blockClass, mainBody, lineBody, shadeBody, rayCastBody]; }; BoxBoundHedron: PUBLIC PROC [mo: MasterObject] RETURNS [hedron: BoundHedron] = { boxRec: BoxRec; bBox: BoundBox; boxRec _ NARROW[mo.mainBody]; bBox _ boxRec.bBox; hedron _ SVBoundBox.RectangularBoundHedron2[bBox.loX,bBox.hiX,bBox.loY,bBox.hiY,0,0]; }; BoxLineDraw: PUBLIC PROC [slice: Slice, dc: Imager.Context, camera: Camera] = { mo: MasterObject _ NARROW[slice.shape, Shape].mo; localCS: CoordSystem _ slice.coordSys; boxRec: BoxRec _ NARROW[mo.lineBody]; poly: Poly3d _ boxRec.poly; localCamera: Matrix4by4 _ CoordSys.WRTCamera[localCS, camera.coordSys]; SVGraphics.SetCP[dc, poly[0], camera, localCamera]; SVGraphics.DrawTo[dc, poly[1], camera, localCamera]; SVGraphics.DrawTo[dc, poly[2], camera, localCamera]; SVGraphics.DrawTo[dc, poly[3], camera, localCamera]; SVGraphics.DrawTo[dc, poly[0], camera, localCamera]; }; blockClass, boxClass: MasterObjectClass; Init: PROC = { block: MasterObject; blockClass _ BuildBlockClass[]; SVMasterObject.RegisterMasterObjectClass[blockClass]; block _ BlockMakeMasterObject["block"]; RegisterMasterObject[block]; boxClass _ BuildBoxClass[]; SVMasterObject.RegisterMasterObjectClass[boxClass]; }; Init[]; END.