CDPolygonsCommands.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
by Christian Jacobi, March 30, 1985 12:19:40 pm PST
last edited by Christian Jacobi, September 19, 1985 4:34:23 am PDT
DIRECTORY
CD,
CDInstances,
CDCommandOps,
CDMenus,
CDOps,
CDOrient,
CDPolygons,
CDSequencer,
Real,
Rope,
TerminalIO;
CDPolygonsCommands: CEDAR PROGRAM
IMPORTS CDInstances, CDCommandOps, CDMenus, CDOps, CDOrient, CDPolygons, CDSequencer, Real, TerminalIO =
BEGIN
PList: TYPE = LIST OF CD.Position;
DrawPolygonComm: 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;
TerminalIO.WriteRope["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] ← CDPolygons.CreatePolygon[points, comm.l];
IF ob=NIL THEN TerminalIO.WriteRope[" not done\n"]
ELSE CDOps.AddAnObject[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: PList, from, to: CD.Position] RETURNS [new: PList←NIL] =
BEGIN
pos: INT ← 0;
cnt: INT ← 0;
dmin: REALLAST[INT];
FOR p: PList ← 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: PList ← points, p.rest WHILE p#NIL DO
new ← CONS[p.first, new];
ENDLOOP;
END;
IncludePoint: PROC [points: PList, from, to: CD.Position] RETURNS [new: PList←NIL] =
BEGIN
after: INT ← 0;
cnt: INT ← 0;
dmin: REALLAST[INT];
last: CD.Position;
d: REAL;
FOR p: PList ← 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: PList ← points, p.rest WHILE p#NIL DO
new ← CONS[p.first, new];
ENDLOOP;
END;
RemovePoint: PROC [points: PList, from, to: CD.Position] RETURNS [new: PList←NIL] =
--to is ignored
BEGIN
pos: INT ← 0;
cnt: INT ← 0;
dmin: REALLAST[INT];
FOR p: PList ← 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 TerminalIO.WriteRope["degenerated polygon not created\n"];
FOR p: PList ← points, p.rest WHILE p#NIL DO
new ← CONS[p.first, new];
ENDLOOP;
END;
OrientedPoints: PROC [ap: CD.Instance] RETURNS [copy: PList←NIL] =
--ap must be application of a polygon object
BEGIN
pp: CDPolygons.PolygonPtr = NARROW[ap.ob.specificRef];
FOR p: PList ← pp.points, p.rest WHILE p#NIL DO
orientedP: CD.Position = CDOrient.MapPoint[
pointInCell: p.first,
cellSize: ap.ob.size,
cellInstOrient: ap.orientation,
cellInstPos: ap.location].pointInWorld;
copy ← CONS[orientedP, copy];
ENDLOOP;
END;
StretchPolygonComm: PROC [comm: CDSequencer.Command] =
BEGIN
ap: CD.Instance;
p: PROC [points: PList, from, to: CD.Position] RETURNS [PList];
r: Rope.ROPE;
SELECT comm.a FROM
$MovePolygonPoint => {p ← StretchPoints; r ← "stretch polygon"};
$AddPolygonPoint => {p ← IncludePoint; r ← "add point to polygon"};
$RemovePolygonPoint => {p ← RemovePoint; r ← "remove point from polygon"};
ENDCASE => {
TerminalIO.WriteRope["unknown command\n"];
RETURN
};
ap ← CDCommandOps.TheInstance[comm, r];
IF ap#NIL THEN {
WITH ap.ob.specificRef SELECT FROM
t: CDPolygons.PolygonPtr => {
offset: CD.Position;
ob: CD.Object;
oldPoints: PList ← OrientedPoints[ap];
newPoints: PList ← p[oldPoints, comm.sPos, comm.pos];
[ob: ob, offset: offset] ← CDPolygons.CreatePolygon[newPoints, ap.ob.layer];
IF ob=NIL THEN {
TerminalIO.WriteRope[" not done\n"];
RETURN
};
CDOps.DelayedRedraw[comm.design, CDInstances.InstRectO[ap]];
ap.ob ← ob;
ap.orientation ← CD.original;
ap.location ← offset;
CDOps.DelayedRedraw[comm.design, CDInstances.InstRectO[ap], FALSE];
}
ENDCASE => TerminalIO.WriteRope["selected ob is not polygon; not done\n"];
};
END;
CDSequencer.ImplementCommand[$DrawPolygon, DrawPolygonComm];
CDSequencer.ImplementCommand[$MovePolygonPoint, StretchPolygonComm];
CDSequencer.ImplementCommand[$AddPolygonPoint, StretchPolygonComm];
CDSequencer.ImplementCommand[$RemovePolygonPoint, StretchPolygonComm];
[] ← CDMenus.CreateMenu["Polygons", $PolygonMenu];
CDMenus.CreateEntry[$PolygonMenu, "draw polygon", $DrawPolygon];
CDMenus.CreateEntry[$PolygonMenu, "add point", $AddPolygonPoint];
CDMenus.CreateEntry[$PolygonMenu, "move point", $MovePolygonPoint];
CDMenus.CreateEntry[$PolygonMenu, "remove point", $RemovePolygonPoint];
CDMenus.ImplementMenuCommand[$PolygonMenu, $PolygonMenu];
END.