CharacterizeCubicImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Maureen Stone, January 18, 1988 5:28:54 pm PST
Package for analyzing the characteristics of cubic segments
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] = {
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: BOOLEANFALSE;
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.