<> <> <> <> <> <> <> <<>> DIRECTORY GGCoreTypes, GGBoundBox, Imager, ImagerTransformation, Lines2d, Real, RealFns, Vectors2d; GGBoundBoxImpl: CEDAR PROGRAM IMPORTS Imager, ImagerTransformation, Lines2d, Real, RealFns, Vectors2d EXPORTS GGBoundBox = BEGIN BoundBox: TYPE = REF BoundBoxObj; BoundBoxObj: TYPE = GGCoreTypes.BoundBoxObj; Edge: TYPE = GGCoreTypes.Edge; MaskArray: TYPE = GGBoundBox.MaskArray; Point: TYPE = Imager.VEC; Vector: TYPE = Imager.VEC; <> CreateBoundBox: PUBLIC PROC [loX, loY, hiX, hiY: REAL, null: BOOL _ FALSE, infinite: BOOL _ FALSE] RETURNS [bBox: BoundBox] = { bBox _ NEW[BoundBoxObj _ [loX, loY, hiX, hiY, null, infinite]]; }; NullBoundBox: PUBLIC PROC [] RETURNS [bBox: BoundBox] = { bBox _ NEW[BoundBoxObj _ [0,0,0,0, TRUE, FALSE]]; }; CopyBoundBox: PUBLIC PROC [bBox: BoundBox] RETURNS [copy: BoundBox] = { copy _ NEW[BoundBoxObj _ [bBox.loX, bBox.loY, bBox.hiX, bBox.hiY, bBox.null, bBox.infinite]]; }; UpdateCopyBoundBox: PUBLIC PROC [bBox: BoundBox, from: BoundBox] = { bBox^ _ from^; }; BoundBoxOfBoxes: PUBLIC PROC [list: LIST OF BoundBox] RETURNS [bigBox: BoundBox] = { bigBox _ NEW[BoundBoxObj]; WHILE list # NIL AND list.first.null DO list _ list.rest ENDLOOP; IF list = NIL THEN {bigBox.null _ TRUE; bigBox.infinite _ FALSE; RETURN}; CopyContents[bigBox, list.first]; FOR bBoxList: LIST OF BoundBox _ list.rest, bBoxList.rest UNTIL bBoxList = NIL DO IF bBoxList.first.infinite THEN {bigBox.null _ FALSE; bigBox.infinite _ TRUE; RETURN}; EnlargeByBox[bBox: bigBox, by: bBoxList.first]; ENDLOOP; }; BoundBoxOfBoundBox: PUBLIC PROC [box: BoundBox, transform: ImagerTransformation.Transformation] RETURNS [newBox: BoundBox] = { rect: Imager.Rectangle _ RectangleFromBoundBox[box]; rect _ ImagerTransformation.TransformRectangle[transform, rect]; newBox _ BoundBoxFromRectangle[rect]; }; UpdateBoundBoxOfBoundBox: PUBLIC PROC [bBox: BoundBox, localBox: BoundBox, transform: ImagerTransformation.Transformation] = { rect: Imager.Rectangle _ RectangleFromBoundBox[localBox]; rect _ ImagerTransformation.TransformRectangle[transform, rect]; UpdateBoundBoxFromRectangle[bBox, rect]; }; BoundBoxFromRectangle: PUBLIC PROC [rect: Imager.Rectangle] RETURNS [bBox: BoundBox] = { bBox _ NEW[BoundBoxObj _ [rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, FALSE, FALSE]]; }; UpdateBoundBoxFromRectangle: PUBLIC PROC [bBox: BoundBox, rect: Imager.Rectangle] = { bBox^ _ [rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, FALSE, FALSE]; }; bigReal: REAL = 100000.0; reallyBigReal: REAL = 1000000.0; infiniteRect: Imager.Rectangle = [-bigReal, -bigReal, reallyBigReal, reallyBigReal]; RectangleFromBoundBox: PUBLIC PROC [bBox: BoundBox] RETURNS [rect: Imager.Rectangle] = { IF bBox=NIL OR bBox.infinite THEN rect _ infiniteRect ELSE IF bBox.null THEN rect _ [bBox.loX, bBox.loY, 0.0, 0.0] ELSE rect _ [bBox.loX, bBox.loY, bBox.hiX - bBox.loX, bBox.hiY - bBox.loY]; }; BoundBoxOfPixelArray: PUBLIC PROC [pa: Imager.PixelArray] RETURNS [bBox: BoundBox] = { xPixels, yPixels: REAL; xPixels _ pa.sSize; yPixels _ pa.fSize; bBox _ CreateBoundBox[0, 0, xPixels, yPixels]; bBox _ BoundBoxOfBoundBox[bBox, pa.m]; }; BoundBoxOfBitMap: PUBLIC PROC [base: LONG POINTER, wordsPerLine: NAT, sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER _ 0] RETURNS [bBox: BoundBox] = { <> }; <<>> <> 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 {CopyContents[to: bBox, from: 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]; }; EnlargeByPoint: PUBLIC PROC [bBox: BoundBox, point: Point] = { IF bBox.infinite THEN RETURN; IF bBox.null THEN { bBox.loX _ bBox.hiX _ point.x; bBox.loY _ bBox.hiY _ point.y; bBox.null _ FALSE; RETURN; }; bBox.loX _ MIN[bBox.loX, point.x]; bBox.hiX _ MAX[bBox.hiX, point.x]; bBox.loY _ MIN[bBox.loY, point.y]; bBox.hiY _ MAX[bBox.hiY, point.y]; }; EnlargeByVector: PUBLIC PROC [bBox: BoundBox, vector: Vector] = { <> IF bBox.null OR bBox.infinite THEN RETURN; IF vector.x <0.0 THEN bBox.loX _ bBox.loX + vector.x ELSE bBox.hiX _ bBox.hiX + vector.x; IF vector.y <0.0 THEN bBox.loY _ bBox.loY + vector.y ELSE bBox.hiY _ bBox.hiY + vector.y; }; EnlargeByOffset: PUBLIC PROC [bBox: BoundBox, offset: REAL] = { <> IF bBox.null OR bBox.infinite THEN RETURN; bBox.loX _ bBox.loX - offset; bBox.hiX _ bBox.hiX + offset; bBox.loY _ bBox.loY - offset; bBox.hiY _ bBox.hiY + offset; }; UpdateBoundBox: PUBLIC PROC [bBox: BoundBox, loX, loY, hiX, hiY: REAL] = { bBox.loX _ loX; bBox.loY _ loY; bBox.hiX _ hiX; bBox.hiY _ hiY; bBox.null _ FALSE; bBox.infinite _ FALSE; }; <> PointIsInBox: PUBLIC PROC [test: Point, box: GGCoreTypes.BoundBoxObj] RETURNS [BOOL] = { RETURN[ NOT (test.x < box.loX OR test.x > box.hiX OR test.y < box.loY OR test.y > box.hiY) ]; }; PointIsInGrownBox: PUBLIC PROC [test: Point, box: BoundBox, offset: REAL] RETURNS [BOOL] = { RETURN[ NOT (test.x < box.loX-offset OR test.x > box.hiX+offset OR test.y < box.loY-offset OR test.y > box.hiY+offset) ]; }; Centroid: PUBLIC PROC [box: BoundBox] RETURNS [centroid: Point _ [0.0, 0.0], success: BOOL _ TRUE] = { IF box.null OR box.infinite THEN {success _ FALSE; RETURN}; centroid _ [(box.loX + box.hiX)/2.0, (box.loY + box.hiY)/2.0]; }; <<>> <> <<>> CopyContents: PROC [to: BoundBox, from: BoundBox] = { to^ _ [from.loX, from.loY, from.hiX, from.hiY, from.null, from.infinite]; }; <> <> <<>> <> <> <<[arrowHeight, arrowHalfWidth] _ GGShapes.ArrowSize[MAX[firstWidth, lastWidth]];>> < GGModelTypes.halfJointSize THEN {>> <> <> <> <> <> <<};>> <<};>> <<>> <> <<>> EraseWithinBoundBox: PUBLIC PROC [dc: Imager.Context, bBox: BoundBox] = { EraseWithinBoundBoxAux: PROC = { Imager.SetColor[dc, Imager.white]; Imager.MaskRectangle[dc, IF bBox.infinite THEN infiniteRect ELSE [x: bBox.loX, y: bBox.loY, w: bBox.hiX-bBox.loX, h: bBox.hiY-bBox.loY] ]; }; <> IF bBox.null THEN RETURN; Imager.DoSave[dc, EraseWithinBoundBoxAux]; }; Clip: PUBLIC PROC [dc: Imager.Context, bBox: BoundBox] = { IF bBox.null THEN ERROR; IF bBox.infinite THEN RETURN; Imager.ClipRectangle[dc, [bBox.loX, bBox.loY, (bBox.hiX-bBox.loX), (bBox.hiY-bBox.loY)]]; }; <> <<>> CatchableMul: PROC [a, b: REAL] RETURNS [REAL] = {RETURN [a*b]}; NearestPoint: PUBLIC PROC [bBox: BoundBox, testPoint: Point, tolerance: REAL _ 1E6, mask: MaskArray _ ALL[TRUE] ] RETURNS [bestDist: REAL, bestJoint: NAT, bestPoint: Point, success: BOOL] = { <> thisPoint: Point; thisDist2, bestDist2: REAL; index: NAT _ 0; tolerance2: REAL; IF bBox.null OR bBox.infinite THEN RETURN[bestDist: 99999.0, bestJoint: 999, bestPoint: [-1.0, -1.0], success: FALSE]; tolerance2 _ CatchableMul[tolerance, tolerance ! Real.RealException => {tolerance2 _ Real.LargestNumber; CONTINUE}]; bestPoint _ [-1.0, -1.0]; bestDist2 _ 1E12; -- better be big enough bestJoint _ 9999; success _ FALSE; FOR index IN [0..4) DO IF mask[index] THEN { thisPoint _ BoxPoint[bBox, index]; thisDist2 _ Vectors2d.DistanceSquared[thisPoint, testPoint]; IF thisDist2 < bestDist2 THEN { bestDist2 _ thisDist2; bestJoint _ index; bestPoint _ thisPoint; IF bestDist2 < tolerance2 THEN success _ TRUE; }; }; ENDLOOP; bestDist _ RealFns.SqRt[bestDist2]; }; NearestSegment: PUBLIC PROC [bBox: BoundBox, testPoint: Point, tolerance: REAL _ 1E6, mask: MaskArray _ ALL[TRUE] ] RETURNS [bestDist: REAL, bestSeg: NAT, bestPoint: Point, success: BOOL] = { <> thisDist2, bestDist2: REAL; thisPoint: Point; index: NAT _ 0; tolerance2: REAL; IF bBox.null OR bBox.infinite THEN RETURN[bestDist: 99999.0, bestSeg: 999, bestPoint: [-1.0, -1.0], success: FALSE]; tolerance2 _ CatchableMul[tolerance, tolerance ! Real.RealException => {tolerance2 _ Real.LargestNumber; CONTINUE}]; bestPoint _ [-1.0, -1.0]; bestDist2 _ 1E12; -- better be big enough bestSeg _ 9999; success _ FALSE; FOR index IN [0..4) DO IF mask[index] THEN { FillBoxEdge[globalBoxEdge, bBox, index]; thisPoint _ Lines2d.NearestPointOnEdge[testPoint, globalBoxEdge]; thisDist2 _ Vectors2d.DistanceSquared[thisPoint, testPoint]; IF thisDist2 < bestDist2 THEN { bestDist2 _ thisDist2; bestSeg _ index; bestPoint _ thisPoint; IF thisDist2 < tolerance2 THEN success _ TRUE; }; }; ENDLOOP; bestDist _ RealFns.SqRt[bestDist2]; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <<[hitPoints[i], noHit] _ Lines2d.LineMeetsEdge[line, globalEdge]; -- global scratch edge>> <> <0 AND hits[i-1] THEN {>> <> <> <<};>> <> <> <> <> < {>> <> <<[hitPoints[3], noHit] _ Lines2d.LineMeetsEdge[line, globalEdge];>> <> <> <> <> <<};>> <> <> <> <<};>> <> <> <> <> < NULL;>> <<};>> <> < 2 THEN ERROR;>> <<};>> <<>> BoxPoint: PROC [bBox: BoundBox, index: NAT] RETURNS [point: Point] ~ { << [Artwork node; type 'ArtworkInterpress on' to command tool] >> <> IF bBox.null OR bBox.infinite THEN ERROR; SELECT index FROM 0 => point _ [bBox.loX, bBox.loY]; 1 => point _ [bBox.loX, bBox.hiY]; 2 => point _ [bBox.hiX, bBox.hiY]; 3 => point _ [bBox.hiX, bBox.loY]; ENDCASE => ERROR; }; FillBoxEdge: PRIVATE PROC [edge: Edge, bBox: BoundBox, index: NAT] = { IF bBox.null OR bBox.infinite THEN ERROR; SELECT index FROM 0 => Lines2d.FillEdge[[bBox.loX, bBox.loY], [bBox.loX, bBox.hiY], edge]; 1 => Lines2d.FillEdge[[bBox.loX, bBox.hiY], [bBox.hiX, bBox.hiY], edge]; 2 => Lines2d.FillEdge[[bBox.hiX, bBox.hiY], [bBox.hiX, bBox.loY], edge]; 3 => Lines2d.FillEdge[[bBox.hiX, bBox.loY], [bBox.loX, bBox.loY], edge]; ENDCASE => ERROR; }; <> globalBoxEdge: Edge; emptyBoundBox: PUBLIC BoundBox; Init: PROC [] = { <> globalBoxEdge _ Lines2d.CreateEmptyEdge[]; emptyBoundBox _ NEW[GGCoreTypes.BoundBoxObj _ [loX: Real.LargestNumber, loY: Real.LargestNumber, hiX: Real.SmallestNormalizedNumber, hiY: Real.SmallestNormalizedNumber, null: TRUE, infinite: FALSE] ]; }; Init[]; END.