CDCurvesImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, March 30, 1985 12:19:40 pm PST
Last edited by: Christian Jacobi, December 18, 1986 2:46:33 pm PST
DIRECTORY
CDInstances,
CDCurves,
CDTexts,
CD,
CDBasics,
CDLayers,
CDIO,
CDOps,
Imager,
ImagerPath,
Rope,
TokenIO,
Vector2;
CDCurvesImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDLayers, CDIO, CDOps, Imager, ImagerPath, Rope, TokenIO
EXPORTS CDCurves =
BEGIN
CurveSpecific: TYPE = CDCurves.CurveSpecific;
CurveRec: TYPE = CDCurves.CurveRec;
LoP: TYPE = LIST OF CD.Position;
splineClass:
PUBLIC CD.ObjectClass ←
CD.RegisterObjectClass[$Spline0, [
drawMe: DrawSpline,
quickDrawMe: DrawSpline,
hitInside: HitInsideCurve,
describe: Describe,
internalRead: ReadCurve,
internalWrite: WriteCurve,
newLayer: ChangeLayer,
description: "spline"
]];
lineClass:
PUBLIC CD.ObjectClass ←
CD.RegisterObjectClass[$Line0, [
drawMe: DrawSpline,
quickDrawMe: DrawSpline,
hitInside: HitInsideCurve,
describe: Describe,
internalRead: ReadCurve,
internalWrite: WriteCurve,
newLayer: ChangeLayer,
description: "line"
]];
polygonClass:
PUBLIC
CD.ObjectClass ←
CD.RegisterObjectClass[$Polygon0, [
drawMe: DrawFilledCurve,
quickDrawMe: DrawFilledCurve,
hitInside: HitInsideCurve,
describe: Describe,
internalRead: ReadCurve,
internalWrite: WriteCurve,
newLayer: ChangeLayer,
description: "polygon"
]];
filledCurveClass:
PUBLIC CD.ObjectClass ←
CD.RegisterObjectClass[$FilledCurve0, [
drawMe: DrawFilledCurve,
quickDrawMe: DrawFilledCurve,
hitInside: HitInsideCurve,
describe: Describe,
internalRead: ReadCurve,
internalWrite: WriteCurve,
newLayer: ChangeLayer,
description: "filled curve"
]];
oldPolygonClass:
CD.ObjectClass ←
CD.RegisterObjectClass[$Polygon, [
internalRead: ReadOldPolygon,
description: "old kind of polygon"
]];
CopyList:
PROC [points: LoP, w: CD.Number𡤀]
RETURNS [copy: LoP←
NIL, r:
CD.Rect, leng:
INT𡤀] = {
min: CD.Position ← CDBasics.highposition;
max: CD.Position ← CDBasics.minposition;
FOR class: LoP ← points, class.rest
WHILE class#
NIL
DO
leng ← leng+1;
min ← CDBasics.MinPoint[min, class.first];
max ← CDBasics.MaxPoint[max, class.first];
ENDLOOP;
min ← [min.x-w, min.y-w];
max ← [max.x+w, max.y+w];
FOR class: LoP ← points, class.rest
WHILE class#
NIL
DO
copy ← CONS[CDBasics.SubPoints[class.first, min], copy];
ENDLOOP;
r ← CDBasics.ToRect[min, max];
IF (r.x2-r.x1)>LAST[NAT] OR (r.y2-r.y1)>LAST[NAT] THEN CD.Error[callingError, "size out of range"];
};
CreatePolygon:
PUBLIC
PROC [points:
LIST
OF
CD.Position, layer:
CD.Layer]
RETURNS [ob:
CD.Object←
NIL, offset:
CD.Position←[0, 0]] = {
r: CD.Rect; leng: INT;
cp: CurveSpecific = NEW[CurveRec];
[cp.points, r, leng] ← CopyList[points, 0];
IF leng<3 THEN RETURN;
cp.path ← ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]];
FOR class: LoP ← cp.points.rest, class.rest
WHILE class#
NIL
DO
cp.path ← ImagerPath.LineTo[cp.path, [class.first.x, class.first.y]];
ENDLOOP;
ob ←
NEW[
CD.ObjectRep←[
bbox: [0, 0, r.x2-r.x1, r.y2-r.y1],
layer: CDLayers.AbstractToPaint[layer],
class: polygonClass,
specific: cp
]];
offset ← CDBasics.BaseOfRect[r];
};
CreateFilledCurve:
PUBLIC
PROC [points:
LIST
OF
CD.Position, layer:
CD.Layer]
RETURNS [ob:
CD.Object←
NIL, offset:
CD.Position←[0, 0]] = {
r: CD.Rect; leng: INT; pl: LoP;
cp: CurveSpecific = NEW[CurveRec];
[cp.points, r, leng] ← CopyList[points, 0];
IF leng<4 THEN RETURN;
cp.path ← ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]];
pl ← cp.points.rest;
WHILE pl #
NIL
DO
p1, p2, p3: Vector2.VEC;
p1 ← [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl ← pl.rest;
p2 ← [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl ← pl.rest;
p3 ← [pl.first.x, pl.first.y]; pl ← pl.rest;
cp.path ← ImagerPath.CurveTo[cp.path, p1, p2, p3];
ENDLOOP;
ob ←
NEW[
CD.ObjectRep←[
bbox: [0, 0, r.x2-r.x1, r.y2-r.y1],
layer: CDLayers.AbstractToPaint[layer],
class: filledCurveClass,
specific: cp
]];
offset ← CDBasics.BaseOfRect[r];
};
CreateSpline:
PUBLIC
PROC [points:
LIST
OF
CD.Position, w:
CD.Number, layer:
CD.Layer]
RETURNS [ob:
CD.Object←
NIL, offset:
CD.Position←[0, 0]] = {
r: CD.Rect; leng: INT; pl: LoP;
cp: CurveSpecific = NEW[CurveRec];
w2: INT ← MAX[1, (w+1)/2];
[cp.points, r, leng] ← CopyList[points, w2];
IF leng<1 THEN RETURN;
cp.w ← w2*2;
cp.path ← ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]];
pl ← cp.points.rest;
WHILE pl #
NIL
DO
p1, p2, p3: Vector2.VEC;
p1 ← [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl ← pl.rest;
p2 ← [pl.first.x, pl.first.y]; IF pl.rest#NIL THEN pl ← pl.rest;
p3 ← [pl.first.x, pl.first.y]; pl ← pl.rest;
cp.path ← ImagerPath.CurveTo[cp.path, p1, p2, p3];
ENDLOOP;
ob ←
NEW[
CD.ObjectRep←[
bbox: [0, 0, MAX[cp.w, r.x2-r.x1], MAX[cp.w, r.y2-r.y1]],
layer: CDLayers.AbstractToPaint[layer],
class: splineClass,
specific: cp
]];
offset ← CDBasics.BaseOfRect[r];
};
CreateLine:
PUBLIC
PROC [points:
LIST
OF
CD.Position, w:
CD.Number, layer:
CD.Layer]
RETURNS [ob:
CD.Object←
NIL, offset:
CD.Position←[0, 0]] = {
r: CD.Rect; leng: INT; pl: LoP;
cp: CurveSpecific = NEW[CurveRec];
w2: INT ← MAX[1, (w+1)/2];
[cp.points, r, leng] ← CopyList[points, w2];
IF leng<1 THEN RETURN;
cp.w ← w2*2;
cp.path ← ImagerPath.MoveTo[[cp.points.first.x, cp.points.first.y]];
pl ← cp.points.rest;
WHILE pl #
NIL
DO
p1: Vector2.VEC ← [pl.first.x, pl.first.y];
pl ← pl.rest;
cp.path ← ImagerPath.LineTo[cp.path, p1];
ENDLOOP;
ob ←
NEW[
CD.ObjectRep←[
bbox: [0, 0, MAX[cp.w, r.x2-r.x1], MAX[cp.w, r.y2-r.y1]],
layer: CDLayers.AbstractToPaint[layer],
class: lineClass,
specific: cp
]];
offset ← CDBasics.BaseOfRect[r];
};
HitInsideCurve:
PROC [ob:
CD.Object, hitRect:
CD.Rect]
RETURNS [yes:
BOOL] = {
RETURN [ CDBasics.Intersect[ob.class.interestRect[ob], hitRect] ];
};
DrawFilledCurve:
PROC [inst:
CD.Instance, trans: CD.Transformation, pr:
CD.DrawRef] = {
FilledCurveInContext:
PROC [context: Imager.Context, ob:
CD.Object, layer:
CD.Layer] = {
Imager.ClipRectangleI[context, 0, 0, ob.bbox.x2, ob.bbox.y2];
Imager.MaskFillTrajectory[context, NARROW[ob.specific, CurveSpecific].path, TRUE];
};
pr.drawContext[pr, FilledCurveInContext, inst.ob, trans, inst.ob.layer]
};
DrawSpline:
PROC [inst:
CD.Instance, trans:
CD.Transformation, pr:
CD.DrawRef] = {
SplineInContext:
PROC [context: Imager.Context, ob:
CD.Object, layer:
CD.Layer] = {
Imager.ClipRectangleI[context, 0, 0, ob.bbox.x2, ob.bbox.y2];
Imager.SetStrokeWidth[context: context, strokeWidth: NARROW[ob.specific, CurveSpecific].w];
Imager.SetStrokeEnd[context: context, strokeEnd: square];
Imager.MaskStrokeTrajectory[context, NARROW[ob.specific, CurveSpecific].path, FALSE];
};
pr.drawContext[pr, SplineInContext, inst.ob, trans, inst.ob.layer]
};
Describe:
PROC[me:
CD.Object]
RETURNS [Rope.
ROPE] = {
RETURN [Rope.Cat[me.class.description, " ", CDOps.LayerRope[me.layer]]]
};
WriteCurve:
CD.InternalWriteProc = {
Length:
PROC [points:
LIST
OF
CD.Position]
RETURNS [n:
NAT ← 0] = {
FOR l: LIST OF CD.Position ← points, l.rest WHILE l#NIL DO n ← n+1 ENDLOOP
};
cp: CurveSpecific = NARROW[ob.specific];
l: NAT ← Length[cp.points];
CDIO.WriteLayer[h, ob.layer];
SELECT ob.class
FROM
lineClass => {TokenIO.WriteInt[h, 0]; TokenIO.WriteInt[h, cp.w]};
polygonClass => TokenIO.WriteInt[h, 1];
splineClass => {TokenIO.WriteInt[h, 2]; TokenIO.WriteInt[h, cp.w]};
filledCurveClass => TokenIO.WriteInt[h, 3];
ENDCASE => ERROR;
TokenIO.WriteInt[h, l];
FOR pl: LoP ← cp.points, pl.rest
WHILE pl#
NIL
DO
CDIO.WritePos[h, pl.first];
ENDLOOP;
};
ReadCurve:
CD.InternalReadProc = {
ob: CD.Object ← NIL; kind, w, leng: INT; layer: CD.Layer;
points: LoP ← NIL;
layer ← CDIO.ReadLayer[h];
SELECT kind ← TokenIO.ReadInt[h]
FROM
0, 2 => w ← TokenIO.ReadInt[h];
ENDCASE => NULL;
leng ← TokenIO.ReadInt[h];
FOR i:
INT
IN [1..leng]
DO
points ← CONS[CDIO.ReadPos[h], points];
ENDLOOP;
SELECT kind
FROM
0 => ob ← CreateLine[points, w, layer].ob;
1 => ob ← CreatePolygon[points, layer].ob;
2 => ob ← CreateSpline[points, w, layer].ob;
3 => ob ← CreateFilledCurve[points, layer].ob;
ENDCASE;
RETURN [ob]
};
ReadOldPolygon:
CD.InternalReadProc = {
ob: CD.Object;
layer: CD.Layer = CDIO.ReadLayer[h];
leng: INT = TokenIO.ReadInt[h];
points: LIST OF CD.Position ← NIL;
FOR i:
INT
IN [1..leng]
DO
points ← CONS[CDIO.ReadPos[h], points];
ENDLOOP;
ob ← CreatePolygon[points, layer].ob;
RETURN [ob]
};
ChangeLayer:
CD.ChangeLayerProc = {
--at this point we have to now the class implementation
--to know that the specific field is treated readonly...
newLayer: CD.Layer ← CDLayers.AbstractToPaint[layer];
IF newLayer#inst.ob.layer
AND newLayer#
CD.undefLayer
THEN {
new: CD.Object ← NEW[CD.ObjectRep←inst.ob^];
new.layer ← newLayer;
new.properties ← NIL;
inst.ob ← new;
RETURN [TRUE]
};
RETURN [FALSE]
};
END.