<> <> <> <> <> DIRECTORY Atom, CD, CDBasics, CornerBasedDRC, CStitching, Rope; CornerBasedDRCImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CStitching EXPORTS CornerBasedDRC = BEGIN OPEN CornerBasedDRC; Quadrants: TYPE = {ne, nw, sw, se}; DefaultError: ErrorProc = { }; DefaultCompatibleNodes: CompatibleNodesProc = { RETURN [FALSE]; }; neverInTesselation: REF ATOM _ NEW[ATOM_$neverInTesselation]; stopped: ERROR = CODE; Check: PUBLIC PROC [task: REF DrcTask, area: CD.Rect] = { IF task.geometry.stopFlag=NIL THEN task.geometry.stopFlag_NEW[BOOL_FALSE]; IF task.compatibleNodes=NIL THEN task.compatibleNodes _ DefaultCompatibleNodes; IF task.error=NIL THEN task.error _ DefaultError; [] _ CStitching.EnumerateArea[plane: task.geometry, rect: area, eachTile: CheckOneTile, skip: neverInTesselation, data: task ! stopped => GOTO hasStopped]; EXITS hasStopped => NULL; }; CompatibleNodes: PROC [task: REF DrcTask, rule: Rule, corner: REF, pos: CD.Position, other: REF, r: CD.Rect _ CDBasics.empty] RETURNS [BOOL] = INLINE { RETURN [ corner=other OR task.compatibleNodes[task, rule, corner, pos, other, r] ] }; CheckOneTile: CStitching.TileProc = { task: REF DrcTask = NARROW[data]; r: CD.Rect = CStitching.Area[tile]; CheckCorner: PROC [quadVals: ARRAY Quadrants OF REF ANY, pos: CD.Position] = { CheckArea: PROC [rule: Rule, orient: CD.Orientation, flavour: { convex, concave}] = { CheckTileValue: CStitching.TileProc = { CheckValue[tile.value, CStitching.Area[tile]] }; CheckValue: PROC [value: REF ANY, area: CD.Rect] = { IF value=NIL THEN { IF ~rule.isError[spaceConstraintIndex] THEN RETURN; } ELSE WITH value SELECT FROM cc: Constraint => { IF ~rule.isError[cc.index] THEN RETURN; IF rule.okIfConnected AND nodeOrConstraintAtCorner#NIL AND CompatibleNodes[task, rule, nodeOrConstraintAtCorner, pos, cc, area] THEN RETURN; }; ENDCASE => { IF ~rule.isError[nodeConstraintIndex] THEN RETURN; IF rule.okIfConnected AND nodeOrConstraintAtCorner#NIL AND CompatibleNodes[task, rule, nodeOrConstraintAtCorner, pos, value] THEN RETURN; }; <<-- Check if it really is an error.>> IF ~notReportedYet THEN RETURN; IF task.restrict#NIL THEN { IF ~CStitching.IsEmpty[ plane: task.restrict, rect: CDBasics.MapRect[itemInCell: [x1: -delta, y1: -delta, x2: len, y2: len], cellInWorld: [pos, orient]], skip: task.skipThese ] THEN RETURN; }; task.error[ task: task, rule: rule, r: CDBasics.MapRect[itemInCell: [x1: 0, y1: 0, x2: rule.extent, y2: rule.extent], cellInWorld: [pos, orient]] ]; notReportedYet _ FALSE }; -- CheckValue <<--CheckArea>> notReportedYet: BOOL _ TRUE; len: INT = rule.extent; delta: INT = 1; IF len = 0 THEN { <<-- Optimize purely local checks.>> IF notReportedYet THEN CheckValue[quadVals[ne], [pos.x, pos.y, pos.x+delta, pos.y+delta]]; IF notReportedYet THEN CheckValue[quadVals[nw], [pos.x, pos.y-delta, pos.x+delta, pos.y]]; IF notReportedYet THEN CheckValue[quadVals[sw], [pos.x-delta, pos.y-delta, pos.x, pos.y]]; IF notReportedYet THEN CheckValue[quadVals[se], [pos.x-delta, pos.y, pos.x, pos.y+delta]]; } ELSE { SELECT flavour FROM convex => { [] _ CStitching.EnumerateArea[ plane: task.geometry, rect: CDBasics.MapRect[itemInCell: [x1: -delta, y1: 0, x2: len, y2: len], cellInWorld: [pos, orient]], eachTile: CheckTileValue, skip: neverInTesselation ]; [] _ CStitching.EnumerateArea[ plane: task.geometry, rect: CDBasics.MapRect[itemInCell: [x1: 0, y1: -delta, x2: len, y2: 0], cellInWorld: [pos, orient]], eachTile: CheckTileValue, skip: neverInTesselation ]; }; concave => { [] _ CStitching.EnumerateArea[ plane: task.geometry, rect: CDBasics.MapRect[itemInCell: [x1: 0, y1: 0, x2: len, y2: len], cellInWorld: [pos, orient]], eachTile: CheckTileValue, skip: neverInTesselation ]; }; ENDCASE } }; -- CheckArea <<-- CheckCorner>> nodeOrConstraintAtCorner: REF _ NIL; FOR rL: Rules _ task.rules, rL.rest WHILE rL#NIL DO rule: Rule = rL.first; bitIndex: ARRAY Quadrants OF INTEGER = [8, 4, 2, 1]; quadBits: INTEGER _ 0; nodeOrConstraintAtCorner _ NIL; <<-- Translate the quadrant contents into bit vector values.>> FOR q: Quadrants IN Quadrants DO IF quadVals[q]=NIL THEN { IF rule.isStuff[spaceConstraintIndex] THEN quadBits _ quadBits + bitIndex[q] } ELSE WITH quadVals[q] SELECT FROM cc: Constraint => { IF rule.isStuff[cc.index] THEN { quadBits _ quadBits + bitIndex[q]; IF nodeOrConstraintAtCorner=NIL THEN nodeOrConstraintAtCorner _ cc } }; ENDCASE => { IF rule.isStuff[nodeConstraintIndex] THEN { quadBits _ quadBits + bitIndex[q]; nodeOrConstraintAtCorner _ quadVals[q]; }; }; ENDLOOP; <<-- Is this really a corner in the terms of this rule?>> <<-- Bits are ne=8, nw=4, sw=2, se=1. >> <<-- The check is applied to the quad opposite the generating corner. (IE rot. 180)>> <<-- X=TRUE, O=FALSE 0 - OO 1 - OO 2 - OO 3 - OO OO OX XO XX 4 - XO 5 - XO 6 - XO 7 - XO OO OX XO XX 8 - OX 9 - OX 10- OX 11- OX OO OX XO XX 12- XX 13- XX 14- XX 15- XX OO OX XO XX>> SELECT quadBits FROM 0 => NULL; 1 => CheckArea[rule, rotate90, convex]; 2 => CheckArea[rule, original, convex]; 3 => NULL; 4 => CheckArea[rule, rotate270, convex]; 5 => {CheckArea[rule, rotate90, convex]; CheckArea[rule, rotate270, convex]}; 6 => NULL; 7 => CheckArea[rule, original, concave]; 8 => CheckArea[rule, rotate180, convex]; 9 => NULL; 10 => {CheckArea[rule, original, convex]; CheckArea[rule, rotate180, convex]}; 11 => CheckArea[rule, rotate90, concave]; 12 => NULL; 13 => CheckArea[rule, rotate180, concave]; 14 => CheckArea[rule, rotate270, concave]; 15 => NULL; ENDCASE => ERROR; ENDLOOP; }; -- CheckCorner <<-- SW corner>> IF task.geometry.stopFlag^ THEN ERROR stopped; IF task.restrict=NIL OR CStitching.FindTile[task.restrict, [x: r.x1, y: r.y1]].value#task.skipThese THEN { IF tile.SW.SEdge[] = r.y1 THEN { IF tile.WS.WEdge[]#r.x1 THEN { IF tile.value=tile.SW.value THEN CD.Error[ec: other, explanation: "tile violates horz rule"]; <<-- Get the quadrants at the SW corner>> CheckCorner[[ne: tile.value, nw: tile.SW.value, sw: tile.WS.value, se: tile.WS.value], [r.x1, r.y1]]; } <<-- ELSE NULL; a (probably rare) 4 way corner; handled at the NE corner.>> } ELSE { -- CStitching.WEdge[CStitching.WS[tile]] = r.x1 IMPLICITLY IF tile.value=tile.WS.value THEN { <<-- Get the quadrants at the SW corner>> CheckCorner[[ne: tile.value, nw: tile.SW.value, sw: tile.SW.value, se: tile.WS.value], [r.x1, r.y1]]; } <<-- ELSE NULL; No corner really>> } }; <<-- NE corner>> IF task.restrict=NIL OR CStitching.FindTile[task.restrict, [x: r.x2, y: r.y2]].value#task.skipThese THEN { IF tile.NE.NEdge[]=r.y2 THEN { IF tile.EN.EEdge[]=r.x2 THEN { <<-- 4 way corner>> neQTile: CStitching.Tile _ tile.EN.NE; WHILE neQTile.SEdge > r.y2 DO neQTile _ neQTile.WS[] ENDLOOP; CheckCorner[[ne: neQTile.value, nw: tile.EN.value, sw: tile.value, se: tile.NE.value], [r.x2, r.y2]]; } ELSE { IF tile.value = tile.NE.value THEN CD.Error[ec: other, explanation: "tile violates max horz rule NEast"]; <<-- Get the quadrants at the NE corner>> CheckCorner[[ne: tile.EN.value, nw: tile.EN.value, sw: tile.value, se: tile.NE.value], [r.x2, r.y2]]; } } ELSE { -- tile.EN.EEdge = r.x2 IMPLICITLY IF tile.value#tile.EN.value THEN { <<-- NE corner>> CheckCorner[[ne: tile.NE.value, nw: tile.EN.value, sw: tile.value, se: tile.NE.value], [r.x2, r.y2]]; } <<--ELSE NULL; No corner really>> } } }; --CheckOneTile END.