<> <> <> <> DIRECTORY II USING [Error, ErrorDesc], IIBox USING [Rectangle], IITransformation USING [FactoredTransformation, ScanMode, Transformation, TransformationRep], Real USING [FScale, RoundI, RoundLI, LargestNumber, TrappingNaN], RealFns USING [ArcTanDeg, CosDeg, SinDeg, SqRt], Rope USING [ROPE], SF USING [Box], Vector2 USING [VEC]; IITransformationImpl: CEDAR MONITOR IMPORTS II, Real, RealFns EXPORTS IITransformation ~ BEGIN OPEN IITransformation; VEC: TYPE ~ Vector2.VEC; Rectangle: TYPE ~ IIBox.Rectangle; ErrorDesc: TYPE ~ II.ErrorDesc; <<>> < interpress -> Interpress -> imager -> IIInterpress works.>> <<>> formErrorDesc: ErrorDesc ~ [code: $invalidTransformation, explanation: "Transformation has illegal form"]; Validate: PROC [m: Transformation] ~ { form: NAT _ 0; tx, ty: INTEGER _ 0; SELECT TRUE FROM m.form > 10 => form _ m.form; (m.b=0 AND m.d=0) => { form _ 1; IF m.a=+1 THEN { IF m.e=+1 THEN form _ 3 ELSE IF m.e=-1 THEN form _ 4 } ELSE IF m.a=-1 THEN { IF m.e=+1 THEN form _ 5 ELSE IF m.e=-1 THEN form _ 6 }; }; (m.a=0 AND m.e=0) => { form _ 2; IF m.b=+1 THEN { IF m.d=+1 THEN form _ 7 ELSE IF m.d=-1 THEN form _ 8 } ELSE IF m.b=-1 THEN { IF m.d=+1 THEN form _ 9 ELSE IF m.d=-1 THEN form _ 10 }; }; ENDCASE => NULL; IF ABS[m.c]<=INTEGER.LAST/2 THEN tx _ Real.RoundI[m.c]; IF ABS[m.f]<=INTEGER.LAST/2 THEN ty _ Real.RoundI[m.f]; m.form _ form; m.tx _ tx; m.ty _ ty; m.integerTrans _ (tx=m.c AND ty=m.f); }; nScratchMax: NAT ~ 3; nScratch: NAT _ 0; scratch: ARRAY [0..nScratchMax) OF Transformation _ ALL[NIL]; New: ENTRY PROC [rep: TransformationRep] RETURNS [Transformation] ~ { m: Transformation _ NIL; IF nScratch = 0 THEN m _ NEW[TransformationRep] ELSE {nScratch _ nScratch-1; m _ scratch[nScratch]; scratch[nScratch] _ NIL}; m^ _ rep; RETURN [m] }; MultipleReleaseOfScratch: ERROR ~ CODE; Destroy: PUBLIC ENTRY PROC [m: Transformation] ~ { IF m = NIL THEN RETURN WITH ERROR MultipleReleaseOfScratch; FOR i: NAT IN [0..nScratch) DO IF m = scratch[i] THEN RETURN WITH ERROR MultipleReleaseOfScratch; ENDLOOP; m.a _ m.b_ m.c _ m.d _ m.e _ m.f _ Real.TrappingNaN; m.form _ 0; m.integerTrans _ FALSE; IF nScratch < nScratchMax THEN { scratch[nScratch] _ m; nScratch _ nScratch + 1 }; }; Create: PUBLIC PROC [a, b, c, d, e, f: REAL] RETURNS [Transformation] ~ { new: Transformation ~ New[[a: a, b: b, c: c, d: d, e: e, f: f]]; Validate[new]; RETURN[new]; }; Scale: PUBLIC PROC [s: REAL] RETURNS [Transformation] ~ { new: Transformation ~ New[[a: s, b: 0, c: 0, d: 0, e: s, f: 0]]; Validate[new]; RETURN[new]; }; Scale2: PUBLIC PROC [s: VEC] RETURNS [Transformation] ~ { new: Transformation ~ New[[a: s.x, b: 0, c: 0, d: 0, e: s.y, f: 0]]; Validate[new]; RETURN[new]; }; Rotate: PUBLIC PROC [r: REAL] RETURNS [Transformation] ~ { cos: REAL ~ RealFns.CosDeg[r]; sin: REAL ~ RealFns.SinDeg[r]; new: Transformation ~ New[[a: cos, b: -sin, c: 0, d: sin, e: cos, f: 0]]; Validate[new]; RETURN[new]; }; Translate: PUBLIC PROC [t: VEC] RETURNS [Transformation] ~ { new: Transformation ~ New[[a: 1, b: 0, c: t.x, d: 0, e: 1, f: t.y]]; Validate[new]; RETURN[new]; }; SFToXY: PUBLIC PROC [scanMode: ScanMode, sSize, fSize: INT] RETURNS [Transformation] ~ { a: REAL ~ SELECT scanMode.slow FROM right => 1.0, left => -1.0, ENDCASE => 0.0; b: REAL ~ SELECT scanMode.fast FROM right => 1.0, left => -1.0, ENDCASE => 0.0; d: REAL ~ SELECT scanMode.slow FROM up => 1.0, down => -1.0, ENDCASE => 0.0; e: REAL ~ SELECT scanMode.fast FROM up => 1.0, down => -1.0, ENDCASE => 0.0; tX: REAL ~ MAX[-(a*sSize + b*fSize), 0]; tY: REAL ~ MAX[-(d*sSize + e*fSize), 0]; RETURN[Create[a, b, tX, d, e, tY]]; }; <<>> XYToSF: PUBLIC PROC [scanMode: ScanMode, sSize, fSize: INT] RETURNS [Transformation] ~ { m: Transformation ~ SFToXY[scanMode, sSize, fSize]; ApplyInvert[m]; RETURN[m]; }; Copy: PUBLIC PROC [m: Transformation] RETURNS [Transformation] ~ { IF m=NIL THEN RETURN[Scale[1]] ELSE RETURN[New[m^]]; }; Concat: PUBLIC PROC [m, n: Transformation] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPostConcat[new, n]; RETURN[new]; }; PreScale: PUBLIC PROC [m: Transformation, s: REAL] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPreScale[new, s]; RETURN[new]; }; PreScale2: PUBLIC PROC [m: Transformation, s: VEC] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPreScale2[new, s]; RETURN[new]; }; PreRotate: PUBLIC PROC [m: Transformation, r: REAL] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPreRotate[new, r]; RETURN[new]; }; PreTranslate: PUBLIC PROC [m: Transformation, t: VEC] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPreTranslate[new, t]; RETURN[new]; }; PostScale: PUBLIC PROC [m: Transformation, s: REAL] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPostScale[new, s]; RETURN[new]; }; PostScale2: PUBLIC PROC [m: Transformation, s: VEC] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPostScale2[new, s]; RETURN[new]; }; PostRotate: PUBLIC PROC [m: Transformation, r: REAL] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPostRotate[new, r]; RETURN[new]; }; PostTranslate: PUBLIC PROC [m: Transformation, t: VEC] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyPostTranslate[new, t]; RETURN[new]; }; TranslateTo: PUBLIC PROC [m: Transformation, t: VEC] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyTranslateTo[new, t]; RETURN[new]; }; Cat: PUBLIC PROC [m1, m2, m3, m4: Transformation _ NIL] RETURNS [Transformation] ~ { new: Transformation ~ NEW[TransformationRep]; ApplyCat[new, m1, m2, m3, m4]; RETURN[new]; }; Invert: PUBLIC PROC [m: Transformation] RETURNS [Transformation] ~ { new: Transformation ~ Copy[m]; ApplyInvert[new]; RETURN[new]; }; ApplyPreConcat: PUBLIC PROC [m, p: Transformation] ~ { old: TransformationRep ~ m^; IF p=NIL THEN RETURN; IF p.form > 10 THEN ERROR II.Error[formErrorDesc]; m.a _ p.a*old.a + p.d*old.b; m.d _ p.a*old.d + p.d*old.e; m.b _ p.b*old.a + p.e*old.b; m.e _ p.b*old.d + p.e*old.e; m.c _ p.c*old.a + p.f*old.b + old.c; m.f _ p.c*old.d + p.f*old.e + old.f; Validate[m]; }; ApplyPreScale: PUBLIC PROC [m: Transformation, s: REAL] ~ { old: TransformationRep ~ m^; m.a _ s*old.a; m.d _ s*old.d; m.b _ s*old.b; m.e _ s*old.e; Validate[m]; }; ApplyPreScale2: PUBLIC PROC [m: Transformation, s: VEC] ~ { old: TransformationRep ~ m^; m.a _ s.x*old.a; m.d _ s.x*old.d; m.b _ s.y*old.b; m.e _ s.y*old.e; Validate[m]; }; ApplyPreRotate: PUBLIC PROC [m: Transformation, r: REAL] ~ { old: TransformationRep ~ m^; cos: REAL ~ RealFns.CosDeg[r]; sin: REAL ~ RealFns.SinDeg[r]; m.a _ cos*old.a + sin*old.b; m.d _ cos*old.d + sin*old.e; m.b _ cos*old.b - sin*old.a; m.e _ cos*old.e - sin*old.d; Validate[m]; }; ApplyPreTranslate: PUBLIC PROC [m: Transformation, t: VEC] ~ { old: TransformationRep ~ m^; m.c _ t.x*old.a + t.y*old.b + old.c; m.f _ t.x*old.d + t.y*old.e + old.f; Validate[m]; }; ApplySFToXY: PUBLIC PROC [m: Transformation, scanMode: ScanMode, sSize, fSize: INT] ~ { old: TransformationRep ~ m^; X: TYPE ~ PROC [r: REAL] RETURNS [REAL]; A: X~INLINE{RETURN [SELECT scanMode.slow FROM right => r, left => -r, ENDCASE => 0.0]}; B: X~INLINE{RETURN [SELECT scanMode.fast FROM right => r, left => -r, ENDCASE => 0.0]}; D: X~INLINE{RETURN [SELECT scanMode.slow FROM up => r, down => -r, ENDCASE => 0.0]}; E: X~INLINE{RETURN [SELECT scanMode.fast FROM up => r, down => -r, ENDCASE => 0.0]}; c: REAL ~ MAX[-(A[sSize] + B[fSize]), 0]; f: REAL ~ MAX[-(D[sSize] + E[fSize]), 0]; m.a _ A[old.a] + D[old.b]; m.b _ B[old.a] + E[old.b]; m.c _ c*old.a + f*old.b + old.c; m.d _ A[old.d] + D[old.e]; m.e _ B[old.d] + E[old.e]; m.f _ c*old.d + f*old.e + old.f; Validate[m]; }; ApplyPostConcat: PUBLIC PROC [m, p: Transformation] ~ { old: TransformationRep ~ m^; IF p=NIL THEN RETURN; IF m.form > 10 THEN ERROR II.Error[formErrorDesc]; m.form _ p.form; m.a _ old.a*p.a + old.d*p.b; m.d _ old.a*p.d + old.d*p.e; m.b _ old.b*p.a + old.e*p.b; m.e _ old.b*p.d + old.e*p.e; m.c _ old.c*p.a + old.f*p.b + p.c; m.f _ old.c*p.d + old.f*p.e + p.f; Validate[m]; }; ApplyPostScale: PUBLIC PROC [m: Transformation, s: REAL] ~ { old: TransformationRep ~ m^; IF m.form > 10 THEN ERROR II.Error[formErrorDesc]; m.a _ old.a*s; m.d _ old.d*s; m.b _ old.b*s; m.e _ old.e*s; m.c _ old.c*s; m.f _ old.f*s; Validate[m]; }; ApplyPostScale2: PUBLIC PROC [m: Transformation, s: VEC] ~ { old: TransformationRep ~ m^; IF m.form > 10 THEN ERROR II.Error[formErrorDesc]; m.a _ old.a*s.x; m.d _ old.d*s.y; m.b _ old.b*s.x; m.e _ old.e*s.y; m.c _ old.c*s.x; m.f _ old.f*s.y; Validate[m]; }; ApplyPostRotate: PUBLIC PROC [m: Transformation, r: REAL] ~ { old: TransformationRep ~ m^; cos: REAL ~ RealFns.CosDeg[r]; sin: REAL ~ RealFns.SinDeg[r]; IF m.form > 10 THEN ERROR II.Error[formErrorDesc]; m.a _ old.a*cos - old.d*sin; m.d _ old.a*sin + old.d*cos; m.b _ old.b*cos - old.e*sin; m.e _ old.b*sin + old.e*cos; m.c _ old.c*cos - old.f*sin; m.f _ old.c*sin + old.f*cos; Validate[m]; }; ApplyPostTranslate: PUBLIC PROC [m: Transformation, t: VEC] ~ { old: TransformationRep ~ m^; IF m.form > 10 THEN ERROR II.Error[formErrorDesc]; m.c _ old.c+t.x; m.f _ old.f+t.y; Validate[m]; }; ApplyXYToSF: PUBLIC PROC [m: Transformation, scanMode: ScanMode, sSize, fSize: INT] ~ { post: Transformation ~ XYToSF[scanMode, sSize, fSize]; ApplyPostConcat[m, post]; Destroy[post]; }; ApplyTranslateTo: PUBLIC PROC [m: Transformation, t: VEC] ~ { tx, ty: INTEGER _ 0; IF m.form > 10 THEN ERROR II.Error[formErrorDesc]; IF ABS[t.x]<=INTEGER.LAST/2 THEN tx _ Real.RoundI[t.x]; IF ABS[t.y]<=INTEGER.LAST/2 THEN ty _ Real.RoundI[t.y]; m.c _ t.x; m.f _ t.y; m.tx _ tx; m.ty _ ty; m.integerTrans _ (tx=t.x AND ty=t.y); }; ApplyCat: PUBLIC PROC [m: Transformation, m1, m2, m3, m4: Transformation _ NIL] ~ { count: NAT _ 0; Apply: PROC [p: Transformation] ~ { IF count=0 THEN m^ _ p^ ELSE ApplyPostConcat[m, p]; count _ count+1; }; IF m1#NIL THEN Apply[m1]; IF m2#NIL THEN Apply[m2]; IF m3#NIL THEN Apply[m3]; IF m4#NIL THEN Apply[m4]; IF count=0 THEN { m^ _ [a: 1, b: 0, c: 0, d: 0, e: 1, f: 0]; Validate[m] }; }; ApplyInvert: PUBLIC PROC [m: Transformation] ~ { old: TransformationRep ~ m^; det: REAL ~ old.a*old.e - old.d*old.b; m.a _ old.e/det; m.d _ -old.d/det; m.b _ -old.b/det; m.e _ old.a/det; m.c _ (old.b*old.f - old.e*old.c)/det; m.f _ (old.d*old.c - old.a*old.f)/det; Validate[m]; }; Transform: PUBLIC PROC [m: Transformation, v: VEC] RETURNS [VEC] ~ { IF m=NIL THEN RETURN[v]; SELECT m.form FROM 0 => RETURN[[v.x*m.a + v.y*m.b + m.c, v.x*m.d + v.y*m.e + m.f]]; 1 => RETURN[[v.x*m.a + m.c, v.y*m.e + m.f]]; 2 => RETURN[[v.y*m.b + m.c, v.x*m.d + m.f]]; 3 => RETURN[[m.c + v.x, m.f + v.y]]; 4 => RETURN[[m.c + v.x, m.f - v.y]]; 5 => RETURN[[m.c - v.x, m.f + v.y]]; 6 => RETURN[[m.c - v.x, m.f - v.y]]; 7 => RETURN[[m.c + v.y, m.f + v.x]]; 8 => RETURN[[m.c + v.y, m.f - v.x]]; 9 => RETURN[[m.c - v.y, m.f + v.x]]; 10 => RETURN[[m.c - v.y, m.f - v.x]]; ENDCASE => ERROR II.Error[formErrorDesc]; }; TransformVec: PUBLIC PROC [m: Transformation, v: VEC] RETURNS [VEC] ~ { IF m=NIL THEN RETURN[v]; SELECT m.form FROM 0 => RETURN[[v.x*m.a + v.y*m.b, v.x*m.d + v.y*m.e]]; 1 => RETURN[[v.x*m.a, v.y*m.e]]; -- b=0, d=0 2 => RETURN[[v.y*m.b, v.x*m.d]]; -- a=0, e=0 3 => RETURN[[+ v.x, + v.y]]; -- a=+1, b=0, d=0, e=+1 4 => RETURN[[+ v.x, - v.y]]; -- a=+1, b=0, d=0, e=-1 5 => RETURN[[- v.x, + v.y]]; -- a=-1, b=0, d=0, e=+1 6 => RETURN[[- v.x, - v.y]]; -- a=-1, b=0, d=0, e=-1 7 => RETURN[[+ v.y, + v.x]]; -- a=0, b=+1, d=+1, e=0 8 => RETURN[[+ v.y, - v.x]]; -- a=0, b=+1, d=-1, e=0 9 => RETURN[[- v.y, + v.x]]; -- a=0, b=-1, d=+1, e=0 10 => RETURN[[- v.y, - v.x]]; -- a=0, b=-1, d=-1, e=0 ENDCASE => ERROR II.Error[formErrorDesc]; }; InverseTransform: PUBLIC PROC [m: Transformation, v: VEC] RETURNS [VEC] ~ { IF m=NIL THEN RETURN[v]; RETURN[InverseTransformVec[m, [v.x - m.c, v.y - m.f]]]; }; InverseTransformVec: PUBLIC PROC [m: Transformation, v: VEC] RETURNS [VEC] ~ { IF m=NIL THEN RETURN[v]; SELECT m.form FROM 0 => { D: REAL ~ m.a*m.e-m.b*m.d; RETURN[[(v.x*m.e-v.y*m.b)/D, (v.y*m.a-v.x*m.d)/D]] }; 1 => RETURN[[v.x/m.a, v.y/m.e]]; -- b=0, d=0 2 => RETURN[[v.y/m.d, v.x/m.b]]; -- a=0, e=0 3 => RETURN[[+ v.x, + v.y]]; -- a=+1, b=0, d=0, e=+1 4 => RETURN[[+ v.x, - v.y]]; -- a=+1, b=0, d=0, e=-1 5 => RETURN[[- v.x, + v.y]]; -- a=-1, b=0, d=0, e=+1 6 => RETURN[[- v.x, - v.y]]; -- a=-1, b=0, d=0, e=-1 7 => RETURN[[+ v.y, + v.x]]; -- a=0, b=+1, d=+1, e=0 8 => RETURN[[- v.y, + v.x]]; -- a=0, b=+1, d=-1, e=0 9 => RETURN[[+ v.y, - v.x]]; -- a=0, b=-1, d=+1, e=0 10 => RETURN[[- v.y, - v.x]]; -- a=0, b=-1, d=-1, e=0 ENDCASE => ERROR II.Error[formErrorDesc]; }; InlineRound: PROC [x: REAL] RETURNS [REAL] ~ INLINE { RETURN[IF ABS[x]<100000000B THEN REAL[Real.RoundLI[x]] ELSE x]; }; DRound: PUBLIC PROC [v: VEC] RETURNS [VEC] ~ { RETURN[[InlineRound[v.x], InlineRound[v.y]]] }; RoundXY: PUBLIC PROC [m: Transformation, v: VEC] RETURNS [VEC] ~ { RETURN[InverseTransform[m, DRound[Transform[m, v]]]]; }; RoundXYVec: PUBLIC PROC [m: Transformation, v: VEC] RETURNS [VEC] ~ { RETURN[InverseTransformVec[m, DRound[TransformVec[m, v]]]]; }; TransformRectangle: PUBLIC PROC [m: Transformation, r: Rectangle] RETURNS [Rectangle] ~ { IF m=NIL THEN RETURN[r]; IF m.form=0 THEN { p0: VEC ~ Transform[m, [r.x, r.y]]; p1: VEC ~ Transform[m, [r.x+r.w, r.y]]; p2: VEC ~ Transform[m, [r.x+r.w, r.y+r.h]]; p3: VEC ~ Transform[m, [r.x, r.y+r.h]]; xmin, xmax: REAL _ p0.x; ymin, ymax: REAL _ p0.y; IF p1.xxmax THEN xmax _ p1.x; IF p1.yymax THEN ymax _ p1.y; IF p2.xxmax THEN xmax _ p2.x; IF p2.yymax THEN ymax _ p2.y; IF p3.xxmax THEN xmax _ p3.x; IF p3.yymax THEN ymax _ p3.y; RETURN[[x: xmin, y: ymin, w: xmax-xmin, h: ymax-ymin]]; } ELSE { p0: VEC ~ Transform[m, [r.x, r.y]]; p2: VEC ~ Transform[m, [r.x+r.w, r.y+r.h]]; xmin, xmax: REAL _ p0.x; ymin, ymax: REAL _ p0.y; IF p2.xxmax THEN xmax _ p2.x; IF p2.yymax THEN ymax _ p2.y; RETURN[[x: xmin, y: ymin, w: xmax-xmin, h: ymax-ymin]]; }; }; InverseTransformRectangle: PUBLIC PROC [m: Transformation, r: Rectangle] RETURNS [Rectangle] ~ { IF m=NIL THEN RETURN[r]; SELECT m.form FROM 0 => { p0: VEC ~ InverseTransform[m, [r.x, r.y]]; p1: VEC ~ InverseTransform[m, [r.x+r.w, r.y]]; p2: VEC ~ InverseTransform[m, [r.x+r.w, r.y+r.h]]; p3: VEC ~ InverseTransform[m, [r.x, r.y+r.h]]; xmin, xmax: REAL _ p0.x; ymin, ymax: REAL _ p0.y; IF p1.xxmax THEN xmax _ p1.x; IF p1.yymax THEN ymax _ p1.y; IF p2.xxmax THEN xmax _ p2.x; IF p2.yymax THEN ymax _ p2.y; IF p3.xxmax THEN xmax _ p3.x; IF p3.yymax THEN ymax _ p3.y; RETURN[[x: xmin, y: ymin, w: xmax-xmin, h: ymax-ymin]]; }; <= 10 => { p0: VEC ~ InverseTransform[m, [r.x, r.y]]; p2: VEC ~ InverseTransform[m, [r.x+r.w, r.y+r.h]]; xmin, xmax: REAL _ p0.x; ymin, ymax: REAL _ p0.y; IF p2.xxmax THEN xmax _ p2.x; IF p2.yymax THEN ymax _ p2.y; RETURN[[x: xmin, y: ymin, w: xmax-xmin, h: ymax-ymin]]; }; ENDCASE => ERROR II.Error[formErrorDesc]; }; RestrictAbsTo: PROC [limit: REAL, real: REAL] RETURNS [REAL] ~ { <> limit _ ABS[limit]; WHILE real < -limit DO real _ real + 2*limit ENDLOOP; WHILE real >= limit DO real _ real - 2*limit ENDLOOP; RETURN[real] }; EasyTransformBox: PUBLIC PROC [m: Transformation, x, y, w, h: INTEGER, clip: SF.Box] RETURNS [SF.Box] ~ { assert: BOOL[TRUE..TRUE] ~ m.form>=3 AND m.integerTrans; x0: INT ~ INT[x]; y0: INT ~ INT[y]; x1: INT ~ x0+INT[w]; y1: INT ~ y0+INT[h]; ts: INT ~ INT[m.tx]; tf: INT ~ INT[m.ty]; s0, s1, f0, f1: INT; box: SF.Box _ clip; SELECT m.form FROM 3 => { s0 _ ts + x0; s1 _ ts + x1; f0 _ tf + y0; f1 _ tf + y1 }; 4 => { s0 _ ts + x0; s1 _ ts + x1; f0 _ tf - y0; f1 _ tf - y1 }; 5 => { s0 _ ts - x0; s1 _ ts - x1; f0 _ tf + y0; f1 _ tf + y1 }; 6 => { s0 _ ts - x0; s1 _ ts - x1; f0 _ tf - y0; f1 _ tf - y1 }; 7 => { s0 _ ts + y0; s1 _ ts + y1; f0 _ tf + x0; f1 _ tf + x1 }; 8 => { s0 _ ts + y0; s1 _ ts + y1; f0 _ tf - x0; f1 _ tf - x1 }; 9 => { s0 _ ts - y0; s1 _ ts - y1; f0 _ tf + x0; f1 _ tf + x1 }; 10 => { s0 _ ts - y0; s1 _ ts - y1; f0 _ tf - x0; f1 _ tf - x1 }; ENDCASE => ERROR; IF s0 > s1 THEN { s2: INT ~ s0; s0 _ s1; s1 _ s2 }; IF f0 > f1 THEN { f2: INT ~ f0; f0 _ f1; f1 _ f2 }; IF s0 > box.max.s THEN s0 _ s1 _ box.max.s; IF s1 < box.min.s THEN s0 _ s1 _ box.min.s; IF f0 > box.max.f THEN f0 _ f1 _ box.max.f; IF f1 < box.min.f THEN f0 _ f1 _ box.min.f; IF s0 > box.min.s THEN box.min.s _ s0; IF s1 < box.max.s THEN box.max.s _ s1; IF f0 > box.min.f THEN box.min.f _ f0; IF f1 < box.max.f THEN box.max.f _ f1; RETURN[box]; }; Singular: PUBLIC PROC [m: Transformation] RETURNS [BOOL] ~ { det: REAL ~ m.a*m.e - m.d*m.b; IF ABS[det] >= 0.01 THEN RETURN [FALSE]; IF det = 0 THEN RETURN [TRUE]; RETURN [MAX[ABS[m.a], ABS[m.b], ABS[m.d], ABS[m.e]] >= (Real.LargestNumber)*0.125*det] }; NumericalInstability: PUBLIC SIGNAL [real: REAL] ~ CODE; maxRelError: REAL _ 1.0e-4; Factor: PUBLIC PROC [m: Transformation] RETURNS [FactoredTransformation] ~ { IF m=NIL THEN RETURN[[r1: 0, s: [1, 1], r2: 0, t: [0, 0]]]; SELECT m.form FROM 0 => { t: TransformationRep ~ m^; theta: REAL ~ RestrictAbsTo[45, 0.5*RealFns.ArcTanDeg[2*(t.a*t.b+t.d*t.e), (t.a*t.a-t.b*t.b+t.d*t.d-t.e*t.e)]]; cosTheta: REAL ~ RealFns.CosDeg[theta]; sinTheta: REAL ~ RealFns.SinDeg[theta]; aa: REAL ~ cosTheta*t.a + sinTheta*t.b; bb: REAL ~ -sinTheta*t.a + cosTheta*t.b; dd: REAL ~ cosTheta*t.d + sinTheta*t.e; ee: REAL ~ -sinTheta*t.d + cosTheta*t.e; phi: REAL ~ RestrictAbsTo[90, IF ABS[aa]>ABS[ee] THEN RealFns.ArcTanDeg[-dd, aa] ELSE RealFns.ArcTanDeg[bb, ee]]; cosPhi: REAL ~ RealFns.CosDeg[phi]; sinPhi: REAL ~ RealFns.SinDeg[phi]; a: REAL ~ aa*cosPhi - dd*sinPhi; b: REAL ~ bb*cosPhi - ee*sinPhi; d: REAL ~ aa*sinPhi + dd*cosPhi; e: REAL ~ bb*sinPhi + ee*cosPhi; mag: REAL ~ ABS[a]+ABS[d]; IF ABS[b]+ABS[d] > maxRelError*mag THEN SIGNAL NumericalInstability[ABS[b]+ABS[d]]; RETURN[[r1: -theta, s: [a, e], r2: -phi, t: [t.c, t.f]]] }; 1 => RETURN[[r1: 0, s: [m.a, m.e], r2: 0, t: [m.c, m.f]]]; 2 => { IF m.b > 0 THEN RETURN[[r1: 0, s: [-m.d, m.b], r2: -90, t: [m.c, m.f]]] ELSE RETURN[[r1: 0, s: [m.d, -m.b], r2: 90, t: [m.c, m.f]]]; }; 3 => RETURN[[r1: 0, s: [1, 1], r2: 0, t: [m.c, m.f]]]; 4 => RETURN[[r1: 0, s: [1, -1], r2: 0, t: [m.c, m.f]]]; 5 => RETURN[[r1: 0, s: [-1, 1], r2: 0, t: [m.c, m.f]]]; 6 => RETURN[[r1: 0, s: [-1, -1], r2: 0, t: [m.c, m.f]]]; 7 => RETURN[[r1: 0, s: [1, -1], r2: 90, t: [m.c, m.f]]]; 8 => RETURN[[r1: 0, s: [1, 1], r2: -90, t: [m.c, m.f]]]; 9 => RETURN[[r1: 0, s: [1, 1], r2: 90, t: [m.c, m.f]]]; 10 => RETURN[[r1: 0, s: [-1, 1], r2: 90, t: [m.c, m.f]]]; ENDCASE => ERROR II.Error[formErrorDesc]; }; Equal: PUBLIC PROC [s, t: Transformation] RETURNS [BOOL] ~ { RETURN [s.a=t.a AND s.b=t.b AND s.c=t.c AND s.d=t.d AND s.e=t.e AND s.f=t.f]; }; WithinQuarterPixel: PROC [p, q: VEC] RETURNS [BOOL] ~ { RETURN [ABS[p.x-q.x] <= 0.25 AND ABS[p.y-q.y] <= 0.25] }; CloseEnough: PUBLIC PROC [s, t: Transformation, range: REAL] RETURNS [BOOL] ~ { p00: VEC _ Transform[s, InverseTransform[t, [0, 0]]]; p10: VEC _ Transform[s, InverseTransform[t, [range, 0]]]; p01: VEC _ Transform[s, InverseTransform[t, [0, range]]]; RETURN [ WithinQuarterPixel[p00, [0, 0]] AND WithinQuarterPixel[p10, [range, 0]] AND WithinQuarterPixel[p01, [0, range]] ] }; CloseToTranslation: PUBLIC PROC [s, t: Transformation, range: REAL] RETURNS [BOOL] ~ { p10: VEC _ TransformVec[s, InverseTransformVec[t, [range, 0]]]; p01: VEC _ TransformVec[s, InverseTransformVec[t, [0, range]]]; RETURN [ WithinQuarterPixel[p10, [range, 0]] AND WithinQuarterPixel[p01, [0, range]] ] }; SingularValues: PUBLIC PROC [m: Transformation] RETURNS [VEC] ~ { t1: REAL _ m.a*m.a + m.d*m.d; t2: REAL _ m.b*m.b + m.e*m.e; t3: REAL _ t1 - t2; t4: REAL _ Real.FScale[m.a*m.b + m.d*m.e, 1]; s: REAL _ RealFns.SqRt[t3*t3+t4*t4]; x: REAL _ RealFns.SqRt[Real.FScale[t1+t2+s, -1]]; y: REAL _ RealFns.SqRt[Real.FScale[t1+t2-s, -1]]; RETURN[[x, y]] }; fuzz: REAL _ 2.0e-6; Different: PROC [a, b: REAL] RETURNS [BOOL] ~ { IF ABS[a-b] < fuzz THEN RETURN [FALSE]; RETURN [ABS[a - b]/MAX[ABS[a], ABS[b]] > fuzz]; }; ShouldBeSameT: PROC [s, t: Transformation] ~ { IF Different[s.a, t.a] THEN ERROR; IF Different[s.b, t.b] THEN ERROR; IF Different[s.c, t.c] THEN ERROR; IF Different[s.d, t.d] THEN ERROR; IF Different[s.e, t.e] THEN ERROR; IF Different[s.f, t.f] THEN ERROR; }; ShouldBeSamePt: PROC [p, q: VEC] ~ { IF Different[p.x, q.x] THEN ERROR; IF Different[p.y, q.y] THEN ERROR; }; TestTransformation: PROC [r: Transformation] ~ { p: VEC _ [3.14159, -265.35]; ShouldBeSameT[PreTranslate[r, p], Concat[Translate[p], r]]; ShouldBeSameT[Rotate[0], Concat[r, Invert[r]]]; ShouldBeSamePt[InverseTransform[r, p], Transform[Invert[r], p]]; ShouldBeSamePt[InverseTransformVec[r, p], TransformVec[Invert[r], p]]; ShouldBeSamePt[TransformVec[r, TransformVec[r, p]], TransformVec[Concat[r, r], p]]; ShouldBeSamePt[SingularValues[r], SingularValues[PreRotate[r, 33.5]]]; }; SelfTest: PROC ~ { ShouldBeSameT[Rotate[90], Concat[Rotate[45], Rotate[45]]]; TestTransformation[PreTranslate[PreScale2[Rotate[61], [1, 5]], [12, 6]]]; TestTransformation[Create[1, 2, 4, 9, 3, 1]]; TestTransformation[Create[3, 1, 4, 1, 5, 9]]; TestTransformation[Create[2, 0, 0, 0, 2, 0]]; TestTransformation[Create[0, 3, 0, 4, 0, 0]]; TestTransformation[Create[1, 0, 0, 0, 1, 0]]; TestTransformation[Create[1, 0, 0, 0, -1, 808]]; TestTransformation[Create[-1, 0, 0, 0, 1, 0]]; TestTransformation[Create[-1, 0, 0, 0, -1, 0]]; TestTransformation[Create[0, 1, 0, 1, 0, 0]]; TestTransformation[Create[0, 1, 0, -1, 0, 0]]; TestTransformation[Create[0, -1, 0, 1, 0, 0]]; TestTransformation[Create[0, -1, 0, -1, 0, 0]]; }; <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> <> <> <> <> <> <> <> <> <new.x DO x0 _ x0-1 ENDLOOP;>> <new.y DO y0 _ y0-1 ENDLOOP;>> <> <> <> <<};>> <<>> END.