<> <> <> <> <<-- 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: BOOL _ FALSE; 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.