PipalRealImpl.mesa
Copyright Ó 1985, 1987 by Xerox Corporation. All rights reserved.
Bertrand Serlet May 17, 1988 2:19:43 pm PDT
Louis Monier January 15, 1988 11:30:47 pm PST
Barth, January 27, 1988 11:30:23 am PST
DIRECTORY ImagerBox, ImagerTransformation, IO, Pipal, PipalInt, PipalReal, PipalRealInline, RefTab;
PipalRealImpl: CEDAR PROGRAM
IMPORTS ImagerTransformation, IO, Pipal, PipalInt, PipalRealInline, RefTab
EXPORTS PipalReal, PipalRealInline =
BEGIN OPEN PipalReal;
Printing Utilities
VectorToRope: PUBLIC PROC [v: Vector] RETURNS [rope: Pipal.ROPE] = {
rope ← IO.PutFR["[%g, %g]", IO.real[v.x], IO.real[v.y]];
};
RectangleToRope: PUBLIC PROC [r: Rectangle] RETURNS [rope: Pipal.ROPE] = {
rope ← IO.PutFR["[base: %g, size: %g]", IO.rope[VectorToRope[r.base]], IO.rope[VectorToRope[r.size]]];
};
TransformationToRope: PUBLIC PROC [t: Transformation] RETURNS [rope: Pipal.ROPE] = {
rope ← IO.PutFR["[...Transformation...]"];
};
Operations on Vectors
Add: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalRealInline.Add[v1, v2]] };
Sub: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalRealInline.Sub[v1, v2]] };
Min: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalRealInline.Min[v1, v2]] };
Max: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalRealInline.Max[v1, v2]] };
Neg: PUBLIC PROC [v: Vector] RETURNS [Vector] = { RETURN [PipalRealInline.Neg[v]] };
IsDegeneratedSize: PUBLIC PROC [s: Size] RETURNS [BOOL] = { RETURN [PipalRealInline.IsDegeneratedSize[s]] };
IsEmptySize: PUBLIC PROC [s: Size] RETURNS [BOOL] = { RETURN [PipalRealInline.IsEmptySize[s]] };
Operations on Intervals
IntersectionIntervals: PUBLIC PROC [i1, i2: Interval] RETURNS [Interval]
= { RETURN [PipalRealInline.IntersectionIntervals[i1, i2]] };
UnionIntervals: PUBLIC PROC [i1, i2: Interval] RETURNS [Interval]
= { RETURN [PipalRealInline.UnionIntervals[i1, i2]] };
DoIntervalsIntersect: PUBLIC PROC [i1, i2: Interval] RETURNS [BOOL]
= { RETURN [PipalRealInline.DoIntervalsIntersect[i1, i2]] };
IsInsideInterval: PUBLIC PROC [container, candidate: Interval] RETURNS [BOOL]
= { RETURN [PipalRealInline.IsInsideInterval[container, candidate]] };
IsInsideIntervalNumber: PUBLIC PROC [container: Interval, candidate: Number] RETURNS [BOOL] = { RETURN [PipalRealInline.IsInsideIntervalNumber[container, candidate]] };
Operations on Rectangles
Transformations
Translate: PUBLIC PROC [r: Rectangle, v: Vector] RETURNS [Rectangle]
= { RETURN [PipalRealInline.Translate[r, v]] };
Extend: PUBLIC PROC [r: Rectangle, n: Number] RETURNS [Rectangle]
= { RETURN [[[r.base.x-n, r.base.y-n], [r.size.x+n+n, r.size.y+n+n]]] };
IntersectBox: PUBLIC PROC [r1, r2: Rectangle] RETURNS [r: Rectangle] = {
Could be optimized
r.base ← PipalRealInline.Max[r1.base, r2.base];
r.size ← PipalRealInline.Sub[PipalRealInline.Min[PipalRealInline.Extremity[r1], PipalRealInline.Extremity[r2]], r.base];
};
BoundingBox: PUBLIC PROC [r1, r2: Rectangle] RETURNS [r: Rectangle] = {
Could be optimized
r.base ← PipalRealInline.Min[r1.base, r2.base];
r.size ← PipalRealInline.Sub[PipalRealInline.Max[PipalRealInline.Extremity[r1], PipalRealInline.Extremity[r2]], r.base];
};
BoundingRectangle: PUBLIC PROC [p1, p2: Position] RETURNS [r: Rectangle] = {
Could be inlined
r.base ← PipalRealInline.Min[p1, p2];
r.size ← PipalRealInline.Sub[PipalRealInline.Max[p1, p2], r.base];
};
Predicates
IsDegeneratedRectangle: PUBLIC PROC [r: Rectangle] RETURNS [BOOL]
= { RETURN [PipalRealInline.IsDegeneratedRectangle[r]] };
IsEmptyRectangle: PUBLIC PROC [r: Rectangle] RETURNS [BOOL]
= { RETURN [PipalRealInline.IsEmptyRectangle[r]] };
DoRectanglesIntersect: PUBLIC PROC [r1, r2: Rectangle] RETURNS [BOOL]
= { RETURN [PipalRealInline.DoRectanglesIntersect[r1, r2]] };
IsInsideRectangle: PUBLIC PROC [container, candidate: Rectangle] RETURNS [BOOL]
= { RETURN [PipalRealInline.IsInsideRectangle[container, candidate]] };
IsInsidePoint: PUBLIC PROC [container: Rectangle, candidate: Position] RETURNS [BOOL]
= { RETURN [PipalRealInline.IsInsidePoint[container, candidate]] };
Others
AlwaysQuit: PUBLIC RectangleProc = {quit ← TRUE};
Extremity: PUBLIC PROC [r: Rectangle] RETURNS [Position]
= { RETURN [PipalRealInline.Extremity[r]] };
DecomposeRect: PUBLIC PROC [r, clip: Rectangle, inside, outside: RectangleProc ← NIL] RETURNS [quit: BOOLFALSE] = {
clipext: Position = PipalRealInline.Extremity[clip];
rext: Position = PipalRealInline.Extremity[r];
delta: Vector = PipalRealInline.Sub[r.base, clip.base];
IF clip.base.x<r.base.x THEN {
IF outside#NIL THEN quit ← outside[[clip.base, [MIN[clip.size.x, delta.x], clip.size.y]]];
IF clipext.x<r.base.x OR quit THEN RETURN;
};
IF clip.base.y<r.base.y THEN {
IF outside#NIL THEN quit ← outside[[[MAX[r.base.x, clip.base.x], clip.base.y], [clip.size.x, MIN[clip.size.y, delta.y]]]];
IF clipext.y<r.base.y OR quit THEN RETURN;
};
IF rext.y<clipext.y THEN {
IF outside#NIL THEN quit ← outside[[[MAX[r.base.x, clip.base.x], MAX[rext.y, clip.base.y]], clip.size]];
IF rext.y<clip.base.y OR quit THEN RETURN;
};
IF rext.x<clipext.x THEN {
IF outside#NIL THEN quit ← outside[[[MAX[rext.x, clip.base.x], MAX[r.base.y, clip.base.y]], [clip.size.x, MIN[clip.size.y, delta.y]]]];
IF rext.x<clip.base.x OR quit THEN RETURN;
};
IF inside#NIL THEN quit ← inside[IntersectBox[r, clip]];
};
Center: PUBLIC PROC [r: Rectangle] RETURNS [Position]
= { RETURN [[r.base.x+r.size.x/2, r.base.y+r.size.y/2]] };
Operations on Transformations
TransformVector: PUBLIC PROC [t: Transformation, v: Vector] RETURNS [Vector] = {
Can be inlined!!!!
RETURN [ImagerTransformation.Transform[t, v]];
};
TransformBBox: PUBLIC PROC [t: Transformation, s: Size] RETURNS [Rectangle] = {
Can be inlined!!!!
RETURN [TransformRectangle[t, [zeroVector, s]]];
};
TransformRectangle: PUBLIC PROC [t: Transformation, r: Rectangle] RETURNS [rr: Rectangle] = {
Can be optimized and inlined!!!!
ir: ImagerBox.Rectangle = ImagerTransformation.TransformRectangle[t, [r.base.x, r.base.y, r.size.x, r.size.y]];
rr ← [[ir.x, ir.y], [ir.w, ir.h]];
};
Compose: PUBLIC PROC [t1, t2: Transformation] RETURNS [Transformation] = {
Can be inlined!!!!
RETURN [ImagerTransformation.Concat[t2, t1]];
};
Apply: PUBLIC PROC [t1, t2: Transformation] = {
Can be inlined!!!!
ImagerTransformation.ApplyPreConcat[t1, t2];
};
CreateTransformation: PUBLIC PROC RETURNS [Transformation] = {
RETURN [ImagerTransformation.Create[1, 0, 0, 0, 1, 0]]};
CopyTransformation: PUBLIC PROC [t: Transformation] RETURNS [Transformation] = {
RETURN [ImagerTransformation.Copy[t]]};
DestroyTransformation: PUBLIC PROC [t: Transformation] = {ImagerTransformation.Destroy[t]};
EqualTransformation: PUBLIC PROC [t1, t2: Transformation] RETURNS [BOOL] = {RETURN [ImagerTransformation.CloseEnough[t1, t2]]};
Enumeration Method
enumerateMethod: PUBLIC Pipal.Method ← Pipal.RegisterMethod["RealEnumerate"];
HasEnumerate: PUBLIC PROC [object: Pipal.Object] RETURNS [BOOL] = {
RETURN [Pipal.ObjectMethod[object, enumerateMethod]#NIL OR Pipal.ObjectMethod[object, PipalInt.enumerateMethod]#NIL];
};
Enumerate: PUBLIC EnumerateProc = {
data: REF ← Pipal.ObjectMethod[object, enumerateMethod];
quit ← (IF data=NIL THEN UseIntEnumerate ELSE NARROW [data, REF EnumerateProc]^)[object, each, transformation];
};
UseIntEnumerate: EnumerateProc = {
EachChild: PipalInt.EachChildProc = {
realTransformation: Transformation ← CopyTransformation[rt];
ApplyRealInt[realTransformation, transformation];
quit ← each[realTransformation, child];
DestroyTransformation[realTransformation];
};
rt: Transformation ← transformation; -- just renaming!
quit ← PipalInt.Enumerate[object, EachChild];
};
NthChild: PUBLIC PROC [object: Pipal.Object, transformation: Transformation, rank: NAT ← 0] RETURNS [nthTrans: Transformation, nthChild: Pipal.Object ← NIL] = {
EachChild: EachChildProc = {
IF rank=0
THEN {nthChild ← child; nthTrans ← CopyTransformation[transformation]; quit ← TRUE}
ELSE rank ← rank - 1;
};
[] ← Enumerate[object, EachChild, transformation];
};
CountChildren: PUBLIC PROC [object: Pipal.Object] RETURNS [count: NAT ← 0] = {
realTransformation: Transformation ← CreateTransformation[];
EachChild: EachChildProc = {count ← count + 1};
[] ← Enumerate[object, EachChild, realTransformation];
DestroyTransformation[realTransformation];
};
Size Method
It's kind of tricky: objects inherently have a size, but no bbox. However, within an overlay, objects have a bbox. The implementation reflects that situation, and the bbox and size methods play ping-pong.
sizeMethod: PUBLIC Pipal.Method ← Pipal.RegisterMethod["RealSize"];
bboxMethod: PUBLIC Pipal.Method ← Pipal.RegisterMethod["RealBBox"];
ObjectSize: PUBLIC SizeProc = {
ref: REF = Pipal.ObjectMethod[object, sizeMethod];
size ← (IF ref=NIL THEN SizeFromEnumerate ELSE NARROW [ref, REF SizeProc]^)[object];
};
BBox: PUBLIC BBoxProc = {
ref: REF = Pipal.ObjectMethod[object, bboxMethod];
bbox ← (SELECT TRUE FROM
ref#NIL  => (NARROW [ref, REF BBoxProc]^),
HasEnumerate[object]  => BBoxFromEnumerate,
ENDCASE     => BBoxFromSize)[object, transformation];
};
UseIntSize: PUBLIC SizeProc = {
size ← PipalRealInline.IntToRealVector[PipalInt.ObjectSize[object]];
};
SizeFromEnumerate: SizeProc = {
transformation: Transformation ← CreateTransformation[];
size ← BBoxFromEnumerate[object, transformation].size;
DestroyTransformation[transformation];
};
BBoxFromEnumerate: BBoxProc = {
ComputeBBoxRec: EachChildProc = {
bbox ← BoundingBox[bbox, BBox[child, transformation]];
};
bbox ← emptyRectangle;
[] ← Enumerate[object, ComputeBBoxRec, transformation];
};
BBoxFromSize: BBoxProc = {
bbox ← TransformRectangle[transformation, [zeroVector, ObjectSize[object]]];
};
cachedSizes: Pipal.ObjectCache ← Pipal.CreateObjectCache[];
CachedSizeFromEnumerate: PUBLIC SizeProc = {
refSize: REF Size ← NARROW [RefTab.Fetch[cachedSizes, object].val];
IF refSize#NIL THEN RETURN [refSize^];
size ← SizeFromEnumerate[object];
refSize ← NEW [Size ← size];
[] ← RefTab.Store[cachedSizes, object, refSize];
};
cachedBBoxes: Pipal.ObjectCache ← Pipal.CreateObjectCache[];
CachedBBoxFromEnumerate: PUBLIC BBoxProc = {
refBBox: REF Rectangle ← NARROW [RefTab.Fetch[cachedBBoxes, object].val];
IF refBBox#NIL
THEN bbox ← refBBox^
ELSE {
transformation: Transformation ← CreateTransformation[];
bbox ← BBoxFromEnumerate[object, transformation];
DestroyTransformation[transformation];
refBBox ← NEW [Rectangle ← bbox];
[] ← RefTab.Store[cachedBBoxes, object, refBBox];
};
bbox ← TransformRectangle[transformation, bbox];
};
Geometrical Classes
General Transform
transformClass: PUBLIC Pipal.Class ← Pipal.RegisterClass["RealTransform", CODE [TransformRec]];
EnumerateTransform: EnumerateProc = {
transform: Transform ← NARROW [object];
rt: Transformation ← Compose[transformation, transform.transformation];
quit ← each[rt, transform.child];
DestroyTransformation[rt];
};
DescribeTransform: Pipal.DescribeProc = {
transform: Transform ← NARROW [object];
Pipal.PutIndent[out, indent, cr];
IO.PutF[out, "RealTransform %g of : ", IO.rope[TransformationToRope[transform.transformation]]];
Pipal.Describe[out, transform.child, indent+1, level-1, cr];
};
CreateTransform: PUBLIC PROC [transformation: Transformation, child: Pipal.Object] RETURNS [transform: Transform] = {
transform ← NEW [TransformRec ← [transformation, child]];
};
Compacted creation of objects
identityTransformation: PRIVATE Transformation = CreateTransformation[];
TransformObject: PUBLIC PROC [transformation: Transformation, child: Pipal.Object] RETURNS [Pipal.Object] = {
RETURN [SELECT TRUE FROM
transformation=identityTransformation => child,
ENDCASE => CreateTransform[transformation, child]
];
};
Coercion with PipalInt Types
IntToRealVector: PUBLIC PROC [v: PipalInt.Vector] RETURNS [Vector]
= {RETURN [PipalRealInline.IntToRealVector[v]]};
IntToRealRectangle: PUBLIC PROC [r: PipalInt.Rectangle] RETURNS [Rectangle]
= {RETURN [PipalRealInline.IntToRealRectangle[r]]};
IntToRealTransformation: PUBLIC PROC [t: PipalInt.Transformation] RETURNS [Transformation]
= {RETURN [PipalRealInline.IntToRealTransformation[t]]};
ApplyRealInt: PUBLIC PROC [t1: Transformation, t2: PipalInt.Transformation] = {
Can be optimized!
rt: Transformation ← PipalRealInline.IntToRealTransformation[t2];
Apply[t1, rt];
DestroyTransformation[rt];
};
Initialization
Pipal classes functions
EnumerateOverlay: EnumerateProc ~ {
overlay: Pipal.Overlay ← NARROW [object];
FOR i: NAT IN [0..overlay.size) DO
IF each[transformation, overlay[i]] THEN RETURN[TRUE];
ENDLOOP;
};
BBoxAnnotation: BBoxProc = {
annotation: Pipal.Annotation ← NARROW [object];
bbox ← BBox[annotation.child, transformation];
IF annotation.key=PipalInt.abutBoxProp THEN bbox ← BoundingBox[
bbox,
TransformRectangle[transformation, PipalRealInline.IntToRealRectangle[(NARROW [annotation.value, REF PipalInt.Rectangle]^)]]
];
};
Pipal classes
Pipal.PutClassMethod[Pipal.overlayClass, enumerateMethod, NEW [EnumerateProc ← EnumerateOverlay]]; -- speed up only
Pipal.PutClassMethod[Pipal.overlayClass, sizeMethod, NEW [SizeProc ← CachedSizeFromEnumerate]]; -- speed up only
Pipal.PutClassMethod[Pipal.overlayClass, bboxMethod, NEW [BBoxProc ← CachedBBoxFromEnumerate]]; -- speed up only
Pipal.PutClassMethod[Pipal.annotationClass, bboxMethod, NEW [BBoxProc ← BBoxAnnotation]];
Classes defined in this interface
Pipal.PutClassMethod[transformClass, enumerateMethod, NEW [EnumerateProc ← EnumerateTransform]];
Pipal.PutClassMethod[transformClass, Pipal.describeMethod, NEW [Pipal.DescribeProc ← DescribeTransform]];
END.