DIRECTORY JunoStorage USING [Constr, Point, Coords, Frame, Action, Cons, GcList, HorConstr, VerConstr, ParaConstr, PerpConstr, CongConstr, AtConstr, CcwConstr], JunoBody, JunoAlgebra USING [Se, Value, ValueList, comma, leftPren, semicolon, hor, ver, para, perp, cong, at, ccw, rel, print, draw, font, face, size, justified, true, skip, suchThat, if, approx, and, rightArrow], JunoMatrix USING [Matrix, MapCoords, InvertMatrix, GetFrameMatrix], Rope USING [ROPE], JunoImage USING [EnumPoints, EnumConstrs, EnumActions, PointVisitProc, ConstrVisitProc, ActionVisitProc, ActionIsWound, ConstrIsWound]; JunoBodyImpl: PROGRAM IMPORTS JunoStorage, JunoMatrix, JunoAlgebra, JunoImage EXPORTS JunoBody = BEGIN OPEN JunoBody, Stor: JunoStorage, Alg: JunoAlgebra, Mat: JunoMatrix, Im: JunoImage; Value: TYPE = Alg.Value; m: REF Mat.Matrix _ NEW[Mat.Matrix]; mInv: REF Mat.Matrix _ NEW[Mat.Matrix]; SingularFrame: ERROR = CODE; MakeBody: PUBLIC PROC [frame: Frame] RETURNS [body: Se] = BEGIN locals, actions, constrs: Se; sing: BOOL; m _ Mat.GetFrameMatrix[frame, m]; [mInv, sing] _ Mat.InvertMatrix[m, mInv]; IF sing THEN ERROR SingularFrame; locals _ BuildLocalList [frame, mInv]; constrs _ BuildConstrList[frame]; actions _ BuildActionList[]; IF locals = NIL AND constrs = Alg.true THEN {RETURN[actions]} ELSE {RETURN [LIST[Alg.if, LIST[Alg.rightArrow, LIST[Alg.suchThat, locals, constrs], actions]]]} END; BuildCoordsExpr: PROC [coords: Coords] RETURNS [expr: Se] = BEGIN RETURN[LIST[Alg.leftPren, LIST[Alg.comma, NEW[REAL _ coords.x], NEW[REAL _ coords.y]]]] END; BuildLocalList: PROC [frame: Frame, mInv: REF Mat.Matrix] RETURNS [locals: Se] = BEGIN framex: Se _ MakeFrameExpr[frame]; localList: LIST OF Se _ NIL; DeclarePoint: Im.PointVisitProc = {IF p.wn # 0 AND NOT p.fixed THEN {coords: Coords = Mat.MapCoords[p.coords, mInv]; relex: Se = LIST [Alg.rel, BuildCoordsExpr[coords], framex]; dec: Se = LIST[Alg.approx, p.name, relex]; localList _ Stor.Cons [dec, localList]}}; Im.EnumPoints[DeclarePoint]; locals _ ReverseAndNest[localList, Alg.comma, NIL]; Stor.GcList[localList] END; ReverseAndNest: PROC [args: LIST OF Se, op: Se, zero: Se] RETURNS [expr: Se] = BEGIN IF args = NIL THEN RETURN [zero]; expr _ args.first; args _ args.rest; FOR p: LIST OF Se _ args.rest, p.rest WHILE p # NIL DO expr _ LIST[op, p.first, expr] ENDLOOP; RETURN [expr] END; BuildConstrList: PROC [frame: Frame] RETURNS [constrs: Se] = BEGIN cExprList: LIST OF Se _ NIL; BuildConstr: PROC [c: Stor.Constr] RETURNS [cex: Se] = BEGIN OPEN Stor; op: ATOM; r1, r2: Se _ NIL; cfr: Frame = IF c.frame # [NIL, NIL, NIL] THEN c.frame ELSE frame; WITH c SELECT FROM cc: Stor.HorConstr => {op _ Alg.hor; r1 _ Pren2[cc.i, cc.j]}; cc: Stor.VerConstr => {op _ Alg.ver; r1 _ Pren2[cc.i, cc.j]}; cc: Stor.ParaConstr => {op _ Alg.para; r1 _ Pren2[cc.i, cc.j]; r2 _ Pren2[cc.k, cc.l]}; cc: Stor.PerpConstr => {op _ Alg.perp; r1 _ Pren2[cc.i, cc.j]; r2 _ Pren2[cc.k, cc.l]}; cc: Stor.CongConstr => {op _ Alg.cong; r1 _ Pren2[cc.i, cc.j]; r2 _ Pren2[cc.k, cc.l]}; cc: Stor.AtConstr => {op _ Alg.at; r1 _ cc.p.name; r2 _ BuildCoordsExpr[cc.coords]}; cc: Stor.CcwConstr => {op _ Alg.ccw; r1 _ Pren3[cc.i, cc.j, cc.k]}; ENDCASE => ERROR; cex _ IF r2 = NIL THEN LIST[op, r1] ELSE LIST[op, r1, r2]; IF cfr # [NIL, NIL, NIL] THEN {cex _ LIST[Alg.rel, cex, MakeFrameExpr[cfr]]}; END; {ProcessConstr: Im.ConstrVisitProc = {IF Im.ConstrIsWound[c] THEN {cExprList _ Stor.Cons[BuildConstr[c], cExprList]}}; Im.EnumConstrs[ProcessConstr]}; constrs _ ReverseAndNest [cExprList, Alg.and, Alg.true]; Stor.GcList[cExprList] END; BuildActionList: PROC RETURNS [actions: Se] = BEGIN acs: LIST OF REF ANY _ NIL; ListEm: Im.ActionVisitProc = {IF Im.ActionIsWound[a] THEN acs _ Stor.Cons[a, acs]}; Seq: PROC [e1, e2: Se] RETURNS [e: Se] = {RETURN[IF e2=Alg.skip THEN e1 ELSE LIST[Alg.semicolon, e1, e2]]}; Im.EnumActions[ListEm]; actions _ Alg.skip; FOR ap: LIST OF REF ANY _ acs, ap.rest WHILE ap # NIL DO a: Stor.Action = NARROW [ap.first]; BEGIN OPEN Stor, a; SELECT kind FROM draw => {aex: Se = LIST [Alg.draw, PrenArgs[args]]; actions _ Seq[aex, actions]}; print => {aex: Se = LIST [Alg.print, PrenArgs[args]]; actions _ Seq[aex, actions]}; font => {font: Rope.ROPE = NARROW[args.first]; actions _ LIST [Alg.font, font, actions]}; face => {face: ATOM = NARROW[args.first]; actions _ LIST [Alg.face, face, actions]}; size => {size: INT = NARROW[args.first, REF INT]^; actions _ LIST [Alg.size, NEW[INT _ size], actions]}; justify => {justification: ATOM = NARROW[args.first]; actions _ LIST [Alg.justified, justification, actions]}; call => {func: ATOM = NARROW[args.first]; vargs: Alg.ValueList = NARROW [args.rest]; aex: Se = IF vargs=NIL THEN func ELSE LIST[Alg.leftPren, func, UnEvalList[vargs]]; actions _ Seq[aex, actions]}; ENDCASE => {ERROR}; END ENDLOOP; Stor.GcList[acs] END; Nest: PUBLIC PROC [list: LIST OF Se, op, zero: ATOM] RETURNS [Se] = {IF list = NIL THEN RETURN [zero] ELSE IF list.rest = NIL THEN RETURN [list.first] ELSE RETURN [LIST[op, list.first, Nest[list.rest, op, zero]]]}; UnEval: PROC [arg: Alg.Value] RETURNS [expr: Se] = {WITH arg SELECT FROM aa: REF INT => RETURN [aa]; aa: REF REAL => RETURN [aa]; aa: Rope.ROPE => RETURN [aa]; aa: Point => RETURN [aa.name]; aa: LIST OF Alg.Value => RETURN [UnEvalList[aa]]; ENDCASE => ERROR}; UnEvalList: PROC [list: LIST OF Alg.Value] RETURNS [expr: Se] = {IF list.rest = NIL THEN RETURN [UnEval[ list.first]] ELSE RETURN [LIST[Alg.comma, UnEval[list.first], UnEvalList[list.rest]] ]}; Pren2: PROC [v1, v2: Value] RETURNS [expr: Se] = {RETURN [LIST[Alg.leftPren, LIST[Alg.comma, UnEval[v1], UnEval[v2]]]]}; Pren3: PROC [v1, v2, v3: Alg.Value] RETURNS [expr: Se] = {RETURN [LIST[Alg.leftPren, LIST[Alg.comma, UnEval[v1], LIST[Alg.comma, UnEval[v2], UnEval[v3]]]]]}; PrenArgs: PROC [arg: LIST OF Alg.Value] RETURNS [expr: Se] = {RETURN [LIST[Alg.leftPren, UnEvalList[arg]]]}; MakeFrameExpr: PROC [frame: Frame] RETURNS [expr: Se] = {RETURN [IF frame.org =NIL THEN NIL ELSE IF frame.hor = NIL THEN frame.org.name ELSE IF frame.ver = NIL THEN Pren2[frame.org, frame.hor] ELSE Pren3[frame.org, frame.hor, frame.ver]]}; END. InsertPoint: PROCEDURE[p:PointPtr] = BEGIN temp: PointPtr _ pointLpad; WHILE temp.link.x < p.x DO temp _ temp.link ENDLOOP; p.link _ temp.link; temp.link _ p; END; SortPoints: PUBLIC PROC = {p,q,r, temp: PointPtr; IF pointLpad = pointRpad THEN RETURN; p _ pointLpad.link; q _ p.link; p.link _ pointLpad; UNTIL q = pointRpad DO IF q.x >= p.x THEN {temp _ q.link; q.link _ p; p _ q; q _ temp; LOOP}; -- Insert q into list p, link[p], link[link[p]], which is sorted in DESCENDING order. r _ p; WHILE r.link.x > q.x DO r _ r.link ENDLOOP; temp _ q.link; q.link _ r.link; r.link _ q; q _ temp; ENDLOOP; -- Now reverse the list by moving backwards through it: UNTIL p = pointLpad DO temp _ p.link; p.link _ q; q _ p; p _ temp; ENDLOOP; pointLpad.link _ q}; Distance: PROCEDURE[x1, y1, x2, y2: REAL] RETURNS [REAL] = -- this procedure returns the distance between the points (x1,y1) -- and (x2,y2). BEGIN RETURN [RealFns.SqRt[(x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)]] END; FindSelectedPoint: PUBLIC PROCEDURE [x,y:REAL] RETURNS [PointPtr] = -- This procedure finds the selected point closest to the current mouse coordinates. -- It is identical to FindPoint except that slink replaces link. This is a good -- example of why field selectors should be values. BEGIN leftpad: PointPtr = pointLpad; rightpad: PointPtr = pointRpad; p, champ: PointPtr; champdistance, pdistance: REAL; p _ leftpad.slink; IF p = rightpad THEN RETURN[NIL]; champ _ p; champdistance _ Distance[p.x, p.y, x, y]; p _ p.slink; WHILE p # rightpad DO pdistance _ Distance[p.x, p.y, x, y]; IF pdistance < champdistance THEN BEGIN champ _ p; champdistance _ pdistance END; p _ p.slink; ENDLOOP; RETURN [champ]; END; m, m1, mInv: ARRAY [1..3] OF ARRAY [1..3] OF REAL; singular: PUBLIC BOOLEAN; Invertm: PROC = -- Inverts m into mInv by pivoting three times; or sets "singular" flag. BEGIN i, j, k, l: INTEGER; c: ARRAY [1..3] OF INTEGER; pivoted: ARRAY [1..3] OF BOOLEAN _ [FALSE, FALSE, FALSE]; p: REAL; -- k is the row in which we are pivoting. -- l is the column in which we are pivoting. -- i and j are miscellaneous row and column indices respectively -- c[i] is the column of the pivot in the ith row. -- p is the reciprocal of the pivot element; also used as temp for swapping. singular _ FALSE; FOR k IN [1..3] DO -- set l so m[k,l] is largest of m[k,1], m[k, 2], m[k, 3], excluding -- columns in which we have already pivoted. p _ 0; FOR j IN [1 .. 3] DO IF ABS[m[k][j]] >= p AND NOT pivoted[j] THEN {l _ j; p _ ABS[m[k][l]]} ENDLOOP; -- We will pivot at m[k,l], if it is not too small: IF ABS[m[k][l]] < .0001 THEN {singular _ TRUE; RETURN}; c[k] _ l; pivoted[l] _ TRUE; p _ 1.0 / m[k][l]; m[k][l] _ 1.0; -- divide everything in pivot row by the pivot element: FOR j IN [1..3] DO m[k][j] _ m[k][j] * p ENDLOOP; FOR i IN [1..3] DO IF i # k THEN FOR j IN [1..3] DO IF j # l THEN -- for each m[i,j] outside the pivot row and column m[i][j] _ m[i][j] - m[i][l] * m[k][j]; -- note that m[k,j] was already * p. ENDLOOP ENDLOOP; -- Finally process pivot column: FOR i IN [1..3] DO IF i # k THEN m[i][l] _ -m[i][l] * p ENDLOOP; ENDLOOP; -- Now we permute rows and columns: FOR i IN [1..3] DO FOR j IN [1..3] DO mInv[c[i]][j] _ m[i][c[j]] ENDLOOP ENDLOOP; END; MultiplyMatrix: PROCEDURE = -- multiply m1 * mInv to produce m. BEGIN i, j, k: INTEGER; sum: REAL; FOR i IN [1..3] DO FOR j IN [1..3] DO {sum _ 0.0; FOR k IN [1..3] DO sum _ sum + m1[i][k] * mInv[k][j] ENDLOOP; m[i][j] _ sum} ENDLOOP ENDLOOP; END; Identify: PUBLIC PROC[] = -- replace all occurences of p by p.copy if p.copy # NIL. {r, rr: PointPtr; ScanLists[operation:move]; r _ pointLpad; UNTIL r = pointRpad DO IF r.link.copy # NIL THEN {rr _ r.link; r.link _ rr.link; GcPoint[rr]} ELSE r _ r.link; ENDLOOP}; MakeDefBody: PUBLIC PROC[orig, xaxis: PointPtr] RETURNS [REF] = {IF xaxis = NIL THEN RETURN[OtherMakeDefBody[orig]] ELSE {m[1][1] _ orig.x; m[2][1] _ orig.y; m[1][2] _ xaxis.x; m[2][2] _ xaxis.y; m1[1][1] _ 0; m1[2][1] _ 0; m1[1][2] _ 1; m1[2][2] _ 0; m[1][3] _ m[1][1] + m[2][1] - m[2][2]; m[2][3] _ m[2][1] + m[1][2] - m[1][1]; FOR j: INT IN [1..3] DO m[3][j] _ 1.0; m1[3][j] _ 1.0 ENDLOOP; m1[1][3] _ m1[1][1] + m1[2][1] - m1[2][2]; m1[2][3] _ m1[2][1] + m1[1][2] - m1[1][1]; Invertm[]; IF singular THEN ERROR; MultiplyMatrix[]; {p:PointPtr _ pointLpad.link; WHILE p # pointRpad DO p.name _ NIL; p _ p.link ENDLOOP}; BuildLocalList[orig, xaxis]; BuildActionAndPredLists[]; {locals: REF _ IF localList = NIL THEN NIL ELSE Fix[localList, comma]; actions: REF _ IF actionList = NIL THEN $Skip ELSE Fix[actionList, semicolon]; preds: REF; IF predList = NIL THEN preds _ $T ELSE preds _ Fix[predList, $and]; IF locals = NIL THEN RETURN[actions] ELSE RETURN [LIST[$if, LIST[arrow, LIST[st, locals, preds], actions]]]}}}; OtherMakeDefBody: PROC[orig: PointPtr] RETURNS [REF] = {p:PointPtr _ pointLpad.link; WHILE p # pointRpad DO p.name _ NIL; p _ p.link ENDLOOP; BuildLocalList[orig, NIL]; BuildActionAndPredLists[]; {locals: REF _ IF localList = NIL THEN NIL ELSE Fix[localList, comma]; actions: REF _ IF actionList = NIL THEN $Skip ELSE Fix[actionList, semicolon]; preds: REF; IF predList = NIL THEN preds _ $T ELSE preds _ Fix[predList, $and]; IF locals = NIL THEN RETURN[actions] ELSE RETURN [LIST[$if, LIST[arrow, LIST[st, locals, preds], actions]]]}}; arrow: ATOM = Atom.MakeAtom["->"]; st: ATOM = Atom.MakeAtom["|"]; comma: ATOM = Atom.MakeAtom[","]; semicolon: ATOM = Atom.MakeAtom[";"]; approx: ATOM = Atom.MakeAtom["=="]; leftpren: ATOM = Atom.MakeAtom["("]; Fix: PROC [rr: REF, op: REF] RETURNS [REF] = {r: LIST OF REF _ NARROW[rr]; IF r.rest = NIL THEN RETURN [r.first] ELSE RETURN [LIST[op, r.first, Fix[r.rest, op]]]}; localList: LIST OF REF; actionList: LIST OF REF; predList: LIST OF REF; BuildLocalList: PROC [orig, xaxis: PointPtr] = {i: INT _ 2; p: PointPtr _ pointLpad.slink; x, y: REAL; localList _ NIL; UNTIL p = pointRpad DO IF p = orig THEN p.name _ $a ELSE IF p = xaxis THEN p.name _ $b ELSE {a: ATOM; IF i > 25 THEN a _ Atom.MakeAtom[Rope.Cat["a", Convert.RopeFromInt[i - 26, 10, FALSE]]] ELSE a _ Atom.MakeAtom[Rope.FromChar['a + i]]; p.name _ a; i _ i + 1; IF xaxis # NIL THEN {x _ p.x * m[1][1] + p.y * m[1][2] + m[1][3]; y _ p.x * m[2][1] + p.y * m[2][2] + m[2][3]; localList _ CONS[ LIST[approx, a, LIST[$rel, LIST[leftpren, LIST[comma, NEW[REAL _ x], NEW[REAL _ y]]], LIST[leftpren, LIST[comma, $a, $b]]]], localList]} ELSE {x _ p.x - orig.x; y _ p.y - orig.y; localList _ CONS[ LIST[approx, a, LIST[$rel, LIST[leftpren, LIST[comma, NEW[REAL _ x], NEW[REAL _ y]]], LIST[leftpren, $a]]], localList]}}; JunoGraphics.DrawRope[Atom.GetPName[NARROW[p.name]], p.x + 5, p.y + 5]; JunoGraphics.viewerChanged _ TRUE; p _ p.slink ENDLOOP}; BuildActionAndPredLists: PROC = {actionList _ NIL; predList _ NIL; ScanLists[operation: build]}; copiedPoints: PUBLIC PointPtr; Copy: PUBLIC PROCEDURE = BEGIN p, lastnew: PointPtr; -- copy the list of selected points into a new list firstnew, -- firstnew.slink .... copiedPoints _ NewPoint[]; lastnew _ copiedPoints; p _ pointLpad.slink; p.copy _ copiedPoints; copiedPoints.x _ p.x; copiedPoints.y _ p.y; copiedPoints.visible _ p.visible; InsertPoint[copiedPoints]; p _ p.slink; UNTIL p = pointRpad DO lastnew.slink _ NewPoint[]; lastnew _ lastnew.slink; p.copy _ lastnew; lastnew.x _ p.x; lastnew.y _ p.y; copiedPoints.visible _ p.visible; InsertPoint[lastnew]; p _ p.slink; ENDLOOP; lastnew.slink _ pointRpad; ScanLists[operation: copy]; -- scan all edges, arcs, constraints and copy -- any of them that involve copied points. END; ComputeTransform: PUBLIC PROC[a,b,c,sa,sb,sc:PointPtr] = {-- we want m [ sa, sb, sc ] = [ a, b, c], where the points are viewed as -- column vectors with third component 1. Hence we compute the inverse -- of [sa, sb, sc] and multipy on the left by [a, b, c]. But the pairs -- (b, sb), (c, sc) may be missing, in which case they are filled in by default to make -- the transformation a translation (if both are missing) or a Euclidean motion -- (if just (c, sc) is missing). j: INTEGER; FOR j IN [1..3] DO m[3][j] _ 1.0; m1[3][j] _ 1.0 ENDLOOP; m[1][1] _ sa.x; m[2][1] _ sa.y; m1[1][1] _ a.x; m1[2][1] _ a.y; IF b # NIL AND sb # NIL THEN {m[1][2] _ sb.x; m[2][2] _ sb.y; m1[1][2] _ b.x; m1[2][2] _ b.y;} ELSE {m[1][2] _ sa.x + 300; m[2][2] _ sa.y; m1[1][2] _ a.x + 300; m1[2][2] _ a.y}; IF c # NIL AND sc # NIL THEN {m[1][3] _ sc.x; m[2][3] _ sc.y; m1[1][3] _ c.x; m1[2][3] _ c.y} ELSE {m[1][3] _ m[1][1] + m[2][1] - m[2][2]; m[2][3] _ m[2][1] + m[1][2] - m[1][1]; m1[1][3] _ m1[1][1] + m1[2][1] - m1[2][2]; m1[2][3] _ m1[2][1] + m1[1][2] - m1[1][1]}; Invertm[]; IF singular THEN RETURN; MultiplyMatrix[]}; -- end of ComputeTransform. PerformTransform: PUBLIC PROCEDURE[p: PointPtr] = {x, y: REAL; UNTIL p = pointRpad DO x _ p.x * m[1][1] + p.y * m[1][2] + m[1][3]; y _ p.x * m[2][1] + p.y * m[2][2] + m[2][3]; p.x _ x; p.y _ y; p _ p.slink; ENDLOOP}; Operation: TYPE = {copy, delete, move, mark, build}; AddAction: PROC[op: REF, r1: REF _ NIL, r2: REF _ NIL] = {IF r2 = NIL THEN actionList _ CONS[LIST[op, r1], actionList] ELSE actionList _ CONS[LIST[op, r1, r2], actionList]}; Args: PROC [l: LIST OF PointPtr] RETURNS [REF] = {IF l.rest = NIL THEN RETURN [ArgName[l.first]] ELSE RETURN [LIST[comma, ArgName[l.first], Args[l.rest]]]}; NewArgs: PROC [l: LIST OF REF] RETURNS [REF] = {IF l.rest = NIL THEN RETURN [ArgName[l.first]] ELSE RETURN [LIST[comma, ArgName[l.first], NewArgs[l.rest]]]}; ArgName: PROC [r: REF] RETURNS [REF] = { WITH r SELECT FROM rp: PointPtr => RETURN[rp.name]; ri: REF INT => RETURN[ri]; rr: Rope.ROPE => RETURN[rr]; ra: ATOM => RETURN[ra] ENDCASE => ERROR }; PrenArgs: PROC [l: LIST OF PointPtr] RETURNS [REF] = {RETURN [LIST[leftpren, Args[l]]]}; AddPred: PROC[op: REF, r1: REF _ NIL, r2: REF _ NIL] = {IF r2 = NIL THEN predList _ CONS[LIST[op, r1], predList] ELSE predList _ CONS[LIST[op, r1, r2], predList]}; ScanLists: PROC[operation:Operation] = BEGIN { -- scan the edges: p: EdgePtr _ edgeLpad.link; q: EdgePtr _ edgeLpad; r: EdgePtr; UNTIL p = edgeRpad DO SELECT operation FROM move => {IF p.b1.copy # NIL THEN p.b1 _ p.b1.copy; IF p.b2.copy # NIL THEN p.b2 _ p.b2.copy; p _ p.link}; copy => {IF p.b1.copy # NIL AND p.b2.copy # NIL THEN {r _ NewEdge[]; r.b1 _ p.b1.copy; r.b2 _ p.b2.copy; r.link _ edgeLpad.link; edgeLpad.link _ r}; p _ p.link}; delete => IF p.b1.copy # NIL AND p.b2.copy # NIL THEN {q.link _ p.link; GcEdge[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.b1.copy _ NIL; p.b2.copy _ NIL; p _ p.link}; build => {IF p.b1.name # NIL AND p.b2.name # NIL THEN AddAction[$draw, PrenArgs[LIST[p.b1, p.b2]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; {-- scan the arcs: p: ArcPtr _ arcLpad.link; q: ArcPtr _ arcLpad; r: ArcPtr; UNTIL p = arcRpad DO SELECT operation FROM move => {IF p.b1.copy # NIL THEN p.b1 _ p.b1.copy; IF p.b2.copy # NIL THEN p.b2 _ p.b2.copy; IF p.b3.copy # NIL THEN p.b3 _ p.b3.copy; IF p.b4.copy # NIL THEN p.b4 _ p.b4.copy; p _ p.link}; copy => {IF p.b1.copy # NIL AND p.b2.copy # NIL AND p.b3.copy # NIL AND p.b4.copy # NIL THEN {r _ NewArc[]; r.b1 _ p.b1.copy; r.b2 _ p.b2.copy; r.b3 _ p.b3.copy; r.b4 _ p.b4.copy; r.link _ arcLpad.link; arcLpad.link _ r}; p _ p.link}; delete => IF p.b1.copy # NIL AND p.b2.copy # NIL AND p.b3.copy # NIL AND p.b4.copy # NIL THEN {q.link _ p.link; GcArc[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.b1.copy _ NIL; p.b2.copy _ NIL; p.b3.copy _ NIL; p.b4.copy _ NIL; p _ p.link}; build => {IF p.b1.name # NIL AND p.b2.name # NIL AND p.b3.name # NIL AND p.b4.name # NIL THEN AddAction[$draw, PrenArgs[LIST[p.b1, p.b2, p.b3, p.b4]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; { -- scan the strings: p : StringPtr _ stringLpad.link; q : StringPtr _ stringLpad; r : StringPtr; UNTIL p = stringRpad DO SELECT operation FROM move => {IF p.b3.copy # NIL THEN p.b3 _ p.b3.copy; IF p.b4.copy # NIL THEN p.b4 _ p.b4.copy; p _ p.link}; copy => {IF p.b3.copy # NIL AND p.b4.copy # NIL THEN {r _ NewString[]; r.b3 _ p.b3.copy; r.b4 _ p.b4.copy; r.stringText _ p.stringText; r.fontName _ p.fontName; r.fontSize _ p.fontSize; r.bold _ p.bold; r.italic _ p.italic; r.height _ p.height; r.width _ p.width; r.depth _ p.depth; r.link _ stringLpad.link; stringLpad.link _ r}; p _ p.link}; delete => IF p.b3.copy # NIL AND p.b4.copy # NIL THEN {q.link _ p.link; GcString[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.b3.copy _ NIL; p.b4.copy _ NIL; p _ p.link }; build => {Pack: PROC[b, i: BOOL] RETURNS [r:INT] = {r _ 0; IF i THEN r _ r + 1; IF b THEN r _ r + 2}; IF p.b3.name # NIL THEN AddAction [leftpren, $print, NewArgs[LIST[p.stringText, p.b3, Atom.MakeAtom[p.fontName], NEW[INT _ p.fontSize], NEW[INT _ Pack[p.bold, p.italic]]]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; { -- scan the horizontal constraints: p: HorPtr _ horLpad.link; q: HorPtr _ horLpad; r: HorPtr; UNTIL p = horRpad DO SELECT operation FROM move => {IF p.i.copy # NIL THEN p.i _ p.i.copy; IF p.j.copy # NIL THEN p.j _ p.j.copy; p _ p.link}; copy => {IF p.i.copy # NIL AND p.j.copy # NIL THEN {r _ NewHor[]; r.i _ p.i.copy; r.j _ p.j.copy; r.link _ horLpad.link; horLpad.link _ r}; p _ p.link}; delete => IF p.i.copy # NIL AND p.j.copy # NIL THEN {q.link _ p.link; GcHor[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.i.copy _ NIL; p.j.copy _ NIL; p _ p.link}; build => {IF p.i.name # NIL AND p.j.name # NIL THEN AddPred[$hor, PrenArgs[LIST[p.i, p.j]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; { -- scan the vertical constraints: p: VerPtr _ verLpad.link; q: VerPtr _ verLpad; r: VerPtr; UNTIL p = verRpad DO SELECT operation FROM move => {IF p.i.copy # NIL THEN p.i _ p.i.copy; IF p.j.copy # NIL THEN p.j _ p.j.copy; p _ p.link}; copy => {IF p.i.copy # NIL AND p.j.copy # NIL THEN {r _ NewVer[]; r.i _ p.i.copy; r.j _ p.j.copy; r.link _ verLpad.link; verLpad.link _ r}; p _ p.link}; delete => IF p.i.copy # NIL AND p.j.copy # NIL THEN {q.link _ p.link; GcVer[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.i.copy _ NIL; p.j.copy _ NIL; p _ p.link}; build => {IF p.i.name # NIL AND p.j.name # NIL THEN AddPred[$ver, PrenArgs[LIST[p.i, p.j]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; {-- scan the congruence constraints: p: CongPtr _ congLpad.link; q: CongPtr _ congLpad; r: CongPtr; UNTIL p = congRpad DO SELECT operation FROM move => {IF p.i.copy # NIL THEN p.i _ p.i.copy; IF p.j.copy # NIL THEN p.j _ p.j.copy; IF p.k.copy # NIL THEN p.k _ p.k.copy; IF p.l.copy # NIL THEN p.l _ p.l.copy; p _ p.link}; copy => {IF p.i.copy # NIL AND p.j.copy # NIL AND p.k.copy # NIL AND p.l.copy # NIL THEN {r _ NewCong[]; r.i _ p.i.copy; r.j _ p.j.copy; r.k _ p.k.copy; r.l _ p.l.copy; r.link _ congLpad.link; congLpad.link _ r}; p _ p.link}; delete => IF p.i.copy # NIL AND p.j.copy # NIL AND p.k.copy # NIL AND p.l.copy # NIL THEN {q.link _ p.link; GcCong[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.i.copy _ NIL; p.j.copy _ NIL; p.k.copy _ NIL; p.l.copy _ NIL; p _ p.link}; build => {IF p.i.name # NIL AND p.j.name # NIL AND p.k.name # NIL AND p.l.name # NIL THEN AddPred[$cong, PrenArgs[LIST[p.i, p.j]], PrenArgs[LIST[p.k, p.l]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; {-- scan the line constraints: p: LinPtr _ lineLpad.link; q: LinPtr _ lineLpad; r: LinPtr; UNTIL p = lineRpad DO SELECT operation FROM move => {IF p.i.copy # NIL THEN p.i _ p.i.copy; IF p.j.copy # NIL THEN p.j _ p.j.copy; IF p.k.copy # NIL THEN p.k _ p.k.copy; IF p.l.copy # NIL THEN p.l _ p.l.copy; p _ p.link}; copy => {IF p.i.copy # NIL AND p.j.copy # NIL AND p.k.copy # NIL AND p.l.copy # NIL THEN {r _ NewLine[]; r.i _ p.i.copy; r.j _ p.j.copy; r.k _ p.k.copy; r.l _ p.l.copy; r.link _ lineLpad.link; lineLpad.link _ r}; p _ p.link}; delete => IF p.i.copy # NIL AND p.j.copy # NIL AND p.k.copy # NIL AND p.l.copy # NIL THEN {q.link _ p.link; GcLine[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.i.copy _ NIL; p.j.copy _ NIL; p.k.copy _ NIL; p.l.copy _ NIL; p _ p.link}; build => {IF p.i.name # NIL AND p.j.name # NIL AND p.k.name # NIL AND p.l.name # NIL THEN AddPred[$para, PrenArgs[LIST[p.i, p.j]], PrenArgs[LIST[p.k, p.l]]]; p _ p.link} ENDCASE => ERROR; ENDLOOP}; {-- scan the counter-clockwise constraints: p: CCPtr _ ccLpad.link; q: CCPtr _ ccLpad; r: CCPtr; UNTIL p = ccRpad DO SELECT operation FROM move => {IF p.i.copy # NIL THEN p.i _ p.i.copy; IF p.j.copy # NIL THEN p.j _ p.j.copy; IF p.k.copy # NIL THEN p.k _ p.k.copy; p _ p.link}; copy => {IF p.i.copy # NIL AND p.j.copy # NIL AND p.k.copy # NIL THEN {r _ NewCC[]; r.i _ p.i.copy; r.j _ p.j.copy; r.k _ p.k.copy; r.link _ ccLpad.link; ccLpad.link _ r}; p _ p.link}; delete => IF p.i.copy # NIL AND p.j.copy # NIL AND p.k.copy # NIL THEN {q.link _ p.link; GcCC[p]; p _ q.link} ELSE {q _ p; p _ p.link}; mark => {p.i.copy _ NIL; p.j.copy _ NIL; p.k.copy _ NIL; p _ p.link}; ENDCASE => ERROR; ENDLOOP}; { -- scan the algebraic constructions p: LIST OF ApplyRecord _ constructionList; q: LIST OF PointPtr _ NIL; r: LIST OF ApplyRecord _ NIL; UNTIL p = NIL DO SELECT operation FROM move => {q _ p.first.args; UNTIL q = NIL DO IF q.first.copy # NIL THEN q.first _ q.first.copy; q _ q.rest ENDLOOP; p _ p.rest}; copy => {IF AllHaveCopies[p.first.args] THEN AddX[p.first.f, ListOfCopies[p.first.args]]; p _ p.rest}; delete => {IF AllHaveCopies[p.first.args] THEN {IF r = NIL THEN {constructionList _ constructionList.rest; p _ p.rest} ELSE {r.rest _ p.rest; p _ p.rest}} ELSE {r _ p; p _ p.rest}}; mark => {SetCopiesToNil[p.first.args]; p _ p.rest}; build => {IF AllHaveNames[p.first.args] THEN actionList _ CONS[LIST[leftpren, p.first.f, Args[p.first.args]], actionList]; p _ p.rest} ENDCASE => ERROR; ENDLOOP} END; -- finally. AllHaveCopies: PROC[l: LIST OF PointPtr] RETURNS [BOOL] = {RETURN [l = NIL OR l.first.copy # NIL AND AllHaveCopies[l.rest]]}; AllHaveNames: PROC[l: LIST OF PointPtr] RETURNS [BOOL] = {RETURN [l = NIL OR l.first.name # NIL AND AllHaveNames[l.rest]]}; ListOfCopies: PROC [l: LIST OF PointPtr] RETURNS [LIST OF PointPtr] = {IF l = NIL THEN RETURN [NIL]; RETURN [CONS[l.first.copy, ListOfCopies[l.rest]]]}; SetCopiesToNil: PROC [l: LIST OF PointPtr] = {IF l # NIL THEN {l.first.copy _ NIL; SetCopiesToNil[l.rest]}}; Delete: PUBLIC PROCEDURE = BEGIN p: PointPtr _ pointLpad.slink; UNTIL p = pointRpad DO p.copy _ p; p _ p.slink ENDLOOP; ScanLists[delete]; ScanLists[mark]; DeleteOriginals[]; END; DeleteOriginals: PROC[] = BEGIN p, q: PointPtr; p _ pointLpad.link; q _ pointLpad; UNTIL p = pointRpad DO IF p.copy = NIL THEN {q _ p; p _ p.link} ELSE {p.copy _ NIL; q.link _ p.link; GcPoint[p]; p _ q.link}; ENDLOOP; END; @ JunoBodyImpl.mesa Coded July 1981 by Greg Nelson Last edited by GNelson June 13, 1983 5:05 pm Last edited by Stolfi May 31, 1984 6:06:17 pm PDT This module is concerned with converting selected constraints and actions from the current image into an equivalent Juno S-expression. - - - - IMPORTED TYPES - - - - PUBLIC PROCEDURES Get the reference frame matrix: Build the expression: - - - - FIX THESE THINGS FROM HERCULES Retirns a Juno expression for the given coordinates, of the form ( ( ^x ^y )). Retirns a Juno expression declaring all wound but unmarked points as local variables. The hint for each point will be its current position, relative to the given frame; mInv should be the matrix of the viewer's frame relative to the given one. ?? Is it OK for all hints to share the same frame expression? Returns a Juno expression describing the conjunction of all constraints affecting only wound points. - - - - CLEAN UP THE JUNK BELOW Now the procedures that are invoked as commands: The move, copy, and delete commands operate on groups, and the former two involve -- linear transformations, so before giving their code, we give the program that -- inverts a matrix. It sets "singular" to TRUE if the matrix is singular. The move, copy and delete commands all involve scanning the lists of edges, -- arcs, and constraints; this scan is done by one procedure (ScanLists) which -- takes as an argument one of the four distinguished values copy, delete, move, mark: - - - - OLD JUNK Edited March 7, 1984 2:42:12 am PST by Stolfi Tioga formatting Ê—˜™™J™J™,J™4—J™‡—šÏk œ˜ Jš œœ«œÜœ;œœœƒ˜‚—šœ˜šœ˜Jšœ1˜1—Jšœœ ˜—šœœ˜ JšœO˜O—™JšœÏbœœ ˜—™Jšœœœ ˜%Jšœœœ ˜(Jšœž œœœ˜š œÏnœœœœ˜;šœ˜Jšœ%œ˜*šœ ™ JšœMœœœ˜n—šœ™Jšœf˜fJšœœ œœœœ œœœœœ1˜¶——Jšœœ˜——™'šœŸœœœ ˜™>Jšœ˜Jšœ/œ˜4Jšœ˜—Jšœœ˜—š œŸœœœœœ ˜OJš!œœœœœœ2œœœœœœœ œœœœ˜Ð—šœŸœœœ˜=Jšœe™ešœ˜Jšœ œœœ˜šœŸ œœœ ˜8šœœœ˜Jšœœœœ œœœœ œ˜_šœœœ˜šœ˜Jšœ(˜(—šœ˜Jšœ(˜(—šœ˜JšœA˜A—šœ˜JšœA˜A—šœ˜JšœA˜A—šœ˜Jšœ@˜@—šœ˜Jšœ.˜.—Jšœœœ˜—Jšœœœœœ œœœœœœœ œ$˜—Jšœœ˜—Jšœž œœœV˜œJšœ9˜9Jšœ˜—Jšœœ˜—šœŸœœœ˜.šœ˜Jš œœœœœœ˜šœžœ˜Jšœœœ˜7—šœŸœœœ ˜)Jš œœœ œœœ˜C—Jšœ˜Jšœ˜šœœœœœœœœ˜9šœœ ˜$šœœœ ˜šœœ˜šœ˜Jšœ œ;˜L—šœ ˜ Jšœ œ<˜M—šœ˜Jšœ œœœ˜S—šœ˜Jšœœœœ˜N—šœ˜Jšœœœ œœœ œœ˜b—šœ ˜ Jšœœœœ*˜e—šœ˜Jšœœœ&œœœœ œœG˜Ç—šœœ˜ Jšœœ˜ ———Jšœ˜——Jšœœ˜ Jšœ˜—Jšœœ˜—šœŸœœœœœœœ˜DJšœœœœœ œœ œœœœœœ1˜™—šœŸœœœ ˜3Jš#œœœœ œœœœœœœœœœœœœœ˜î—š œŸ œœœœ œ ˜@Jšœœ œ œœœœœ:˜‘—šœŸœœœ ˜1Jšœœœœ)˜J—šœŸœœœ ˜9Jš œœœœœ*˜l—š œŸœœœœ œ ˜=Jšœœœ$˜2—šœŸ œœœ ˜8Jšœœœ œœœœœ œœœœ œœ#œ,˜Ð——Jšœœ˜™ JšœŸ œ œœ%œœœ/œ˜¸Jš)œŸ œœœ!œœœBœœœ œ.œÏcVœœœ œPœ¡8œœœ-œ˜’JšœŸœ œœœœ¡Bœ¡œœœ3œ˜ØJš.œŸœœ œœœ¡Uœ¡Qœ¡4œvœœœœœMœœ/œœœ&œœœ œ˜òJšœ0™0Jšœí™íJšœœœœœœ œœ˜MJš¡œŸœœ¡Iœœœ œœœœœœœœœ œ¡*œ¡-œ¡Aœ¡3œ¡Mœœœœœ¡Eœ¡-œœœœœœœœ œ œ œ¡4œœœœ œœ œ1¡8œœœœœœœœ œœœœœœœ¡4œ.¡%œœœ¡!œœœœœœœœ¡$œ œœœœœœœœ œ˜Ÿ Jš'œŸœ œ¡$œœœ œœœœœœœœœœ#œœœœ˜¥JšœŸœœœ¡:œCœœœœœHœœ˜±Jš_œŸ œœœœœœ œœœœ÷œœœœœsœ œœ=œœ œ œRœœ œœœœ%œœœœœ(œœ œœ œ"œ œœœœœœœœ$˜æJšEœŸœœœœ%œœ œ œœ,œœ œœœœ%œœœœœ(œœ œœ œ"œ œœœœœœœœ#˜ÁJš œœœœ"œœ"œ˜ÓJš#œŸœœœœœœ œœœœ œ œœœœœœ!˜°Jšœ œœœœœœ œœœ˜HJš]œŸœœœ-œœœœœ œœœ œœœœœAœ œNœ œœtœœ œœœœœœœœ œ)œ@œœ œœœœœœœœNœ?œœ˜îJš œŸœœœœ ˜cJšœœ ˜JšœŸœœ œœ¡>œ¡œþœœëœA¡.œ ¡+œœ˜áJš<œŸœœœ¡Iœ¡Gœ¡Hœ¡Xœ¡Pœ¡!œœœœœœRœœœœœWœeœœœœœVœÈœ œœ¡˜ä JšœŸœœ œœœœ–œ˜ûJšœó™óJšœ œ&˜6JšœŸ œœœœœœœœœœœœœœœ˜¸JšœŸœœœœ œœœ œœœœœœ*˜§JšœŸœœœœœœœœ œœœœœœ-˜¨Jš%œŸœœœœœœœœœœœœœœœœœœ˜×JšœŸœœœœ œœœœ˜[JšœŸœœœœœœœœœœ œœœ œœ˜®JšúœŸ œœœ¡œTœœœ œœ œœœ œœ1œ œœ œ œ–œ œœ œœ/œ9œœ$œ œœ œœ&œ-œœœ ¡œOœ œœ œœ œœœ œœœ œœœ œœ1œ œœ œœ œœ œ œ»œ œœ œœ œœ œœ.œ9œœœœ(œ œœ œœ œœ œœœMœœœ ¡œfœœœ œœ œœ'œ œœTœ œœ œœ€œ œœ œœ;œDœœCŸœœœœœ'œœœœ!œ œœzœ®œœ:œœTœœ œ¡$œOœ œœ œœ œœœ œœ/œ œœ œ œœ œœ œœ.œ8œ œ*œ œœ œœœ/œœœ ¡"œOœ œœ œœ œœœ œœ/œ œœ œ œœ œœ œœ.œ8œ œ*œ œœ œœœ0œœœ ¡$œTœœœ œœ œœœ œœœ œœœ œœ/œ œœ œœ œœ œ œ¶œ œœ œœ œœ œœ/œ8œ œ œ œ(œ œœ œœ œœ œœœœ?œœœ ¡œQœœœ œœ œœœ œœœ œœœ œœ/œ œœ œœ œœ œœ·œ œœ œœ œœ œœ/œ8œ œ œ œ(œ œœ œœ œœ œœœœ0œœœ¡+œJœ œœ œœ œœœ œœœ œœ/œ œœ œœ œœ¡œ œœ œœ œœ-œ8œ œ œœœœ ¡$œœœ'œœ œœœœ œœœœ œ<œœœœœœPœ6œ2œcœ2œœœœrœ5œqœ*œ"œœtœœœœ¡ ˜“SJšœŸ œœœœ œœœœœœœ˜€JšœŸ œœœœ œœœœœœœ˜~JšœŸ œœœœ œœœœœœœœœœ'˜žJšœŸœœœœœœœœ˜pJšœŸœœ œœ(œœœGœ˜ÍJšœŸœœœDœœœ œœœ œ0œœ˜‡—™™.J™———…—qôË