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: REALLAST[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: REALLAST[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: REALLAST[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.