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];