PSPathImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Doug Wyatt, April 2, 1987 4:56:20 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]]]];
};
ArcTo: PROC [path: Path, p0: VEC, r: REAL, ang1, ang2: REAL, neg: BOOL] RETURNS [Path] ~ {
p1: VEC ~ Vector2.Add[p0, Vector2.Mul[[RealFns.CosDeg[ang1], RealFns.SinDeg[ang1]], r]];
p2: VEC ~ Vector2.Add[p0, Vector2.Mul[[RealFns.CosDeg[ang2], RealFns.SinDeg[ang2]], r]];
g.path ← (IF g.path=NIL THEN MoveTo ELSE LineTo)[g.path, Transform[g.CTM, p1]];
};
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;
};
Primitives
Pnewpath: PROC [self: Root] ~ {
g: GState ~ self.graphics;
g.path ← NIL;
};
Pcurrentpoint: PROC [self: Root] ~ {
g: GState ~ self.graphics;
PushVec[self, ITransform[g.CTM, CurrentPoint[g.path]]];
};
Pmoveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
p: VEC ~ PopVec[self];
tp: VEC ~ Transform[g.CTM, p];
g.path ← MoveTo[g.path, tp];
};
Prmoveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
d: VEC ~ PopVec[self];
td: VEC ~ DTransform[g.CTM, d];
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];
tp: VEC ~ Transform[g.CTM, p];
g.path ← LineTo[g.path, tp];
};
Prlineto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
d: VEC ~ PopVec[self];
td: VEC ~ DTransform[g.CTM, d];
c: VEC ~ CurrentPoint[g.path];
g.path ← LineTo[g.path, Vector2.Add[c, td]];
};
Parc: PROC [self: Root] ~ {
g: GState ~ self.graphics;
ang2: REAL ~ PopReal[self];
ang1: REAL ~ PopReal[self];
r: REAL ~ PopReal[self];
p0: VEC ~ PopVec[self];
p1: VEC ~ Vector2.Add[p0, Vector2.Mul[[RealFns.CosDeg[ang1], RealFns.SinDeg[ang1]], r]];
p2: VEC ~ Vector2.Add[p0, Vector2.Mul[[RealFns.CosDeg[ang2], RealFns.SinDeg[ang2]], r]];
g.path ← (IF g.path=NIL THEN MoveTo ELSE LineTo)[g.path, Transform[g.CTM, p1]];
};
Parcn: PROC [self: Root] ~ {
};
Parcto: PROC [self: Root] ~ {
};
Pcurveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
p3: VEC ~ PopVec[self];
p2: VEC ~ PopVec[self];
p1: VEC ~ PopVec[self];
tp3: VEC ~ Transform[g.CTM, p3];
tp2: VEC ~ Transform[g.CTM, p2];
tp1: VEC ~ Transform[g.CTM, p1];
g.path ← CurveTo[g.path, tp1, tp2, tp3];
};
Prcurveto: PROC [self: Root] ~ {
g: GState ~ self.graphics;
d3: VEC ~ PopVec[self];
d2: VEC ~ PopVec[self];
d1: VEC ~ PopVec[self];
td3: VEC ~ Transform[g.CTM, d3];
td2: VEC ~ Transform[g.CTM, d2];
td1: VEC ~ Transform[g.CTM, d1];
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[g.CTM, [min.x, min.y]];
b1 ← ITransform[g.CTM, [max.x, min.y]];
b2 ← ITransform[g.CTM, [max.x, max.y]];
b3 ← ITransform[g.CTM, [min.x, max.y]];
PushReal[self, MIN[b0.x, b1.x, b2.x, b3.x]];
PushReal[self, MIN[b0.y, b1.y, b2.y, b3.y]];
PushReal[self, MAX[b0.x, b1.x, b2.x, b3.x]];
PushReal[self, MAX[b0.y, b1.y, b2.y, b3.y]];
};
Ppathforall: PROC [self: Root] ~ {
g: GState ~ self.graphics;
close: Any ~ PopAny[self];
curve: Any ~ PopAny[self];
line: Any ~ PopAny[self];
move: Any ~ PopAny[self];
moveTo: PROC [p: VEC] ~ {
PushVec[self, ITransform[g.CTM, p]];
Execute[self, move];
};
lineTo: PROC [p: VEC] ~ {
PushVec[self, ITransform[g.CTM, p]];
Execute[self, line];
};
curveTo: PROC [p1, p2, p3: VEC] ~ {
PushVec[self, ITransform[g.CTM, p1]];
PushVec[self, ITransform[g.CTM, p2]];
PushVec[self, ITransform[g.CTM, p3]];
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.