<> <> <> <<>> <> <<>> DIRECTORY CharacterizeCubic, Cubic2 USING [Bezier], Imager USING [VEC], ImagerTransformation USING [Transformation, Create, ApplyPreTranslate]; CharacterizeCubicImpl: CEDAR PROGRAM IMPORTS ImagerTransformation EXPORTS CharacterizeCubic ~ BEGIN Bezier: TYPE ~ Cubic2.Bezier; VEC: TYPE ~ Imager.VEC; Type: TYPE ~ CharacterizeCubic.Type; GetType: PUBLIC PROC [bezier: Bezier] RETURNS [Type] = { pt: VEC _ GetCanonicalPoint[bezier ! Colinear => GOTO degenerate]; RETURN[GetTypeFromMapped[pt]]; EXITS degenerate => RETURN[degenerate]; }; GetTypeFromMapped: PUBLIC PROC [pt: VEC] RETURNS [Type] = { <> cuspVal, loopVal: REAL; IF pt.y > 1 OR (pt.y =1 AND pt.x > 1) THEN RETURN[singleInflection]; <> IF pt.x>1 OR (pt.x>0 AND pt.y<0) THEN RETURN[vanilla]; <> cuspVal _ pt.x*pt.x+4*pt.y-2*pt.x-3; IF cuspVal=0 THEN RETURN[cusp]; IF cuspVal > 0 THEN RETURN[doubleInflection]; <> loopVal _ IF pt.y > 0 THEN (pt.x*pt.x+pt.y*pt.y+pt.x*pt.y-3*pt.x) ELSE (pt.x*pt.x-3*pt.x+3*pt.y); IF loopVal >= 0 THEN RETURN[loop] ELSE RETURN[vanilla]; }; GetCanonicalPoint: PUBLIC PROC [bezier: Bezier] RETURNS [pt: VEC] ~ { <> tryAgain: BOOLEAN _ FALSE; a,b,d,e: REAL; t: VEC; FastSixPoints: PROC[from0,from1, from2, to0, to1, to2: VEC] RETURNS[a,b,d,e: REAL, t: VEC] = { dp0, dp1, dp2, dp3: VEC; del: REAL; dp0.x _ from1.x-from0.x; dp0.y _ from1.y-from0.y; dp1.x _ from2.x-from0.x; dp1.y _ from2.y-from0.y; dp2.x _ to1.x-to0.x; dp2.y _ to1.y-to0.y; dp3.x _ to2.x-to0.x; dp3.y _ to2.y-to0.y; del _ dp0.x*dp1.y-dp1.x*dp0.y; IF del=0 THEN SIGNAL Colinear; a _ (dp2.x*dp1.y-dp3.x*dp0.y)/del; b _ (dp0.x*dp3.x-dp1.x*dp2.x)/del; d _ (dp2.y*dp1.y-dp3.y*dp0.y)/del; e _ (dp0.x*dp3.y-dp1.x*dp2.y)/del; t.x_ to0.x-from0.x; t.y_ to0.y-from0.y; }; pt _ bezier.b3; [a,b,d,e,t] _ FastSixPoints[bezier.b0, bezier.b1, bezier.b2, [0,0],[0,1],[1,1] ! Colinear => {tryAgain _ TRUE; CONTINUE}]; IF tryAgain THEN { [a,b,d,e,t] _ FastSixPoints[bezier.b3, bezier.b2, bezier.b1, [0,0],[0,1],[1,1]]; pt _ bezier.b0; }; pt _ [pt.x+t.x, pt.y+t.y]; pt _ [pt.x*a + pt.y*b, pt.x*d + pt.y*e]; }; Colinear: PUBLIC SIGNAL = CODE; SixPoints: PUBLIC PROC[from0,from1, from2, to0, to1, to2: VEC] RETURNS[transform: ImagerTransformation.Transformation] = { dp0, dp1, dp2, dp3: VEC; a,b,d,e: REAL; del: REAL; xform: ImagerTransformation.Transformation; dp0.x _ from1.x-from0.x; dp0.y _ from1.y-from0.y; dp1.x _ from2.x-from0.x; dp1.y _ from2.y-from0.y; dp2.x _ to1.x-to0.x; dp2.y _ to1.y-to0.y; dp3.x _ to2.x-to0.x; dp3.y _ to2.y-to0.y; del _ dp0.x*dp1.y-dp1.x*dp0.y; IF del=0 THEN SIGNAL Colinear; a _ (dp2.x*dp1.y-dp3.x*dp0.y)/del; b _ (dp0.x*dp3.x-dp1.x*dp2.x)/del; d _ (dp2.y*dp1.y-dp3.y*dp0.y)/del; e _ (dp0.x*dp3.y-dp1.x*dp2.y)/del; xform _ ImagerTransformation.Create[a: a, b: b, c: to0.x, d: d, e: e, f: to0.y]; ImagerTransformation.ApplyPreTranslate[xform, [x: -from0.x, y: -from0.y]]; RETURN[xform]; }; <<>> END.