CharacterizeCubicImpl.mesa
Copyright Ó 1987, 1992 by Xerox Corporation. All rights reserved.
Maureen Stone, January 18, 1988 5:28:54 pm PST
Package for analyzing the characteristics of cubic segments
~
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] = {
Determines the type of Bezier curve
cuspVal, loopVal: REAL;
IF pt.y > 1 OR (pt.y =1 AND pt.x > 1) THEN RETURN[singleInflection];
Cull the vanilla region. We now know that y <= 1
IF pt.x>1 OR (pt.x>0 AND pt.y<0) THEN RETURN[vanilla];
We now know x <=1, y <=1
cuspVal ¬ pt.x*pt.x+4*pt.y-2*pt.x-3;
IF cuspVal=0 THEN RETURN[cusp];
IF cuspVal > 0 THEN RETURN[doubleInflection];
Now choose between the loop and the last vanilla case. We now know that x <1, y < 1
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] ~ {
Transform such that three points are on a unit square
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];
};