PSPathImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Doug Wyatt, March 26, 1987 1:17:22 pm PST
PostScript implementation: path operators.
DIRECTORY
PS,
Vector2;
PSPathImpl: CEDAR PROGRAM
IMPORTS PS, Vector2
~ BEGIN OPEN PS;
Path construction operators
CurrentPoint: PROC [path: Path] RETURNS [VEC] ~ {
IF path=NIL THEN ERROR Error[nocurrentpoint];
RETURN [path.first.point];
};
MoveTo: PROC [path: Path, p: VEC] RETURNS [Path] ~ {
IF path#NIL AND path.first.type=move THEN path ← path.rest;
RETURN [CONS[[move, p], path]];
};
LineTo: PROC [path: Path, p: VEC] RETURNS [Path] ~ {
IF path=NIL THEN ERROR Error[nocurrentpoint];
RETURN [CONS[[line, p], path]];
};
CurveTo: PROC [path: Path, p1, p2, p3: VEC] RETURNS [Path] ~ {
IF path=NIL THEN ERROR Error[nocurrentpoint];
RETURN [CONS[[curve, p3], CONS[[curve, p2], CONS[[curve, p1], path]]]];
};
ClosePath: PROC [path: Path] RETURNS [Path] ~ {
IF path=NIL OR path.first.type=close THEN RETURN [path];
FOR each: Path ← path, path.rest UNTIL path=NIL DO
SELECT each.first.type FROM
move, close => RETURN [CONS[[close, each.first.point], path]];
ENDCASE;
ENDLOOP;
RETURN [path]; -- should never happen
};
MapPath: PROC [path: Path,
moveTo: PROC [p: VEC],
lineTo: PROC [p: VEC],
curveTo: PROC [p1, p2, p3: VEC],
closePath: PROC
] ~ {
prev: Path ← NIL;
IF path=NIL THEN RETURN;
prev ← path.rest;
IF path.first.type=curve THEN THROUGH [0..2) DO
IF prev=NIL OR prev.first.type#curve THEN ERROR;
prev ← prev.rest;
ENDLOOP;
IF prev#NIL THEN MapPath[prev, moveTo, lineTo, curveTo, closePath];
SELECT path.first.type FROM
move => moveTo[path.first.point];
line => lineTo[path.first.point];
curve => curveTo[path.rest.rest.first.point, path.rest.first.point, path.first.point];
close => closePath[];
ENDCASE => ERROR;
};
MapPath: PROC [path: Path,
moveTo: PROC [p: VEC],
lineTo: PROC [p: VEC],
curveTo: PROC [p1, p2, p3: VEC],
closePath: PROC
] ~ {
Map: PROC [path: Path, length: INT] ~ {
max: NAT ~ 16;
array: ARRAY[0..max) OF Path;
size: NAT ~ MIN[length, max];
n: INT ~ IF length>size THEN length/size ELSE 1;
rem: INT ~ length-n*size;
t: Trajectory ← trajectory;
FOR i: NAT IN[0..size) DO
array[i] ← t;
THROUGH [0..n) DO t ← t.prev ENDLOOP;
ENDLOOP;
IF rem>0 THEN Map[t, rem];
IF n>1 THEN FOR i: NAT DECREASING IN[0..size) DO Map[array[i], n] ENDLOOP
ELSE FOR i: NAT DECREASING IN[0..size) DO
WITH array[i] SELECT FROM
t: REF TrajectoryRep[move] => moveTo[t.lp];
t: REF TrajectoryRep[line] => lineTo[t.lp];
t: REF TrajectoryRep[curve] => curveTo[t.p1, t.p2, t.lp];
t: REF TrajectoryRep[conic] => conicTo[t.p1, t.lp, t.r];
t: REF TrajectoryRep[arc] => arcTo[t.p1, t.lp];
ENDCASE => ERROR; -- unknown variant
ENDLOOP;
};
Map[trajectory, trajectory.length];
};
Primitives
Pnewpath: PROC [self: Root] ~ {
g: GState ~ self.graphics;
g.path ← NIL;
};
Pcurrentpoint: PROC [self: Root] ~ {
g: GState ~ self.graphics;
PushVec[self.ostack, ITransform[CurrentPoint[g.path], g.CTM]];
};
Pmoveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
p: VEC ~ PopVec[self.ostack];
tp: VEC ~ Transform[p, g.CTM];
g.path ← MoveTo[g.path, tp];
};
Prmoveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
d: VEC ~ PopVec[self.ostack];
td: VEC ~ DTransform[d, g.CTM];
c: VEC ~ CurrentPoint[g.path];
g.path ← MoveTo[g.path, Vector2.Add[c, td]];
};
Plineto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
p: VEC ~ PopVec[self.ostack];
tp: VEC ~ Transform[p, g.CTM];
g.path ← LineTo[g.path, tp];
};
Prlineto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
d: VEC ~ PopVec[self.ostack];
td: VEC ~ DTransform[d, g.CTM];
c: VEC ~ CurrentPoint[g.path];
g.path ← LineTo[g.path, Vector2.Add[c, td]];
};
Parc: PROC [self: Root] ~ {
};
Parcn: PROC [self: Root] ~ {
};
Parcto: PROC [self: Root] ~ {
};
Pcurveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
p3: VEC ~ PopVec[self.ostack];
p2: VEC ~ PopVec[self.ostack];
p1: VEC ~ PopVec[self.ostack];
tp3: VEC ~ Transform[p3, g.CTM];
tp2: VEC ~ Transform[p2, g.CTM];
tp1: VEC ~ Transform[p1, g.CTM];
g.path ← CurveTo[g.path, tp1, tp2, tp3];
};
Prcurveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
d3: VEC ~ PopVec[self.ostack];
d2: VEC ~ PopVec[self.ostack];
d1: VEC ~ PopVec[self.ostack];
td3: VEC ~ Transform[d3, g.CTM];
td2: VEC ~ Transform[d2, g.CTM];
td1: VEC ~ Transform[d1, g.CTM];
c: VEC ~ CurrentPoint[g.path];
g.path ← CurveTo[g.path, Vector2.Add[c, td1], Vector2.Add[c, td2], Vector2.Add[c, td3]];
};
Pclosepath: PROC [self: Root] ~ {
g: GState ~ self.graphics;
g.path ← ClosePath[g.path];
};
Pflattenpath: PROC [self: Root] ~ {
};
Preversepath: PROC [self: Root] ~ {
};
Pstrokepath: PROC [self: Root] ~ {
};
Pcharpath: PROC [self: Root] ~ {
};
Pclippath: PROC [self: Root] ~ {
};
Ppathbbox: PROC [self: Root] ~ {
g: GState ~ self.graphics;
min, max, b0, b1, b2, b3: VEC;
IF g.path=NIL THEN ERROR Error[nocurrentpoint];
min ← max ← g.path.first.point;
FOR each: Path ← g.path.rest, each.rest UNTIL each=NIL DO
p: VEC ~ each.first.point;
IF p.x<min.x THEN min.x ← p.x ELSE IF p.x>max.x THEN max.x ← p.x;
IF p.y<min.y THEN min.y ← p.y ELSE IF p.y>max.y THEN max.y ← p.y;
ENDLOOP;
b0 ← ITransform[[min.x, min.y], g.CTM];
b1 ← ITransform[[max.x, min.y], g.CTM];
b2 ← ITransform[[max.x, max.y], g.CTM];
b3 ← ITransform[[min.x, max.y], g.CTM];
PushReal[self.ostack, MIN[b0.x, b1.x, b2.x, b3.x]];
PushReal[self.ostack, MIN[b0.y, b1.y, b2.y, b3.y]];
PushReal[self.ostack, MAX[b0.x, b1.x, b2.x, b3.x]];
PushReal[self.ostack, MAX[b0.y, b1.y, b2.y, b3.y]];
};
Ppathforall: PROC [self: Root] ~ {
g: GState ~ self.graphics;
close: Any ~ PopAny[self.ostack];
curve: Any ~ PopAny[self.ostack];
line: Any ~ PopAny[self.ostack];
move: Any ~ PopAny[self.ostack];
moveTo: PROC [p: VEC] ~ {
PushVec[self.ostack, ITransform[p, g.CTM]];
Execute[self, move];
};
lineTo: PROC [p: VEC] ~ {
PushVec[self.ostack, ITransform[p, g.CTM]];
Execute[self, line];
};
curveTo: PROC [p1, p2, p3: VEC] ~ {
PushVec[self.ostack, ITransform[p1, g.CTM]];
PushVec[self.ostack, ITransform[p2, g.CTM]];
PushVec[self.ostack, ITransform[p3, g.CTM]];
Execute[self, curve];
};
closePath: PROC [] ~ {
Execute[self, close];
};
MapPath[g.path, moveTo, lineTo, curveTo, closePath ! Exit => CONTINUE];
};
Pinitclip: PROC [self: Root] ~ {
};
Pclip: PROC [self: Root] ~ {
};
Peoclip: PROC [self: Root] ~ {
};
PathPrimitives: PROC [self: Root] ~ {
Register[self, "newpath", Pnewpath];
Register[self, "currentpoint", Pcurrentpoint];
Register[self, "moveto", Pmoveto];
Register[self, "rmoveto", Prmoveto];
Register[self, "lineto", Plineto];
Register[self, "rlineto", Prlineto];
Register[self, "arc", Parc];
Register[self, "arcn", Parcn];
Register[self, "arcto", Parcto];
Register[self, "curveto", Pcurveto];
Register[self, "rcurveto", Prcurveto];
Register[self, "closepath", Pclosepath];
Register[self, "flattenpath", Pflattenpath];
Register[self, "reversepath", Preversepath];
Register[self, "strokepath", Pstrokepath];
Register[self, "charpath", Pcharpath];
Register[self, "clippath", Pclippath];
Register[self, "pathbbox", Ppathbbox];
Register[self, "pathforall", Ppathforall];
Register[self, "initclip", Pinitclip];
Register[self, "clip", Pclip];
Register[self, "eoclip", Peoclip];
};
RegisterPrimitives[PathPrimitives];
END.