DIRECTORY CoordSys, SVGraphics, Imager, SV2d, SV3d, SVAssembly, SVBasicTypes, SVBoundBox, SVModelTypes, SVPolygon3d, SVSceneTypes, SVSelect, SVVector3d; SVBoundBoxImpl: CEDAR PROGRAM IMPORTS CoordSys, 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, CoordSys.WRTCamera[localWRTWorld, camera.coordSys]]; SVGraphics.DrawTo[dc, bh[j], camera, CoordSys.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 _ CoordSys.ScreenToCamera[[bBox.loX, bBox.loY], camera.screenCS]; hi _ CoordSys.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 _ CoordSys.CameraToScreen[[boundBox.loX, boundBox.loY], screen]; upperLeft _ CoordSys.CameraToScreen[[boundBox.loX, boundBox.hiY], screen]; upperRight _ CoordSys.CameraToScreen[[boundBox.hiX, boundBox.hiY], screen]; lowerRight _ CoordSys.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 _ CoordSys.CameraToScreen[[boundBox.loX, boundBox.loY], screen]; upperRight _ CoordSys.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 _ CoordSys.CameraToScreen[[bBox.loX, bBox.loY], screen]; upperRight _ CoordSys.CameraToScreen[[bBox.hiX, bBox.hiY], screen]; Imager.ClipRectangle[dc, [lowerLeft[1], lowerLeft[2], (upperRight[1]-lowerLeft[1]), (upperRight[2]-lowerLeft[2])]]; }; Min: PROC [a, b: REAL] RETURNS [REAL] = { RETURN[IF a < b THEN a ELSE b]; }; Max: PROC [a, b: REAL] RETURNS [REAL] = { RETURN[IF a > b THEN a ELSE b]; }; END. ’File: SVBoundBoxImpl.mesa Last edited by Bier on June 1, 1987 10:38:38 am PDT Copyright c 1984 by Xerox Corporation. All rights reserved. Contents: Procedures for creating bounding polyhedra of master objects, and for deriving "3-d" bounding boxes from these polyhedra. Procedures for combining these bounding boxes with union, intersection and difference operators. Creating a BoundHedron A pyramid with base of size sx by sz on the y=0 plane and tip at [0, sy, 0]. A pyramid having base a hexagon around the circle (of radius r centered on [0, 0, 0] on the y=0 plane) and having tip at [0, h, 0]. Bounds a cone slice (cone around y axis) with radius r1 at y=h1 and radius r2 at y = h2. Currently uses two hexagons. Octagons may follow. Bounds a disk (centered on y axis) with radius r at y = h; A boundHedron is expressed in local coordinates. For now, draw a line from each point to every other. Find the average of all of the points in the boundhedron. For each point of the bound hedron, find its perspective or orthogonal projection into camera coordinates. Do not project z. Find min x, y, z and max x, y, z as you go. Initialize minX, minY, and minZ to the values for the first boundhedron point. Now look at the rest of the points. Creating a BoundBox routine called to calculate the boundBox of all objects that are about to move; that is, all selected slices, selected CPs, selected joints AND the dangling segments of selected joints AND the segments of selected CPs. Boundbox is in camera coords so this is easy. Bound box is in perspective camera coords. Convert to screen and draw. Bound box is in perspective camera coords. Convert to screen and draw. Κ Ν– "cedar" style˜Iheadšœ™Iprocšœ3™3Jšœ Οmœ1™˜OLšœ˜Mšžœ žœžœ˜Mšžœžœžœ˜LšœB˜BLšœC˜CMšœs˜sM˜Lšœ˜—š Ÿœžœžœžœžœ˜)Lšžœžœžœžœ˜Lšœ˜L˜—š Ÿœžœžœžœžœ˜)Lšžœžœžœžœ˜Lšœ˜—L˜Lšžœ˜—…—/’D