<> <> <> <> DIRECTORY SVCoordSys, SVGraphics, Imager, SV2d, SV3d, SVAssembly, SVBasicTypes, SVBoundBox, SVModelTypes, SVPolygon3d, SVSceneTypes, SVSelect, SVVector3d; SVBoundBoxImpl: CEDAR PROGRAM IMPORTS SVCoordSys, SVGraphics, Imager, SVAssembly, SVPolygon3d, SVSelect, SVVector3d EXPORTS SVBoundBox = BEGIN BoundBox: TYPE = REF BoundBoxObj; BoundBoxObj: TYPE = SVBasicTypes.BoundBoxObj; BoundHedron: TYPE = REF BoundHedronObj; BoundHedronObj: TYPE = SVBasicTypes.BoundHedronObj; Camera: TYPE = SVModelTypes.Camera; CoordSystem: TYPE = SVModelTypes.CoordSystem; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; PointSetOp: TYPE = SVSceneTypes.PointSetOp; Poly3d: TYPE = SV3d.Poly3d; Scene: TYPE = SVSceneTypes.Scene; SelectionClass: TYPE = SVSelect.SelectionClass; SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = SVSceneTypes.SliceDescriptorGenerator; Vector3d: TYPE = SV3d.Vector3d; <> CreateBoundHedron: PUBLIC PROC [len: NAT] RETURNS [bh: BoundHedron] = { bh _ NEW[BoundHedronObj[len]]; bh.len _ 0; }; AddBoundHedronPoint: PUBLIC PROC [bh: BoundHedron, point: Point3d] = { IF bh.len = bh.maxVerts THEN ERROR ELSE { bh[bh.len] _ point; bh.len _ bh.len + 1; }; }; -- end of AddBoundHedronPoint AddBoundHedronPoly: PUBLIC PROC [bh: BoundHedron, poly: Poly3d] = { FOR i: NAT IN[0..poly.len) DO AddBoundHedronPoint[bh, poly[i]]; ENDLOOP; }; RectangularBoundHedron: PUBLIC PROC [sx, sy, sz: REAL] RETURNS [bh: BoundHedron] = { sx2, sy2, sz2: REAL; sx2 _ sx/2; sy2 _ sy/2; sz2 _ sz/2; bh _ CreateBoundHedron[8]; AddBoundHedronPoint[bh, [-sx2, sy2, sz2]]; AddBoundHedronPoint[bh, [-sx2, sy2, -sz2]]; AddBoundHedronPoint[bh, [sx2, sy2, -sz2]]; AddBoundHedronPoint[bh, [sx2, sy2, sz2]]; AddBoundHedronPoint[bh, [-sx2, -sy2, sz2]]; AddBoundHedronPoint[bh, [-sx2, -sy2, -sz2]]; AddBoundHedronPoint[bh, [sx2, -sy2, -sz2]]; AddBoundHedronPoint[bh, [sx2, -sy2, sz2]]; }; -- end of RectangularBoundHedron RectangularBoundHedron2: PUBLIC PROC [x1, x2, y1, y2, z1, z2: REAL] RETURNS [bh: BoundHedron] = { bh _ CreateBoundHedron[8]; AddBoundHedronPoint[bh, [x1, y2, z2]]; AddBoundHedronPoint[bh, [x1, y2, z1]]; AddBoundHedronPoint[bh, [x2, y2, z1]]; AddBoundHedronPoint[bh, [x2, y2, z2]]; AddBoundHedronPoint[bh, [x1, y1, z2]]; AddBoundHedronPoint[bh, [x1, y1, z1]]; AddBoundHedronPoint[bh, [x2, y1, z1]]; AddBoundHedronPoint[bh, [x2, y1, z2]]; }; -- end of RectangularBoundHedron2 PyramidBoundHedron: PUBLIC PROC [sx, sy, sz: REAL] RETURNS [bh: BoundHedron] = { <> sx2, sz2: REAL; sx2 _ sx/2; sz2 _ sz/2; bh _ CreateBoundHedron[5]; AddBoundHedronPoint[bh, [-sx2, 0, sz2]]; AddBoundHedronPoint[bh, [-sx2, 0, -sz2]]; AddBoundHedronPoint[bh, [sx2, 0, -sz2]]; AddBoundHedronPoint[bh, [sx2, 0, sz2]]; AddBoundHedronPoint[bh, [0, sy, 0]]; }; -- end of PyramidBoundHedron HexagonalBoundHedron: PUBLIC PROC [r, hOver2: REAL] RETURNS [bh: BoundHedron] = { topPoly, bottomPoly: Poly3d; bh _ CreateBoundHedron[12]; topPoly _ SVPolygon3d.CircumHexagon[hOver2, r]; bottomPoly _ SVPolygon3d.CircumHexagon[-hOver2, r]; AddBoundHedronPoly[bh, topPoly]; AddBoundHedronPoly[bh, bottomPoly]; }; HexPyramidBoundHedron: PUBLIC PROC [r, h: REAL] RETURNS [bh: BoundHedron] = { <> base: Poly3d; base _ SVPolygon3d.CircumHexagon[0, r]; bh _ CreateBoundHedron[7]; AddBoundHedronPoly[bh, base]; AddBoundHedronPoint[bh, [0, h, 0]]; }; -- end of HexPyramidBoundHedron GeneralConeBoundHedron: PUBLIC PROC [r1, h1, r2, h2: REAL] RETURNS [bh: BoundHedron] = { <> poly: Poly3d; bh _ CreateBoundHedron[12]; poly _ SVPolygon3d.CircumHexagon[h1, r1]; AddBoundHedronPoly[bh, poly]; poly _ SVPolygon3d.CircumHexagon[h2, r2]; AddBoundHedronPoly[bh, poly]; }; -- end of GeneralConeBoundHedron DiskBoundHedron: PUBLIC PROC [r, h: REAL] RETURNS [bh: BoundHedron] = { <> poly: Poly3d; bh _ CreateBoundHedron[6]; poly _ SVPolygon3d.CircumHexagon[h, r]; AddBoundHedronPoly[bh, poly]; }; -- end of DiskBoundHedron ClearBoundHedron: PUBLIC PROC [bh: BoundHedron] = { bh.len _ 0; }; DrawBoundHedron: PUBLIC PROC [dc: Imager.Context, bh: BoundHedron, localWRTWorld: CoordSystem, camera: Camera, screen: CoordSystem] = { <> <> FOR i: NAT IN[0..bh.len) DO FOR j: NAT IN[0..bh.len) DO IF i#j THEN { SVGraphics.SetCP[dc, bh[i], camera, SVCoordSys.WRTCamera[localWRTWorld, camera.coordSys]]; SVGraphics.DrawTo[dc, bh[j], camera, SVCoordSys.WRTCamera[localWRTWorld, camera.coordSys]];}; ENDLOOP; ENDLOOP; }; CenterOfMassBoundHedron: PUBLIC PROC [bh: BoundHedron] RETURNS [cm: Point3d] = { <> sum: Vector3d; realLen: REAL; sum _ [0,0,0]; FOR i: NAT IN[0..bh.len) DO sum _ SVVector3d.Add[sum, bh[i]]; ENDLOOP; realLen _ bh.len; cm _ SVVector3d.Scale[sum, 1.0/realLen]; }; BoundBoxFromBoundHedron: PUBLIC PROC [bh: BoundHedron, camera: Camera, localCS: CoordSystem] RETURNS [boundBox: BoundBox] = { IF bh = NIL THEN {boundBox _ NIL; RETURN}; boundBox _ NEW[BoundBoxObj]; FillBoundBoxFromBoundHedron[bh, camera, localCS, boundBox]; }; FillBoundBoxFromBoundHedron: PUBLIC PROC [bh: BoundHedron, camera: Camera, localCS: CoordSystem, boundBox: BoundBox] = { <> minX, minY, maxX, maxY: REAL; localPt, cameraPt: Point3d; projectPt: Point2d; IF bh = NIL THEN {boundBox.infinite _ TRUE; RETURN}; <> localPt _ bh[0]; cameraPt _ SVGraphics.LocalToCamera[localPt, localCS, camera.coordSys]; projectPt _ SVGraphics.DoProjection[cameraPt, camera]; minX _ maxX _ projectPt[1]; minY _ maxY _ projectPt[2]; <> FOR i: NAT IN[1..bh.len) DO localPt _ bh[i]; cameraPt _ SVGraphics.LocalToCamera[localPt, localCS, camera.coordSys]; projectPt _ SVGraphics.DoProjection[cameraPt, camera]; IF projectPt[1] < minX THEN minX _ projectPt[1] ELSE IF projectPt[1] > maxX THEN maxX _ projectPt[1]; IF projectPt[2] < minY THEN minY _ projectPt[2] ELSE IF projectPt[2] > maxY THEN maxY _ projectPt[2]; ENDLOOP; boundBox.loX _ minX; boundBox.loY _ minY; boundBox.hiX _ maxX; boundBox.hiY _ maxY; boundBox.null _ boundBox.infinite _ FALSE; }; -- end of BoundBoxFromBoundHedron <> BoundBoxFromValues: PUBLIC PROC [minX, minY, maxX, maxY: REAL] RETURNS [boundBox: BoundBox] = { boundBox _ NEW[BoundBoxObj]; boundBox.loX _ minX; boundBox.loY _ minY; boundBox.hiX _ maxX; boundBox.hiY _ maxY; boundBox.null _ boundBox.infinite _ FALSE; }; -- end of BoundBoxFromValues BoundBoxFromRectangle: PUBLIC PROC [rect: Imager.Rectangle, camera: Camera] RETURNS [bBox: BoundBox] = { lo, hi: Point2d; bBox _ NEW[BoundBoxObj _ [rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, FALSE, FALSE]]; lo _ SVCoordSys.ScreenToCamera[[bBox.loX, bBox.loY], camera.screenCS]; hi _ SVCoordSys.ScreenToCamera[[bBox.hiX, bBox.hiY], camera.screenCS]; bBox.loX _ lo[1]; bBox.loY _ lo[2]; bBox.hiX _ hi[1]; bBox.hiY _ hi[2]; }; NullBoundBox: PUBLIC PROC [] RETURNS [bBox: BoundBox] = { bBox _ NEW[BoundBoxObj _ [0,0,0,0, TRUE, FALSE]]; }; EnlargeByBox: PUBLIC PROC [bBox: BoundBox, by: BoundBox] = { IF bBox.infinite OR by.null THEN RETURN; IF by.infinite THEN {bBox.infinite _ TRUE; bBox.null _ FALSE; RETURN}; IF bBox.null THEN {bBox^ _ by^; RETURN}; bBox.loX _ MIN[bBox.loX, by.loX]; bBox.hiX _ MAX[bBox.hiX, by.hiX]; bBox.loY _ MIN[bBox.loY, by.loY]; bBox.hiY _ MAX[bBox.hiY, by.hiY]; }; BoundBoxOfMoving: PUBLIC PROC [scene: Scene, camera: Camera] RETURNS [bigBox: BoundBox] = { <> sGen: SliceDescriptorGenerator; sliceD: SliceDescriptor; nextBox: BoundBox; bigBox _ NullBoundBox[]; sGen _ SVSelect.SelectedSlices[scene, normal]; FOR sliceD _ SVSelect.NextSliceDescriptor[sGen], SVSelect.NextSliceDescriptor[sGen] UNTIL sliceD = NIL DO overlay, rubber, drag, movingParts: SliceDescriptor; [----, overlay, rubber, drag] _ SVAssembly.MovingParts[sliceD.slice, sliceD.parts]; movingParts _ SVAssembly.UnionParts[overlay, rubber]; movingParts _ SVAssembly.UnionParts[movingParts, drag]; nextBox _ SVAssembly.GetBoundBox[sliceD.slice, movingParts.parts, camera]; EnlargeByBox[bBox: bigBox, by: nextBox]; ENDLOOP; }; BoundBoxOfSelected: PUBLIC PROC [scene: Scene, camera: Camera, selectClass: SelectionClass] RETURNS [bigBox: BoundBox] = { sGen: SliceDescriptorGenerator; nextBox: BoundBox; bigBox _ NullBoundBox[]; sGen _ SVSelect.SelectedSlices[scene, selectClass]; FOR sliceD: SliceDescriptor _ SVSelect.NextSliceDescriptor[sGen], SVSelect.NextSliceDescriptor[sGen] UNTIL sliceD = NIL DO nextBox _ SVAssembly.GetBoundBox[sliceD.slice, sliceD.parts, camera]; EnlargeByBox[bBox: bigBox, by: nextBox]; ENDLOOP; }; PointInBoundBox: PUBLIC PROC [cameraPoint: Point2d, boundBox: BoundBox] RETURNS [BOOL] = { <> IF boundBox = NIL OR 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 PointInBoundBox UnionCombineBoundBoxes: PUBLIC PROC [bb1, bb2: BoundBox] RETURNS [newBB: BoundBox] = { IF bb1 = NIL OR bb2 = NIL THEN {newBB _ NIL; RETURN}; newBB _ NEW[BoundBoxObj]; newBB.loX _ bb2.loX; newBB.loX _ MIN[bb1.loX, bb2.loX]; newBB.hiX _ MAX[bb1.hiX, bb2.hiX]; newBB.loY _ bb2.loY; newBB.loY _ MIN[bb1.loY, bb2.loY]; newBB.hiY _ MAX[bb1.hiY, bb2.hiY]; }; -- end of UnionCombineBoundBoxes IntersectionCombineBoundBoxes: PUBLIC PROC [bb1, bb2: BoundBox] RETURNS [newBB: BoundBox] = { IF bb1 = NIL AND bb2 = NIL THEN {newBB _ NIL; RETURN}; newBB _ NEW[BoundBoxObj]; SELECT TRUE FROM bb1 = NIL => { newBB.loX _ bb2.loX; newBB.hiX _ bb2.hiX; newBB.loY _ bb2.loY; newBB.hiY _ bb2.hiY; }; bb2 = NIL => { newBB.loX _ bb1.loX; newBB.hiX _ bb1.hiX; newBB.loY _ bb1.loY; newBB.hiY _ bb1.hiY; }; ENDCASE => { newBB.loX _ MAX[bb1.loX, bb2.loX]; newBB.hiX _ MIN[bb1.hiX, bb2.hiX]; newBB.loY _ MAX[bb1.loY, bb2.loY]; newBB.hiY _ MIN[bb1.hiY, bb2.hiY]; }; }; -- end of IntersectionCombineBoundBoxes DifferenceCombineBoundBoxes: PUBLIC PROC [bb1, bb2: BoundBox] RETURNS [newBB: BoundBox] = { IF bb1 = NIL THEN {newBB _ NIL; RETURN}; newBB _ NEW[BoundBoxObj]; newBB.loX _ bb1.loX; newBB.hiX _ bb1.hiX; newBB.loY _ bb1.loY; newBB.hiY _ bb1.hiY; }; -- end of DifferenceCombineBoundBoxes OutsideOf: PUBLIC PROC [test, bound: BoundBox] RETURNS [BOOL] = { RETURN[ test.hiX < bound.loX OR test.loX > bound.hiX OR test.hiY < bound.loY OR test.loY > bound.hiY ]; }; DrawBoundBox: PUBLIC PROC [dc: Imager.Context, boundBox: BoundBox, screen: CoordSystem] = { <> lowerLeft, upperLeft, upperRight, lowerRight: Point2d; RectanglePath: Imager.PathProc = { moveTo[[lowerLeft[1], lowerLeft[2]]]; lineTo[[upperLeft[1], upperLeft[2]]]; lineTo[[ upperRight[1], upperRight[2]]]; lineTo[[ lowerRight[1], lowerRight[2]]]; lineTo[[lowerLeft[1], lowerLeft[2]]]; }; IF boundBox = NIL OR boundBox.null OR boundBox.infinite THEN RETURN; lowerLeft _ SVCoordSys.CameraToScreen[[boundBox.loX, boundBox.loY], screen]; upperLeft _ SVCoordSys.CameraToScreen[[boundBox.loX, boundBox.hiY], screen]; upperRight _ SVCoordSys.CameraToScreen[[boundBox.hiX, boundBox.hiY], screen]; lowerRight _ SVCoordSys.CameraToScreen[[boundBox.hiX, boundBox.loY], screen]; Imager.SetStrokeWidth[dc, 1.0]; Imager.MaskStroke[dc, RectanglePath, TRUE]; }; -- end of DrawBoundBox EraseWithinBoundBox: PUBLIC PROC [dc: Imager.Context, boundBox: BoundBox, screen: CoordSystem] = { <> EraseWithinBoundBoxAux: PROC = { rect: Imager.Rectangle _ [x: lowerLeft[1], y: lowerLeft[2], w: upperRight[1]-lowerLeft[1], h: upperRight[2]-lowerLeft[2]]; Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, rect]; }; lowerLeft, upperRight: Point2d; IF boundBox = NIL OR boundBox.null OR boundBox.infinite THEN RETURN; lowerLeft _ SVCoordSys.CameraToScreen[[boundBox.loX, boundBox.loY], screen]; upperRight _ SVCoordSys.CameraToScreen[[boundBox.hiX, boundBox.hiY], screen]; Imager.DoSaveAll[dc, EraseWithinBoundBoxAux]; }; -- end of DrawBoundBox Clip: PUBLIC PROC [dc: Imager.Context, bBox: BoundBox, screen: CoordSystem] = { lowerLeft, upperRight: Point2d; IF bBox.null THEN ERROR; IF bBox.infinite THEN RETURN; lowerLeft _ SVCoordSys.CameraToScreen[[bBox.loX, bBox.loY], screen]; upperRight _ SVCoordSys.CameraToScreen[[bBox.hiX, bBox.hiY], screen]; Imager.ClipRectangle[dc, [lowerLeft[1], lowerLeft[2], (upperRight[1]-lowerLeft[1]), (upperRight[2]-lowerLeft[2])]]; }; END.