CDCurvesImpl.mesa
Copyright © 1985, 1987 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, March 30, 1985 12:19:40 pm PST
Last edited by: Christian Jacobi, February 23, 1987 6:55:36 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[calling, "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,
immutable: TRUE,
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,
immutable: TRUE,
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: INTMAX[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,
immutable: TRUE,
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: INTMAX[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,
immutable: TRUE,
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: CD.DrawProc = {
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, ob, trans, ob.layer]
};
DrawSpline: CD.DrawProc = {
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, ob, trans, ob.layer]
};
Describe: CD.DescribeProc = {
RETURN [Rope.Cat[ob.class.description, " ", CDOps.LayerRope[ob.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.