<*PRAGMA LL*>A
Path.T
is a sequence of straight and curved line segments,
suitable for stroking or filling.
A {\it segment} is a directed arc in the Cartesian plane determined
by two cubic polynomials h(t)
, v(t)
, where t
ranges over the
interval of real numbers [0, 1]
. The segment is said to {\it start}
at (h(0), v(0))
and {\it end} at (h(1), v(1))
. If h
and v
are linear functions of t
, then the segment is {\it linear}: it
consists of a line segment. If h
and v
are constant functions of
t
, then the segment is {\it degenerate}: it consists of a single
point.
The segments of a path are grouped into contiguous {\it subpaths}, which can be {\it open} or {\it closed}. Within a subpath, each segment starts where the previous segment ends. In a closed subpath, the last segment ends where the first segment starts. (This may also happen for an open subpath, but this coincidence does not make the subpath closed.)
The {\it current point} of a path is the endpoint of the last segment of its last subpath, assuming this subpath is open. If the path is empty or if the last subpath is closed, the current point is undefined.
INTERFACEThe callPath ; IMPORT Point, Rect; TYPE T <: ROOT;
NEW(Path.T)
creates an empty path.
PROCEDURE Reset(path: T);
Set path
to be empty.
PROCEDURE MoveTo(path: T; READONLY p: Point.T);
Extendpath
with a new degenerate segment that starts and ends atp
. This begins a new subpath.
PROCEDURE LineTo(path: T; READONLY p: Point.T);
Extendpath
with a linear segment that starts at its current point and ends atp
.
PROCEDURE CurveTo(path: T; READONLY q, r, s: Point.T);
Extendpath
with a curved segment that starts at its current point and ends ats
.
CurveTo
adds a curve that starts from the current point of path
in the direction of q
, and ends at s
coming from the direction
of r
. More precisely, let p
be the current point of path
and let h(t)
and v(t)
be the cubic polynomials such that
(h(0), v(0)) = p (h(1), v(1)) = s (h'(0), v'(0)) = 3 * (q - p) (h'(1), v'(1)) = 3 * (s - r)(Where the primes denote differentiation with respect to
t
.) Then
CurveTo
adds the segment (h(t), v(t))
for t
between zero and
one. (This is called the {\it Bezier} arc determined by p
, q
,
r
, and s
.)
PROCEDURE Close(path: T);
Add a linear segment to create a closed loop in path
.
More precisely, let
p
be the current point of path
, and let
q
be last point of path
that was added by a call to MoveTo
(Thus q
is the startpoint of the first segment of the last subpath
of path
.) Close
adds a linear segment from p
to q
and marks
the sequence of segments from q
to the end of the path as a closed
subpath.
PROCEDURE IsEmpty(p: T): BOOLEAN;
ReturnsTRUE
ifp
is empty.
PROCEDURE IsClosed(p: T): BOOLEAN;
ReturnsTRUE
ifp
is empty or the last subpath ofp
is closed.
PROCEDURE CurrentPoint(p: T): Point.T;
Returns the current point of p
.
LineTo
, CurveTo
, Close
, and CurrentPoint
are checked runtime
errors if the path has no current point.
EXCEPTION Malformed;The
Malformed
exception is raised when a procedure detects
a malformed path.
PROCEDURE Translate(p: T; READONLY delta: Point.T): T RAISES {Malformed};
The result of translatingp
bydelta
.
TYPE MapObject = OBJECT METHODS move(READONLY pt: Point.T); line(READONLY pt1, pt2: Point.T); close(READONLY pt1, pt2: Point.T); curve(READONLY pt1, pt2, pt3, pt4: Point.T) END; PROCEDURE Map(path: T; map: MapObject) RAISES {Malformed};
Apply the appropriate method ofmap
to each segment ofpath
.
That is, for each segment
s
of path
, in order, Map
excecutes
the following:
IF s is a linear segment (p, q) THEN IF s was generated by MoveTo THEN (* p = q| map.move(p) | ELSIF s `was generated by` LineTo THEN | map.line(p, q) | ELSE (* s `was generated by` Close *) | map.close(p, q) | END | ELSE (* s `is a curved segment` (p, q, r, s) *) | map.curve(p, q, r, s) | END "Map" raises the exception if it is passed a malformed path. *) PROCEDURE Copy(p: T): T;Returns a newly allocated path with the same contents asp
.PROCEDURE Flatten(p: T): T RAISES {Malformed};Return a path likep
but with curved segments replaced by polygonal approximations.PROCEDURE BoundingBox(p: T): Rect.T RAISES {Malformed};Return a rectangle that contains all points ofp
, and that is as small as convenient to compute.END Path.