ImagerPath.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, November 11, 1985 3:38:32 pm PST
DIRECTORY
ImagerTransformation USING [Transformation],
Vector2 USING [VEC];
ImagerPath: CEDAR DEFINITIONS
~ BEGIN
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ ImagerTransformation.Transformation;
General Paths
MoveToProc: TYPE ~ PROC [p: VEC];
LineToProc: TYPE ~ PROC [p1: VEC];
CurveToProc: TYPE ~ PROC [p1, p2, p3: VEC];
ConicToProc: TYPE ~ PROC [p1, p2: VEC, r: REAL];
ArcToProc: TYPE ~ PROC [p1, p2: VEC];
PathProc: TYPE ~ PROC [moveTo: MoveToProc, lineTo: LineToProc,
curveTo: CurveToProc, conicTo: ConicToProc, arcTo: ArcToProc];
A PathProc defines a path by calling moveTo, lineTo, ... in sequence.
Its caller supplies moveTo, lineTo, ... procedures and maintains p0: VEC ← [0, 0].
moveTo[p] begins a new trajectory at p; p0 ← p.
lineTo[p1] extends a straight line from p0 to p1; p0 ← p1.
curveTo[p1, p2, p3] extends a cubic curve from p0 (controlled by p1, p2) to p3; p0 ← p3.
The curve segment is defined by four Bezier control points: p0, p1, p2, p3.
It begins at p0, tangent to [p0, p1], and ends at p3, tangent to [p2, p3].
The curve is bounded by the quadrilateral [p0, p1, p2, p3].
conicTo[p1, p2, r] extends a conic curve from p0 (controlled by p1, r) to p2; p0 ← p2.
Let m be the midpoint of [p0, p2].
Let p be the point on [m, p1] such that Length[m, p]/Length[m, p1] = r.
The curve starts at p0, passes through p, and ends at p2.
It is a line if r=0; an ellipse if 0<r<1/2; a parabola if r=1/2; a hyperbola if 1/2<r<1.
The curve is bounded by the triangle [p0, p1, p2].
arcTo[p1, p2] extends a circular arc from p0 (controlled by p1) to p2; p0 ← p2.
The arc begins at p0, passes through p1, and ends at p2.
It is best for p1 to lie near the halfway point along the arc.
If p0 and p2 are coincident, the result is a circle: p1 lies diametrically opposite p0.
If p0, p1, and p2 are colinear, the effect is { lineTo[p1]; lineTo[p2] }.
ConicToCurves: PROC [p0, p1, p2: VEC, r: REAL, curveTo: CurveToProc];
Turns a conic into a sequence of cubic curves. The first curve begins at p0.
Unless the conic is a parabola, this will necessarily involve some approximation, but the error will be in the range of floating-point fuzz.
ArcToConics: PROC [p0, p1, p2: VEC, conicTo: ConicToProc];
Turns an arc into a sequence of conics. The first conic begins at p0.
Filter: PROC [path: PathProc,
moveTo: MoveToProc ←, lineTo: LineToProc ←, curveTo: CurveToProc ←,
conicTo: ConicToProc ← NIL, arcTo: ArcToProc ← NIL, close: PROCNIL];
Transform: PROC [path: PathProc, m: Transformation ← NIL,
moveTo: MoveToProc ←, lineTo: LineToProc ←, curveTo: CurveToProc ←,
conicTo: ConicToProc ← NIL, arcTo: ArcToProc ← NIL, close: PROCNIL];
Trajectories and Outlines
Trajectory: TYPE ~ REF TrajectoryRep;
TrajectoryRep: TYPE ~ RECORD [
prev: Trajectory, -- preceding trajectory
length: INT, -- number of segments in the trajectory
lp: VEC, -- the last point
variant: SELECT tag: * FROM
move => [], -- begin new trajectory: moveTo[lp]
line => [], -- straight line: lineTo[lp]
curve => [p1, p2: VEC], -- cubic curve: curveTo[p1, p2, lp]
conic => [p1: VEC, r: REAL], -- conic curve: conicTo[p1, lp, r]
arc => [p1: VEC], -- circular arc: arcTo[p1, lp]
ENDCASE
];
A Trajectory is an immutable value. MoveTo creates a Trajectory; other operations take a Trajectory, extend it with a straight or curved segment, and return a new Trajectory. Every trajectory has a last point (lp), the end point of the trajectory's last segment.
LastPoint: PROC [t: Trajectory] RETURNS [VEC];
Return t's lp.
MoveTo: PROC [p: VEC] RETURNS [Trajectory];
Create a new trajectory, with a single vertex. The result's lp is p0.
LineTo: PROC [t: Trajectory, p1: VEC] RETURNS [Trajectory];
LineToX: PROC [t: Trajectory, x: REAL] RETURNS [Trajectory];
LineToY: PROC [t: Trajectory, y: REAL] RETURNS [Trajectory];
LineTo extends t with a straight line segment. The result's lp is p1.
LineToX[t, x] is equivalent to LineTo[t, [x, t.lp.y]].
LineToY[t, y] is equivalent to LineTo[t, [t.lp.x, y]].
CurveTo: PROC [t: Trajectory, p1, p2, p3: VEC] RETURNS [Trajectory];
CurveTo extends t with a cubic curve segment. The result's lp is p3.
ConicTo: PROC [t: Trajectory, p1, p2: VEC, r: REAL] RETURNS [Trajectory];
ConicTo extends t with a segment of a conic section. The result's lp is p2.
ArcTo: PROC [t: Trajectory, p1, p2: VEC] RETURNS [Trajectory];
ArcTo extends t with a circular arc. The result's lp is p2.
MapTrajectory: PROC [trajectory: Trajectory,
moveTo: MoveToProc, lineTo: LineToProc, curveTo: CurveToProc,
conicTo: ConicToProc, arcTo: ArcToProc];
MapTrajectoryBackward: PROC [trajectory: Trajectory,
moveTo: MoveToProc, lineTo: LineToProc, curveTo: CurveToProc,
conicTo: ConicToProc, arcTo: ArcToProc];
TrajectoryList: TYPE ~ LIST OF Trajectory;
MapTrajectoryList: PROC [trajectoryList: TrajectoryList,
moveTo: MoveToProc, lineTo: LineToProc, curveTo: CurveToProc,
conicTo: ConicToProc, arcTo: ArcToProc];
Outline: TYPE ~ REF OutlineRep;
OutlineRep: TYPE ~ RECORD [oddWrap: BOOL, seq: SEQUENCE size: NAT OF Trajectory];
MapOutline: PROC [outline: Outline,
moveTo: MoveToProc, lineTo: LineToProc, curveTo: CurveToProc,
conicTo: ConicToProc, arcTo: ArcToProc];
TrajectoriesFromPath: PROC [path: PathProc, m: Transformation ← NIL,
action: PROC [Trajectory]];
TrajectoryListFromPath: PROC [path: PathProc, m: Transformation ← NIL]
RETURNS
[TrajectoryList];
OutlineFromPath: PROC [path: PathProc, oddWrap: BOOLFALSE, m: Transformation ← NIL]
RETURNS [Outline];
END.