File: ParquetImplC.mesa   
Copyright © 1984 by Xerox Corporation. All rights reserved.
Created by: Mayo, July 16, 1984 4:44:25 pm PDT
Last Edited by: Mayo, November 5, 1984 4:24:33 pm PST
-- Procedures to deal with Parquet's alignment marks.
DIRECTORY
Parquet,
ParquetInternal,
CD,
CDBasics USING [AddPoints],
CDOrient USING [ConcentrateOnRotate90, IncludesOddRot90, rotate180, rotate270, IncludesMirrorX],
Rope USING [ROPE, Equal, Length, Substr, Fetch];
ParquetImplC: CEDAR PROGRAM    
IMPORTS Parquet, ParquetInternal, CDBasics, Rope, CDOrient EXPORTS Parquet, ParquetInternal =  
BEGIN OPEN Parquet, ParquetInternal;
-- store one mark into a tile
StoreMark: PUBLIC PROC [t: Tile, m: Mark] = BEGIN
length: INT ← Rope.Length[m.name];
IF Rope.Fetch[m.name, length-1] = '^ THEN { -- strip off '^ and export it
mark: Mark ← NEW[MarkRec ← m^];
mark.name ← Rope.Substr[m.name, 0, length-1];
t.exportMarks ← CONS[mark, t.exportMarks];
};
m.owner ← LOOPHOLE[t]; -- a unique id for the tile
SELECT TRUE FROM
Rope.Equal[m.name, "top"] => t.top ← m;
Rope.Equal[m.name, "bottom"] => t.bottom ← m;
Rope.Equal[m.name, "left"] => t.left ← m;
Rope.Equal[m.name, "right"] => t.right ← m;
Rope.Equal[m.name, "ul"] => t.ul ← m;
Rope.Equal[m.name, "ur"] => t.ur ← m;
Rope.Equal[m.name, "ll"] => t.ll ← m;
Rope.Equal[m.name, "lr"] => t.lr ← m;
ENDCASE => t.markList ← CONS[m, t.markList];
END;
-- create default marks for a tile
DefaultMarks: PUBLIC PROC [t: Tile, m: Mod ← NIL] = BEGIN
left, bottom: INT ← 0;
right: INT ← t.obj.size.x;
top: INT ← t.obj.size.y;
IF m # NIL THEN {
-- get marks from module
IF m.ul # NIL AND t.ul = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "ul", pos: m.ul^]]];
IF m.ur # NIL AND t.ur = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "ur", pos: m.ur^]]];
IF m.ll # NIL AND t.ll = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "ll", pos: m.ll^]]];
IF m.lr # NIL AND t.lr = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "lr", pos: m.lr^]]];
IF m.top # NIL AND t.top = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "top", pos: m.top^]]];
IF m.bottom # NIL AND t.bottom = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "bottom", pos: m.bottom^]]];
IF m.left # NIL AND t.left = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "left", pos: m.left^]]];
IF m.right # NIL AND t.right = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "right", pos: m.right^]]];
};
-- fabricate default box
IF t.top # NIL THEN top ← t.top.pos.y;
IF t.bottom # NIL THEN bottom ← t.bottom.pos.y;
IF t.left # NIL THEN left ← t.left.pos.x;
IF t.right # NIL THEN right ← t.right.pos.x;
IF t.ul # NIL THEN {left ← MIN[t.ul.pos.x, left]; top ← MAX[t.ul.pos.y, top]};
IF t.ur # NIL THEN {right ← MAX[t.ur.pos.x, right]; top ← MAX[t.ur.pos.y, top]};
IF t.ll # NIL THEN {left ← MIN[t.ur.pos.x, left]; bottom ← MIN[t.ur.pos.y, bottom]};
IF t.lr # NIL THEN {right ← MAX[t.ur.pos.x, right]; bottom ← MIN[t.ur.pos.y, bottom]};
-- fill in defaults
IF t.top = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "top", pos: [(left+right)/2, top]]]];
IF t.bottom = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "bottom", pos: [(left+right)/2, bottom]]]];
IF t.left = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "left", pos: [left, (top+bottom)/2]]]];
IF t.right = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "right", pos: [right, (top+bottom)/2]]]];
IF t.ul = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "ul", pos: [left, top]]]];
IF t.ur = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "ur", pos: [right, top]]]];
IF t.ll = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "ll", pos: [left, bottom]]]];
IF t.lr = NIL THEN StoreMark[t, NEW[MarkRec ← [name: "lr", pos: [right, bottom]]]];
END;
-- retrieve a mark given it's name
GetMark: PUBLIC PROC [fromTile: Tile, markName: Rope.ROPE] RETURNS [Mark] = BEGIN
SELECT TRUE FROM
Rope.Equal[markName, "top"] => RETURN[fromTile.top];
Rope.Equal[markName, "bottom"] => RETURN[fromTile.bottom];
Rope.Equal[markName, "left"] => RETURN[fromTile.left];
Rope.Equal[markName, "right"] => RETURN[fromTile.right];
Rope.Equal[markName, "ul"] => RETURN[fromTile.ul];
Rope.Equal[markName, "ur"] => RETURN[fromTile.ur];
Rope.Equal[markName, "ll"] => RETURN[fromTile.ll];
Rope.Equal[markName, "lr"] => RETURN[fromTile.lr];
ENDCASE => {
FOR marks: MarkList ← fromTile.markList, marks.rest WHILE marks#NIL DO
IF Rope.Equal[markName, marks.first.name] THEN RETURN[marks.first];
ENDLOOP;
};
RETURN[NIL];
END;
-- Procedure to rotate & mirror standard marks by exchanging them with each other.
OrientStdMark: PUBLIC PROC [cell: Tile, orient: Orientation] RETURNS [left, right, top, bottom, ul, ur, ll, lr: Mark] = BEGIN
M2: TYPE = RECORD[a, b: Mark];
M4: TYPE = RECORD[a, b, c, d: Mark];
swapX, swapY, rotate: BOOLFALSE;
IF CDOrient.IncludesOddRot90[orient] THEN rotate ← ~rotate;
IF CDOrient.IncludesMirrorX[orient] THEN swapX ← ~swapX;
IF CDOrient.ConcentrateOnRotate90[orient] = CDOrient.rotate180 OR CDOrient.ConcentrateOnRotate90[orient] = CDOrient.rotate270 THEN
BEGIN swapX ← ~swapX; swapY ← ~swapY END;
left ← cell.left;
right ← cell.right;
top ← cell.top;
bottom ← cell.bottom;
ul ← cell.ul;
ur ← cell.ur;
ll ← cell.ll;
lr ← cell.lr;
IF rotate THEN {
[bottom, left, top, right] ← M4[right, bottom, left, top];
[lr, ll, ul, ur] ← M4[ur, lr, ll, ul];
};
IF swapX THEN {
[right, left] ← M2[left, right];
[ur, ul] ← M2[ul, ur];
[lr, ll] ← M2[ll, lr];
};
IF swapY THEN {
[bottom, top] ← M2[top, bottom];
[ll, ul] ← M2[ul, ll];
[lr, ur] ← M2[ur, lr];
};
END;
PlacedMarkLoc: PUBLIC PROC [oldTile: PlacedTile, oldMark: Mark] RETURNS [Position]= BEGIN
IF oldMark.owner # LOOPHOLE[oldTile.tile, INT] THEN ERROR Error[MarkNotInTile];
RETURN[CDBasics.AddPoints[oldTile.pos, MapPoint[oldMark.pos, oldTile.tile.obj.size, oldTile.orient]]];
END;
-- Update the default marks now that a new tile has been placed
SetModDefaults: PUBLIC PROC [m: Mod, pc: PlacedTile] = BEGIN
l, r, t, b, ul, ur, ll, lr: Mark;
[l, r, t, b, ul, ur, ll, lr] ← OrientStdMark[pc.tile, pc.orient];
-- mark top
IF t # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, t];
IF m.top = NIL THEN
m.top ← NEW[CD.Position ← tPos]
ELSE IF tPos.y > m.top.y OR (tPos.y = m.top.y AND tPos.x < m.top.x) THEN
m.top^ ← tPos;
};
-- mark bottom
IF b # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, b];
IF m.bottom = NIL THEN
m.bottom ← NEW[CD.Position ← tPos]
ELSE IF tPos.y < m.bottom.y OR (tPos.y = m.bottom.y AND tPos.x < m.bottom.x) THEN
m.bottom^ ← tPos;
};
-- mark right
IF r # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, r];
IF m.right = NIL THEN
m.right ← NEW[CD.Position ← tPos]
ELSE IF tPos.x > m.right.x OR (tPos.x = m.right.x AND tPos.y < m.right.y) THEN
m.right^ ← tPos;
};
-- mark left
IF l # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, l];
IF m.left = NIL THEN
m.left ← NEW[CD.Position ← tPos]
ELSE IF tPos.x < m.left.x OR (tPos.x = m.left.x AND tPos.y < m.left.y) THEN
m.left^ ← tPos;
};
-- mark ul
IF ul # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, ul];
IF m.ul = NIL THEN
m.ul ← NEW[CD.Position ← tPos]
ELSE IF -tPos.x + tPos.y > -m.ul.x + m.ul.y OR (-tPos.x + tPos.y = -m.ul.x + m.ul.y AND tPos.x < m.ul.x) THEN
m.ul^ ← tPos;
};
-- mark ur
IF ur # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, ur];
IF m.ur = NIL THEN
m.ur ← NEW[CD.Position ← tPos]
ELSE IF tPos.x + tPos.y > m.ur.x + m.ur.y OR (tPos.x + tPos.y = m.ur.x + m.ur.y AND tPos.x > m.ur.x) THEN
m.ur^ ← tPos;
};
-- mark ll
IF ll # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, ll];
IF m.ll = NIL THEN
m.ll ← NEW[CD.Position ← tPos]
ELSE IF tPos.x + tPos.y < m.ll.x + m.ll.y OR (tPos.x + tPos.y = m.ll.x + m.ll.y AND tPos.x < m.ll.x) THEN
m.ll^ ← tPos;
};
-- mark lr
IF lr # NIL THEN {
tPos: CD.Position ← PlacedMarkLoc[pc, lr];
IF m.lr = NIL THEN
m.lr ← NEW[CD.Position ← tPos]
ELSE IF tPos.x - tPos.y > m.lr.x - m.lr.y OR (tPos.x - tPos.y = m.lr.x - m.lr.y AND tPos.x > m.lr.x) THEN
m.lr^ ← tPos;
};
END;
END.