<> <> <> <> <<>> DIRECTORY Basics, IO, Pipal, PipalInt, PipalIntInline, RefTab; PipalIntImpl: CEDAR PROGRAM IMPORTS Basics, IO, Pipal, PipalIntInline, RefTab EXPORTS PipalInt, PipalIntInline = BEGIN OPEN PipalInt; <> VectorToRope: PUBLIC PROC [v: Vector] RETURNS [rope: Pipal.ROPE] = { rope _ IO.PutFR["[%g, %g]", IO.int[v.x], IO.int[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]]]; }; OrientationToRope: PUBLIC PROC [o: Orientation] RETURNS [rope: Pipal.ROPE] = { rope _ SELECT o FROM identity => "identity", mirrorX => "mirrorX", rotate90 => "rotate90", rotate90X => "rotate90X", rotate180 => "rotate180", rotate180X => "rotate180X", rotate270 => "rotate270", rotate270X => "rotate270X", ENDCASE => ERROR; }; TransformationToRope: PUBLIC PROC [t: Transformation] RETURNS [rope: Pipal.ROPE] = { rope _ IO.PutFR["[%g, %g]", IO.rope[VectorToRope[t.translation]], IO.rope[OrientationToRope[t.orientation]]]; }; <> Add: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalIntInline.Add[v1, v2]] }; Sub: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalIntInline.Sub[v1, v2]] }; Min: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalIntInline.Min[v1, v2]] }; Max: PUBLIC PROC [v1, v2: Vector] RETURNS [Vector] = { RETURN [PipalIntInline.Max[v1, v2]] }; Neg: PUBLIC PROC [v: Vector] RETURNS [Vector] = { RETURN [PipalIntInline.Neg[v]] }; IsDegeneratedSize: PUBLIC PROC [s: Size] RETURNS [BOOL] = { RETURN [PipalIntInline.IsDegeneratedSize[s]] }; IsEmptySize: PUBLIC PROC [s: Size] RETURNS [BOOL] = { RETURN [PipalIntInline.IsEmptySize[s]] }; <> IntersectionIntervals: PUBLIC PROC [i1, i2: Interval] RETURNS [Interval] = {RETURN [PipalIntInline.IntersectionIntervals[i1, i2]] }; UnionIntervals: PUBLIC PROC [i1, i2: Interval] RETURNS [Interval] = {RETURN [PipalIntInline.UnionIntervals[i1, i2]] }; DoIntervalsIntersect: PUBLIC PROC [i1, i2: Interval] RETURNS [BOOL] = { RETURN [PipalIntInline.DoIntervalsIntersect[i1, i2]] }; IsInsideInterval: PUBLIC PROC [container, candidate: Interval] RETURNS [BOOL] = { RETURN [PipalIntInline.IsInsideInterval[container, candidate]] }; IsInsideIntervalNumber: PUBLIC PROC [container: Interval, candidate: Number] RETURNS [BOOL] = { RETURN [PipalIntInline.IsInsideIntervalNumber[container, candidate]] }; <> <> Translate: PUBLIC PROC [r: Rectangle, v: Vector] RETURNS [Rectangle] = { RETURN [PipalIntInline.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] = { <> r.base _ PipalIntInline.Max[r1.base, r2.base]; r.size _ PipalIntInline.Sub[PipalIntInline.Min[PipalIntInline.Extremity[r1], PipalIntInline.Extremity[r2]], r.base]; }; BoundingBox: PUBLIC PROC [r1, r2: Rectangle] RETURNS [r: Rectangle] = { <> r.base _ PipalIntInline.Min[r1.base, r2.base]; r.size _ PipalIntInline.Sub[PipalIntInline.Max[PipalIntInline.Extremity[r1], PipalIntInline.Extremity[r2]], r.base]; }; BoundingRectangle: PUBLIC PROC [p1, p2: Position] RETURNS [r: Rectangle] = { <> r.base _ PipalIntInline.Min[p1, p2]; r.size _ PipalIntInline.Sub[PipalIntInline.Max[p1, p2], r.base]; }; <> IsDegeneratedRectangle: PUBLIC PROC [r: Rectangle] RETURNS [BOOL] = { RETURN [PipalIntInline.IsDegeneratedRectangle[r]] }; IsEmptyRectangle: PUBLIC PROC [r: Rectangle] RETURNS [BOOL] = { RETURN [PipalIntInline.IsEmptyRectangle[r]] }; DoRectanglesIntersect: PUBLIC PROC [r1, r2: Rectangle] RETURNS [BOOL] = { RETURN [PipalIntInline.DoRectanglesIntersect[r1, r2]] }; IsInsideRectangle: PUBLIC PROC [container, candidate: Rectangle] RETURNS [BOOL] = { RETURN [PipalIntInline.IsInsideRectangle[container, candidate]] }; IsInsidePoint: PUBLIC PROC [container: Rectangle, candidate: Position] RETURNS [BOOL] = { RETURN [PipalIntInline.IsInsidePoint[container, candidate]] }; <> AlwaysQuit: PUBLIC RectangleProc = {quit _ TRUE}; Extremity: PUBLIC PROC [r: Rectangle] RETURNS [Position] = { RETURN [PipalIntInline.Extremity[r]] }; DecomposeRect: PUBLIC PROC [r, clip: Rectangle, inside, outside: RectangleProc _ NIL] RETURNS [quit: BOOL _ FALSE] = { clipext: Position = PipalIntInline.Extremity[clip]; rext: Position = PipalIntInline.Extremity[r]; delta: Vector = PipalIntInline.Sub[r.base, clip.base]; IF clip.base.x> OrientVector: PROC [orientation: Orientation, v: Vector] RETURNS [Vector] = { <> SELECT orientation FROM identity => RETURN [[+v.x, +v.y]]; mirrorX => RETURN [[-v.x, +v.y]]; rotate90 => RETURN [[-v.y, +v.x]]; rotate90X => RETURN [[+v.y, +v.x]]; rotate180 => RETURN [[-v.x, -v.y]]; rotate180X => RETURN [[+v.x, -v.y]]; rotate270 => RETURN [[+v.y, -v.x]]; rotate270X => RETURN [[-v.y, -v.x]]; ENDCASE => ERROR; }; TransformVector: PUBLIC PROC [t: Transformation, v: Vector] RETURNS [Vector] = { <> RETURN [PipalIntInline.Add[t.translation, OrientVector[t.orientation, v]]]; }; TransformBBox: PUBLIC PROC [t: Transformation, s: Size] RETURNS [Rectangle] = { <> RETURN [TransformRectangle[t, [zeroVector, s]]]; }; TransformRectangle: PUBLIC PROC [t: Transformation, r: Rectangle] RETURNS [Rectangle] = { <> RETURN [PipalIntInline.Translate[ [SELECT t.orientation FROM identity => [+r.base.x, +r.base.y], mirrorX => [-r.base.x-r.size.x, +r.base.y], rotate90 => [-r.base.y-r.size.y, +r.base.x], rotate90X => [+r.base.y, +r.base.x], rotate180 => [-r.base.x-r.size.x, -r.base.y-r.size.y], rotate180X => [+r.base.x, -r.base.y-r.size.y], rotate270 => [+r.base.y, -r.base.x-r.size.x], rotate270X => [-r.base.y-r.size.y, -r.base.x-r.size.x], ENDCASE => ERROR, PipalIntInline.OrientSize[t.orientation, r.size]], t.translation ]]; }; Compose: PUBLIC PROC [t1, t2: Transformation] RETURNS [Transformation] = { <> RETURN [[TransformVector[t1, t2.translation], PipalIntInline.ComposeOrientation[t1.orientation, t2.orientation]]]; }; <> enumerateMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["IntEnumerate"]; HasEnumerate: PUBLIC PROC [object: Pipal.Object] RETURNS [BOOL] = { RETURN [Pipal.ObjectMethod[object, enumerateMethod]#NIL]; }; Enumerate: PUBLIC EnumerateProc = { quit _ (NARROW [Pipal.ObjectMethod[object, enumerateMethod], REF EnumerateProc]^)[object, each, transformation]; }; 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 _ transformation; quit _ TRUE} ELSE rank _ rank - 1; }; [] _ Enumerate[object, EachChild, transformation]; }; CountChildren: PUBLIC PROC [object: Pipal.Object] RETURNS [count: NAT _ 0] = { EachChild: EachChildProc = {count _ count + 1}; [] _ Enumerate[object, EachChild]; }; <> <> <<>> sizeMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["IntSize"]; bboxMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["IntBBox"]; 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]; }; SizeFromEnumerate: SizeProc = { RETURN [BBoxFromEnumerate[object, []].size]; }; 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 { bbox _ BBoxFromEnumerate[object, []]; refBBox _ NEW [Rectangle _ bbox]; [] _ RefTab.Store[cachedBBoxes, object, refBBox]; }; bbox _ TransformRectangle[transformation, bbox]; }; <> abutBoxMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["IntAbutBox"]; AbutBox: PUBLIC AbutBoxProc = { ref: REF = Pipal.ObjectMethod[object, abutBoxMethod]; abutBox _ (IF ref=NIL THEN AbutBoxFromEnumerate ELSE NARROW [ref, REF AbutBoxProc]^)[object]; }; AbutBoxFromEnumerate: AbutBoxProc = { ComputeBBox: EachChildProc = { abutBox _ BoundingBox[abutBox, TransformRectangle[transformation, AbutBox[child]]]; }; abutBox _ emptyRectangle; [] _ Enumerate[object, ComputeBBox]; }; AbutBoxFromSize: PUBLIC AbutBoxProc = { abutBox _ [zeroVector, ObjectSize[object]]; }; cachedAbutBoxes: Pipal.ObjectCache _ Pipal.CreateObjectCache[]; CachedAbutBoxFromEnumerate: PUBLIC AbutBoxProc = { refAbutBox: REF Rectangle _ NARROW [RefTab.Fetch[cachedAbutBoxes, object].val]; IF refAbutBox#NIL THEN RETURN [refAbutBox^]; abutBox _ AbutBoxFromEnumerate[object]; refAbutBox _ NEW [Rectangle _ abutBox]; [] _ RefTab.Store[cachedAbutBoxes, object, refAbutBox]; }; <> <> transformClass: PUBLIC Pipal.Class _ Pipal.RegisterClass["IntTransform", CODE [TransformRec]]; EnumerateTransform: EnumerateProc = { transform: Transform _ NARROW [object]; quit _ each[Compose[transformation, transform.transformation], transform.child]; }; DescribeTransform: Pipal.DescribeProc = { transform: Transform _ NARROW [object]; Pipal.PutIndent[out, indent, cr]; IO.PutF[out, "IntTransform %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]]; }; <> translationClass: PUBLIC Pipal.Class _ Pipal.RegisterClass["IntTranslation", CODE [TranslationRec]]; EnumerateTranslation: EnumerateProc = { <> translation: Translation _ NARROW [object]; quit _ each[Compose[transformation, [translation.vector]], translation.child]; }; DescribeTranslation: Pipal.DescribeProc = { translation: Translation _ NARROW [object]; Pipal.PutIndent[out, indent, cr]; IO.PutF[out, "IntTranslation %g of : ", IO.rope[VectorToRope[translation.vector]]]; Pipal.Describe[out, translation.child, indent+1, level-1, cr]; }; CreateTranslation: PUBLIC PROC [vector: Vector, child: Pipal.Object] RETURNS [translation: Translation] = { translation _ NEW [TranslationRec _ [vector, child]]; }; <> orientClass: PUBLIC Pipal.Class _ Pipal.RegisterClass["IntOrient", CODE [OrientRec]]; EnumerateOrient: EnumerateProc = { <> orient: Orient _ NARROW [object]; quit _ each[Compose[transformation, [zeroVector, orient.orientation]], orient.child]; }; DescribeOrient: Pipal.DescribeProc = { orient: Orient _ NARROW [object]; Pipal.PutIndent[out, indent, cr]; IO.PutF[out, "IntOrient %g of : ", IO.rope[OrientationToRope[orient.orientation]]]; Pipal.Describe[out, orient.child, indent+1, level-1, cr]; }; CreateOrient: PUBLIC PROC [orientation: Orientation, child: Pipal.Object] RETURNS [orient: Orient] = { orient _ NEW [OrientRec _ [orientation, child]]; }; <> TransformObject: PUBLIC PROC [transformation: Transformation, child: Pipal.Object] RETURNS [Pipal.Object] = { RETURN [WITH child SELECT FROM transform: Transform => TransformObject[Compose[transformation, transform.transformation], transform.child], translation: Translation => TransformObject[Compose[transformation, [translation.vector]], translation.child], orient: Orient => TransformObject[Compose[transformation, [orientation: orient.orientation]], orient.child], ENDCASE => SELECT TRUE FROM transformation=[] => child, transformation.orientation=identity => CreateTranslation[transformation.translation, child], transformation.translation=zeroVector => CreateOrient[transformation.orientation, child], ENDCASE => CreateTransform[transformation, child] ]; }; <<>> <> <> abutBoxProp: PUBLIC ATOM _ $AbutBoxAnnotation; CreateAbutBoxAnnotation: PUBLIC PROC [child: Pipal.Object, rectangle: Rectangle] RETURNS [annotation: Pipal.Annotation] = { annotation _ Pipal.CreateAnnotation[child, abutBoxProp, NEW [Rectangle _ rectangle]]; }; <> abutClass: PUBLIC Pipal.Class _ Pipal.RegisterClass["IntAbut", CODE [AbutRec]]; EnumerateAbut: EnumerateProc = { abut: Abut _ NARROW [object]; pos: Position _ zeroVector; FOR i: NAT IN [0 .. abut.size) DO ab: Rectangle = AbutBox[abut[i]]; quit _ each[Compose[transformation, [Sub[pos, ab.base]]], abut[i]]; IF quit THEN RETURN; IF abut.inX THEN pos.x _ pos.x + ab.size.x ELSE pos.y _ pos.y + ab.size.y; ENDLOOP; }; DescribeAbut: Pipal.DescribeProc = { abut: Abut _ NARROW [object]; Pipal.PutIndent[out, indent, cr]; IO.PutF[out, "Abut in %g of: ", IO.rope[IF abut.inX THEN "X" ELSE "Y"]]; IF level=1 THEN {IO.PutRope[out, "..."]; RETURN}; FOR i: NAT IN [0 .. abut.size) DO Pipal.Describe[out, abut[i], indent+1, level-1, cr]; ENDLOOP; }; CreateAbut: PUBLIC PROC [inX: BOOL, children: Pipal.Objects] RETURNS [abut: Abut] = { size: NAT _ Pipal.Length[children]; abut _ NEW [AbutRec[size]]; abut.inX _ inX; FOR i: NAT IN [0 .. size) DO abut[i] _ children.first; children _ children.rest ENDLOOP; IF size#0 THEN { irs0: Size = AbutBox[abut[0]].size; FOR i: NAT IN [1 .. size) DO irs: Size = AbutBox[abut[i]].size; IF (IF inX THEN irs0.y#irs.y ELSE irs0.x#irs.x) THEN ERROR; -- incompatible x dimension for an abutY or incompatible y dimension for an abutX ENDLOOP; }; }; <> HashByEnumeration: PUBLIC Pipal.HashProc = { Each: EachChildProc = { hash _ hash + HashTransformation[transformation] + Pipal.Hash[child] + 1; }; hash _ Pipal.HashObjectClass[object]; [] _ Enumerate[object, Each]; }; hashCache: Pipal.ObjectCache _ Pipal.CreateObjectCache[]; CachedHashByEnumeration: PUBLIC Pipal.HashProc = { refHash: REF CARD _ NARROW [RefTab.Fetch[hashCache, object].val]; IF refHash#NIL THEN RETURN [refHash^]; hash _ HashByEnumeration[object]; [] _ RefTab.Store[hashCache, object, NEW [CARD _ hash]]; }; HashObjectSize: PUBLIC Pipal.HashProc = { size: Size = ObjectSize[object]; hash _ size.x+size.y; }; HashVector: PUBLIC PROC [vector: Vector] RETURNS [hash: CARD] = { int: INT _ vector.x*11 + vector.y*17; -- something dissymetric and spreading values hash _ LOOPHOLE [int]; }; HashRectangle: PUBLIC PROC [rectangle: Rectangle] RETURNS [hash: CARD] = { hash _ HashVector[rectangle.base]*5+HashVector[rectangle.size]; }; HashTransformation: PUBLIC PROC [transformation: Transformation] RETURNS [hash: CARD] = { hash _ HashVector[transformation.translation] + 31 * ORD [transformation.orientation]; }; EqualByEnumeration: PUBLIC Pipal.EqualProc = { size: NAT _ CountChildren[object1]; IF CountChildren[object2]#size THEN RETURN [FALSE]; FOR i: NAT IN [0 .. size) DO nthTrans1: Transformation; nthChild1: Pipal.Object; nthTrans2: Transformation; nthChild2: Pipal.Object; [nthTrans1, nthChild1] _ NthChild[object1]; [nthTrans2, nthChild2] _ NthChild[object2]; IF nthTrans1#nthTrans2 OR NOT Pipal.Equal[nthChild1, nthChild2] THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE]; }; AtEdge: PUBLIC PROC [abutBox: Rectangle, trans: Transformation, object: Pipal.Object] RETURNS [BOOL] = { RETURN [NOT IsInsideRectangle[Extend[abutBox, -1], BBox[object, trans]]]; }; <> <> composeTable: PUBLIC ARRAY Orientation OF ARRAY Orientation OF Orientation; ReallyComposeOrientation: PROC [o1, o2: Orientation] RETURNS [Orientation] = { <> refl1: [0..1] ~ Basics.BITAND[ORD[o1], 1]; rot2: [0..6] _ Basics.BITAND[ORD[o2], 6]; IF refl1#0 AND rot2#0 THEN rot2 _ 8-rot2; RETURN [VAL[Basics.BITAND[ Basics.BITAND[ORD[o1], 6] + rot2 + Basics.BITXOR[refl1, Basics.BITAND[ORD[o2], 1]], 7]]]; }; <> EnumerateOverlay: EnumerateProc ~ { overlay: Pipal.Overlay _ NARROW [object]; FOR i: NAT IN [0 .. overlay.size) DO IF each[transformation, overlay[i]] THEN RETURN [TRUE]; ENDLOOP; }; EnumerateIcon: EnumerateProc ~ { icon: Pipal.Icon _ NARROW [object]; quit _ each[transformation, icon.reference]; }; EnumerateAnnotation: EnumerateProc ~ { annotation: Pipal.Annotation _ NARROW [object]; quit _ each[transformation, annotation.child]; }; SizeAnnotation: SizeProc = { size _ BBoxAnnotation[object, []].size; }; BBoxAnnotation: BBoxProc = { annotation: Pipal.Annotation _ NARROW [object]; bbox _ BBox[annotation.child, transformation]; IF annotation.key=abutBoxProp THEN bbox _ BoundingBox[ bbox, TransformRectangle[transformation, (NARROW [annotation.value, REF Rectangle]^)] ]; }; AbutBoxAnnotation: AbutBoxProc = { annotation: Pipal.Annotation _ NARROW [object]; abutBox _ IF annotation.key=abutBoxProp THEN (NARROW [annotation.value, REF Rectangle]^) ELSE AbutBox[annotation.child]; }; <> FOR o1: Orientation IN Orientation DO FOR o2: Orientation IN Orientation DO composeTable[o1][o2] _ ReallyComposeOrientation[o2, o1]; ENDLOOP; ENDLOOP; <> Pipal.PutClassMethod[Pipal.overlayClass, enumerateMethod, NEW [EnumerateProc _ EnumerateOverlay]]; Pipal.PutClassMethod[Pipal.overlayClass, sizeMethod, NEW [SizeProc _ CachedSizeFromEnumerate]]; Pipal.PutClassMethod[Pipal.overlayClass, bboxMethod, NEW [BBoxProc _ CachedBBoxFromEnumerate]]; Pipal.PutClassMethod[Pipal.overlayClass, abutBoxMethod, NEW [AbutBoxProc _ CachedAbutBoxFromEnumerate]]; Pipal.PutClassMethod[Pipal.overlayClass, Pipal.hashMethod, NEW [Pipal.HashProc _ CachedHashByEnumeration]]; Pipal.PutClassMethod[Pipal.overlayClass, Pipal.equalMethod, NEW [Pipal.EqualProc _ EqualByEnumeration]]; Pipal.PutClassMethod[Pipal.iconClass, enumerateMethod, NEW [EnumerateProc _ EnumerateIcon]]; Pipal.PutClassMethod[Pipal.iconClass, Pipal.hashMethod, NEW [Pipal.HashProc _ HashByEnumeration]]; Pipal.PutClassMethod[Pipal.iconClass, Pipal.equalMethod, NEW [Pipal.EqualProc _ EqualByEnumeration]]; Pipal.PutClassMethod[Pipal.annotationClass, enumerateMethod, NEW [EnumerateProc _ EnumerateAnnotation]]; Pipal.PutClassMethod[Pipal.annotationClass, sizeMethod, NEW [SizeProc _ SizeAnnotation]]; Pipal.PutClassMethod[Pipal.annotationClass, bboxMethod, NEW [BBoxProc _ BBoxAnnotation]]; Pipal.PutClassMethod[Pipal.annotationClass, abutBoxMethod, NEW [AbutBoxProc _ AbutBoxAnnotation]]; <> Pipal.PutClassMethod[transformClass, enumerateMethod, NEW [EnumerateProc _ EnumerateTransform]]; Pipal.PutClassMethod[transformClass, Pipal.describeMethod, NEW [Pipal.DescribeProc _ DescribeTransform]]; Pipal.PutClassMethod[transformClass, Pipal.hashMethod, NEW [Pipal.HashProc _ HashByEnumeration]]; Pipal.PutClassMethod[transformClass, Pipal.equalMethod, NEW [Pipal.EqualProc _ EqualByEnumeration]]; Pipal.PutClassMethod[translationClass, enumerateMethod, NEW [EnumerateProc _ EnumerateTranslation]]; Pipal.PutClassMethod[translationClass, Pipal.describeMethod, NEW [Pipal.DescribeProc _ DescribeTranslation]]; Pipal.PutClassMethod[translationClass, Pipal.hashMethod, NEW [Pipal.HashProc _ HashByEnumeration]]; Pipal.PutClassMethod[translationClass, Pipal.equalMethod, NEW [Pipal.EqualProc _ EqualByEnumeration]]; Pipal.PutClassMethod[orientClass, enumerateMethod, NEW [EnumerateProc _ EnumerateOrient]]; Pipal.PutClassMethod[orientClass, Pipal.describeMethod, NEW [Pipal.DescribeProc _ DescribeOrient]]; Pipal.PutClassMethod[orientClass, Pipal.hashMethod, NEW [Pipal.HashProc _ HashByEnumeration]]; Pipal.PutClassMethod[orientClass, Pipal.equalMethod, NEW [Pipal.EqualProc _ EqualByEnumeration]]; Pipal.PutClassMethod[abutClass, enumerateMethod, NEW [EnumerateProc _ EnumerateAbut]]; Pipal.PutClassMethod[abutClass, Pipal.describeMethod, NEW [Pipal.DescribeProc _ DescribeAbut]]; Pipal.PutClassMethod[abutClass, Pipal.hashMethod, NEW [Pipal.HashProc _ CachedHashByEnumeration]]; Pipal.PutClassMethod[abutClass, Pipal.equalMethod, NEW [Pipal.EqualProc _ EqualByEnumeration]]; Pipal.PutClassMethod[abutClass, sizeMethod, NEW [SizeProc _ CachedSizeFromEnumerate]]; Pipal.PutClassMethod[abutClass, bboxMethod, NEW [BBoxProc _ CachedBBoxFromEnumerate]]; Pipal.PutClassMethod[abutClass, abutBoxMethod, NEW [AbutBoxProc _ CachedAbutBoxFromEnumerate]]; END. <<>>