CDCurvesCommands.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, August 24, 1986 8:11:28 pm PDT
DIRECTORY
CD,
CDInstances,
CDBasics,
CDCommandOps,
CDCallSpecific,
CDCurves,
CDLayers,
CDOps,
CDOrient,
CDPrivate,
CDSequencer,
CDSymbolicObjects,
IO,
PriorityQueue,
Real,
Rope,
TerminalIO;
CDCurvesCommands:
CEDAR
PROGRAM
IMPORTS CDBasics, CDCallSpecific, CDCommandOps, CDCurves, CDLayers, CDOps, CDOrient, CDSequencer, CDSymbolicObjects, IO, PriorityQueue, Real, Rope, TerminalIO
SHARES CDCurves =
BEGIN
LP: TYPE = LIST OF CD.Position;
Write: PROC[r: Rope.ROPE] = {TerminalIO.WriteRope[r]};
OldDrawPolygonComm: PROC [comm: CDSequencer.Command] =
BEGIN
ob: CD.Object;
offset: CD.Position;
p1: CD.Position ← comm.sPos; --from
p2: CD.Position ← comm.pos; --to
points: LIST OF CD.Position;
Write["Draw a polygon\n"];
IF ABS[p1.x-p2.x]<4 THEN p2.x ← p1.x+10;
IF ABS[p1.y-p2.y]<4 THEN p2.y ← p1.y+10;
points ← LIST[p1, p2, [p2.x, p1.y]];
[ob, offset] ← CDCurves.CreatePolygon[points, comm.l];
IF ob=NIL THEN Write[" not done\n"] ELSE CDOps.IncludeObjectI[comm.design, ob, offset]
END;
DistanceSq:
PROC[p1, p2:
CD.Position]
RETURNS [
REAL] =
--returns th square of the distance
BEGIN
dx: REAL = Real.Float[p1.x]-Real.Float[p2.x];
dy: REAL = Real.Float[p1.y]-Real.Float[p2.y];
RETURN [dx*dx+dy*dy]
END;
Distance:
PROC [p1, p2:
CD.Position]
RETURNS [
REAL] =
BEGIN
RETURN [Real.SqRt[DistanceSq[p1, p2]]]
END;
DistancePairP:
PROC[p1, p2, p:
CD.Position]
RETURNS [
REAL] =
--returns some bad hack representing distance
BEGIN
RETURN [ABS[Distance[p1, p]+Distance[p2, p]-Distance[p2, p1]]]
END;
StretchPoints:
PROC [points: LP, from, to:
CD.Position]
RETURNS [new: LP←
NIL] =
BEGIN
pos: INT ← 0;
cnt: INT ← 0;
dmin: REAL ← LAST[INT];
FOR p: LP ← points, p.rest
WHILE p#
NIL
DO
d: REAL = DistanceSq[p.first, from];
cnt ← cnt+1;
IF d<dmin THEN {pos𡤌nt; dmin𡤍};
ENDLOOP;
FOR i:
INT
IN [1..pos)
DO
new ← CONS[points.first, new];
points ← points.rest;
ENDLOOP;
new ← CONS[to, new];
points ← points.rest;
FOR p: LP ← points, p.rest
WHILE p#
NIL
DO
new ← CONS[p.first, new];
ENDLOOP;
END;
IncludePoint:
PROC [points: LP, from, to:
CD.Position]
RETURNS [new: LP←
NIL] =
BEGIN
after: INT ← 0;
cnt: INT ← 0;
dmin: REAL ← LAST[INT];
last: CD.Position;
d: REAL;
FOR p: LP ← points, p.rest
WHILE p#
NIL
AND p.rest#
NIL
DO
d ← DistancePairP[p.first, p.rest.first, from];
last ← p.first;
cnt ← cnt+1;
IF d<dmin THEN {after𡤌nt; dmin𡤍};
ENDLOOP;
d ← DistancePairP[points.first, last, from];
IF d<dmin THEN after𡤀
FOR i:
INT
IN [1..after]
DO
new ← CONS[points.first, new];
points ← points.rest;
ENDLOOP;
new ← CONS[to, new];
FOR p: LP ← points, p.rest
WHILE p#
NIL
DO
new ← CONS[p.first, new];
ENDLOOP;
END;
RemovePoint:
PROC [points: LP, from, to:
CD.Position]
RETURNS [new: LP←
NIL] =
--to is ignored
BEGIN
pos: INT ← 0;
cnt: INT ← 0;
dmin: REAL ← LAST[INT];
FOR p: LP ← points, p.rest
WHILE p#
NIL
DO
d: REAL = DistanceSq[p.first, from];
cnt ← cnt+1;
IF d<dmin THEN {pos𡤌nt; dmin𡤍};
ENDLOOP;
FOR i:
INT
IN [1..pos)
DO
new ← CONS[points.first, new];
points ← points.rest;
ENDLOOP;
IF cnt>3 THEN points ← points.rest
ELSE Write["degenerated polygon not created\n"];
FOR p: LP ← points, p.rest
WHILE p#
NIL
DO
new ← CONS[p.first, new];
ENDLOOP;
END;
OffsetInPlace:
PROC [pl: LP, off:
CD.Number] = {
FOR l: LP ← pl, l.rest
WHILE l#
NIL
DO
l.first ← [l.first.x+off, l.first.y+off]
ENDLOOP;
};
OrientedPoints:
PROC [inst:
CD.Instance]
RETURNS [copy: LP←
NIL] =
--inst must be instance of a curve object
BEGIN
pl: LP;
WITH inst.ob.specificRef
SELECT
FROM
cp: CDCurves.CurvePtr => pl ← cp.points;
ENDCASE => ERROR;
FOR p: LP ← pl, p.rest
WHILE p#
NIL
DO
orientedP:
CD.Position = CDOrient.MapPoint[
pointInCell: p.first,
cellSize: inst.ob.size,
cellInstOrient: inst.orientation,
cellInstPos: inst.location].pointInWorld;
copy ← CONS[orientedP, copy];
ENDLOOP;
END;
FindMarks:
PROC [design:
CD.Design, predicate: CDSymbolicObjects.InstEnumerator←
NIL]
RETURNS [pq: PriorityQueue.Ref] = {
pq ← PriorityQueue.Create[SortPred];
FOR w:
CD.InstanceList ← CDOps.InstList[design], w.rest
WHILE w#
NIL
DO
IF CDSymbolicObjects.IsMark[w.first.ob]
AND (predicate=
NIL
OR predicate[w.first])
THEN
PriorityQueue.Insert[pq, w.first];
ENDLOOP;
};
SelectPMarksComm:
PROC [comm: CDSequencer.Command] = {
cnt: INT ← 0;
FOR w:
CD.InstanceList ← CDOps.InstList[comm.design], w.rest
WHILE w#
NIL
DO
IF CDSymbolicObjects.IsMark[w.first.ob]
AND FromPS[w.first]
THEN
IF ~w.first.selected
THEN {
w.first.selected ← TRUE; cnt ← cnt+1;
CDOps.RedrawInstance[comm.design, w.first, FALSE]
};
ENDLOOP;
TerminalIO.WriteF["add-select curve control marks; %g more mark(s) selected\n ", [integer[cnt]]];
MarksStatistic[comm.design];
};
RemOwnerComm:
PROC [comm: CDSequencer.Command] = {
Write[" remove owner of marks\n"];
FOR w:
CD.InstanceList ← CDOps.InstList[comm.design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
AND CDSymbolicObjects.IsMark[w.first.ob]
THEN
CDSymbolicObjects.SetOwner[w.first, NIL];
ENDLOOP;
};
SetOwnerComm:
PROC [comm: CDSequencer.Command] = {
Write[" convert marks to curve control marks\n"];
FOR w:
CD.InstanceList ← CDOps.InstList[comm.design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
AND CDSymbolicObjects.IsMark[w.first.ob]
THEN
IF ~FromPS[w.first] THEN SetOrder[w.first];
ENDLOOP;
};
MarksStatisticComm:
PROC [comm: CDSequencer.Command] = {
Write["count marks: "];
MarksStatistic[comm.design];
};
MarksStatistic:
PROC [design:
CD.Design] = {
oMcnt, pMcnt, oXcnt, notSelPMcnt: INT ← 0;
FOR w:
CD.InstanceList ← CDOps.InstList[design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
THEN {
IF CDSymbolicObjects.IsMark[w.first.ob]
THEN
IF FromPS[w.first] THEN pMcnt ← pMcnt+1
ELSE oMcnt ← oMcnt +1
ELSE oXcnt ← oXcnt + 1
}
ELSE
IF CDSymbolicObjects.IsMark[w.first.ob]
AND FromPS[w.first]
THEN
notSelPMcnt ← notSelPMcnt+1;
ENDLOOP;
TerminalIO.WriteF[" %g curve control marks", [integer[pMcnt]]];
IF oMcnt#0 THEN TerminalIO.WriteF[" %g other-marks", [integer[oMcnt]]];
IF oXcnt#0 THEN TerminalIO.WriteF[" %g other-objects", [integer[oXcnt]]];
Write[" selected"];
IF notSelPMcnt#0 THEN TerminalIO.WriteF[" %g curve control marks NOT selected", [integer[notSelPMcnt]]];
TerminalIO.WriteLn[];
};
ConvertPSToMarks:
PROC [comm: CDSequencer.Command] =
BEGIN
i: CD.Instance ← CDCommandOps.TheInstance[comm, "split up curve object"];
IF i#
NIL
THEN {
IF CDCurves.IsPolygon[i.ob]
OR CDCurves.IsSpline[i.ob]
OR CDCurves.IsFilledCurve[i.ob]
OR CDCurves.IsLine[i.ob]
THEN {
cp: CDCurves.CurvePtr ← NARROW[i.ob.specificRef];
cnt: INT ← 0; oldPoints: LP ← OrientedPoints[i];
CDOps.RemoveInstance[comm.design, i];
FOR pl: LP ← oldPoints, pl.rest
WHILE pl#
NIL
DO
r: CD.Rect ← CDBasics.RectAt[[pl.first.x-cp.w/2, pl.first.y-cp.w/2], [0, 0]];
si: CD.Instance ← CDSymbolicObjects.CreateSymInst[denotes: r, layer: i.ob.layer];
SetOrder[si]; si.selected ← TRUE;
CDOps.IncludeInstance[comm.design, si];
ENDLOOP;
}
ELSE Write["selected ob is neither polygon nor spline; not done\n"];
};
END;
Selected: CDSymbolicObjects.InstEnumerator ={
RETURN [inst.selected]
};
FromPS: CDSymbolicObjects.InstEnumerator ={
RETURN [CDSymbolicObjects.GetOwner[inst]=$CurveControl]
};
SelectedOrFromPS: CDSymbolicObjects.InstEnumerator ={
RETURN [inst.selected OR CDSymbolicObjects.GetOwner[inst]=$CurveControl]
};
SortPred: PriorityQueue.SortPred = {
RETURN [ Rope.Compare[ CDSymbolicObjects.GetName[NARROW[x]], CDSymbolicObjects.GetName[NARROW[y] ], FALSE] < equal];
};
MarksToPSComm:
PROC [comm: CDSequencer.Command] =
BEGIN
MarksToPS:
PROC [design:
CD.Design, pq: PriorityQueue.Ref, layer:
CD.Layer, key:
ATOM, w:
CD.Number ← 0] = {
ob: CD.Object; offset: CD.Position; pl: LIST OF CD.Position ← NIL;
SELECT key
FROM
$s => {w ← (w+1)/2*2};
$p => {w ← 0};
$l => {w ← (w+1)/2*2};
$f => {w ← 0};
ENDCASE => ERROR;
FOR c:
INT
IN [0..PriorityQueue.Size[pq])
DO
i: CD.Instance ← NARROW[PriorityQueue.Remove[pq]];
pos: CD.Position ← CDBasics.BaseOfRect[CDSymbolicObjects.Denotes[i]];
pl ← CONS[[pos.x+w/2, pos.y+w/2], pl];
CDOps.RemoveInstance[design, i];
ENDLOOP;
SELECT key
FROM
$s => [ob: ob, offset: offset] ← CDCurves.CreateSpline[pl, w, layer];
$p => [ob: ob, offset: offset] ← CDCurves.CreatePolygon[pl, layer];
$l => [ob: ob, offset: offset] ← CDCurves.CreateLine[pl, w, layer];
$f => [ob: ob, offset: offset] ← CDCurves.CreateFilledCurve[pl, layer];
ENDCASE => ERROR;
IF ob=NIL THEN Write[" not done\n"]
ELSE CDOps.IncludeObjectI[design, ob, offset];
};
key: ATOM; min: INT;
predicate: CDSymbolicObjects.InstEnumerator;
pq: PriorityQueue.Ref;
Write[" convert marks to "];
IF comm.n<=1
THEN
SELECT comm.key
FROM
$MakeSplineS => {Write["[0 size spline] "]; comm.key ← $MakeFilledCurveS};
$MakeLineS => {Write["[0 size line] "]; comm.key ← $MakePolygonS};
$MakeSplineB => {Write["[0 size spline] "]; comm.key ← $MakeFilledCurveB};
$MakeLineB => {Write["[0 size line] "]; comm.key ← $MakePolygonB};
ENDCASE => NULL;
SELECT comm.key
FROM
$MakePolygonS => {
Write["polygon (selected)"]; predicate ← Selected; key ← $p; min ← 3};
$MakeSplineS => {Write["spline (selected)"]; predicate ← Selected; key ← $s; min ← 4; min ← 4};
$MakeLineS => {
Write["line (selected)"]; predicate ← Selected; key ← $l; min ← 2};
$MakeFilledCurveS => {
Write["filled curve (selected)"]; predicate ← Selected; key ← $f; min ← 4};
$MakePolygonB => {
Write["polygon (selected+origin)"]; predicate ← SelectedOrFromPS; key ← $p; min ← 3};
$MakeSplineB => {
Write["spline (selected+origin)"]; predicate ← SelectedOrFromPS; key ← $s; min ← 4};
$MakeLineB => {
Write["line (selected+origin)"]; predicate ← SelectedOrFromPS; key ← $l; min ← 2};
$MakeFilledCurveB => {
Write["filled curve (selected+origin)"]; predicate ← SelectedOrFromPS; key ← $f; min ← 4};
ENDCASE => {Write["failed\n"]; RETURN};
pq ← FindMarks[comm.design, predicate];
IF pq.Size[]<min THEN TerminalIO.WriteF[" must use %g or more marks\n", [integer[min]]]
ELSE MarksToPS[comm.design, pq, comm.l, key, comm.n];
END;
StretchPolygonComm: PROC [comm: CDSequencer.Command] =
BEGIN
inst: CD.Instance;
p: PROC [points: LP, from, to: CD.Position] RETURNS [LP];
r: Rope.ROPE;
SELECT comm.key FROM
$MovePolygonPoint => {p ← StretchPoints; r ← "stretch polygon"};
$AddPolygonPoint => {p ← IncludePoint; r ← "add point to polygon"};
$RemovePolygonPoint => {p ← RemovePoint; r ← "remove point from polygon"};
ENDCASE => {Write["unknown command\n"]; RETURN};
inst ← CDCommandOps.TheInstance[comm, r];
IF inst#NIL THEN {
WITH inst.ob.specificRef SELECT FROM
t: CDCurves.CurvePtr => {
offset: CD.Position;
ob: CD.Object;
oldPoints: LP ← OrientedPoints[inst];
newPoints: LP ← p[oldPoints, comm.sPos, comm.pos];
[ob: ob, offset: offset] ← CDCurves.CreatePolygon[newPoints, inst.ob.layer];
IF ob=NIL THEN {Write[" not done\n"]; RETURN};
CDOps.DelayedRedraw[comm.design, CDInstances.InstRectO[inst]];
inst.ob ← ob;
inst.orientation ← CD.original;
inst.location ← offset;
CDOps.DelayedRedraw[comm.design, CDInstances.InstRectO[inst], FALSE];
}
ENDCASE => Write["selected ob is not polygon; not done\n"];
};
END;
cnt: INT ← 0;
SetOrder:
PROC [inst:
CD.Instance] = {
CDSymbolicObjects.SetOwner[inst, $CurveControl];
CDSymbolicObjects.SetName[inst, IO.PutFR["CP-%05g", [integer[cnt ← cnt+10]]]];
};
DrawControlMarkComm:
PROC [comm: CDSequencer.Command] =
BEGIN
inst: CD.Instance;
r: CD.Rect = CDBasics.RectAt[comm.pos, [0, 0]];
Write["draw unnamed control-mark\n"];
inst ← CDSymbolicObjects.CreateSymInst[denotes: r];
SetOrder[inst];
CDOps.IncludeInstance[comm.design, inst];
END;
RenameMarkComm:
PROC [comm: CDSequencer.Command] =
BEGIN
Write["rename and make mark a control mark\n"];
FOR w:
CD.InstanceList ← CDOps.InstList[comm.design], w.rest
WHILE w#
NIL
DO
IF w.first.selected
THEN {
IF CDSymbolicObjects.IsMark[w.first.ob] THEN SetOrder[w.first] ELSE Write[" object is not mark\n"];
RETURN;
}
ENDLOOP;
Write[" no mark found\n"];
END;
ChangeLayer: CDCallSpecific.CallProc =
BEGIN
--at this point we have to now the class implementation
--to know that the specifiRref field is treated readonly...
new: CD.Object ← NEW[CD.ObjectRep←inst.ob^];
layer:
CD.Layer ←
WITH x
SELECT
FROM
lr: CDPrivate.LayerRef => lr.number,
ENDCASE => CDLayers.CurrentLayer[design];
new.layer ← CDLayers.AbstractToPaint[layer];
new.properties ← NIL;
inst.ob ← new;
repaintMe ← TRUE;
END;
--old command set
CDSequencer.ImplementCommand[$DrawPolygon, OldDrawPolygonComm];
CDSequencer.ImplementCommand[$MovePolygonPoint, StretchPolygonComm];
CDSequencer.ImplementCommand[$AddPolygonPoint, StretchPolygonComm];
CDSequencer.ImplementCommand[$RemovePolygonPoint, StretchPolygonComm];
--new command set
CDSequencer.ImplementCommand[$DrawPolygonMark, DrawControlMarkComm];
CDSequencer.ImplementCommand[$PolygonRenumber, RenameMarkComm];
CDSequencer.ImplementCommand[$SplitPolygon, ConvertPSToMarks,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakePolygonS, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakePolygonB, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakeLineS, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakeLineB, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakeFilledCurveS, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakeFilledCurveB, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakeSplineS, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MakeSplineB, MarksToPSComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$RSelPMarks, SelectPMarksComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$SetOwnMarkP, SetOwnerComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$RemOwnMarkP, RemOwnerComm,, doQueueAndMark];
CDSequencer.ImplementCommand[$MStatC, MarksStatisticComm,, doQueue];
CDCallSpecific.Register[$ChangeLayer, CDCurves.splineClass, ChangeLayer];
CDCallSpecific.Register[$ChangeLayer, CDCurves.lineClass, ChangeLayer];
CDCallSpecific.Register[$ChangeLayer, CDCurves.polygonClass, ChangeLayer];
CDCallSpecific.Register[$ChangeLayer, CDCurves.filledCurveClass, ChangeLayer];
END.