--routeRectangle.mesa
DIRECTORY RouteDefs;
RouteRectangle:PROGRAM IMPORTS RouteDefs EXPORTS RouteDefs=BEGIN
OPEN RouteDefs;
--SAMPLE EXAMPLE
Error:SIGNAL=CODE;
Rect:TYPE=RECORD[x,y,x1,y1:INTEGER];
nextChannelNo:ChannelNo←0;
CreateRectangles:PUBLIC CtlProc=BEGIN
rectangles←NIL;
nextChannelNo←1;
ShowLabel["RECTANGLES"];
CreateBareChannelsAndInters[];
SubdivideIfNeeded[];
EnumerateRectangles[AddEventsToRectangles];
--EnumerateRectangles[CheckRectangles];
RETURN[-1];
END;
CreateBareChannelsAndInters:PROCEDURE=BEGIN
FOR y:Lambda←0, NextYEvent[y] UNTIL y>=problem.chipSize.y DO
FOR x:Lambda←NextXEvent[0,y], NextXEvent[x,y] UNTIL x>=problem.chipSize.x
DO DealWithPoint[x,y]; ENDLOOP;
ENDLOOP;
END;
--an "event" is the edge of a cell
NextYEvent:PROCEDURE[above:Lambda] RETURNS[next:Lambda]=BEGIN
next←bigLambda;
FOR cl:CellListPtr←problem.cells,cl.t UNTIL cl=NIL DO
y:Lambda←cl.h.pos.y; IF y>above THEN next←MIN[next,y];
y←y+cl.h.sizeL.y; IF y>above THEN next←MIN[next,y];
ENDLOOP;
END;
--NextYEvent:PROCEDURE[above:Lambda] RETURNS[next:Lambda]=BEGIN
--Sub:PROCEDURE[c:CellPtr]=
-- {y:Lambda←c.pos.y;
-- IF above>=y THEN y←y+c.sizeL.y; IF y>above THEN next←MIN[next,y]};
--next←bigLambda;
--EnumerateCells[Sub];
--END;
NextXEvent:PROCEDURE[atX,atY:Lambda] RETURNS[this:Lambda]=BEGIN
kind:RectKind←cell;
next:Lambda←atX;
UNTIL kind=none DO this←next; [next,kind]←NextXEdge[next,atY]; ENDLOOP;
END;
DealWithPoint:PROCEDURE[x,y:Lambda]=BEGIN
--the lower left corner of an as yet empty region
ClipStrange:PROCEDURE[cell:CellPtr]=BEGIN
r1:Rect←[cell.pos.x,cell.pos.y,
cell.pos.x+cell.sizeL.x,cell.pos.y+cell.sizeL.y];
IF ~Overlap[@r0,@r1] THEN RETURN;
IF r1.x NOT IN [r0.x..r0.x1) AND r1.y IN [r0.y..r0.y1)
THEN Error;
r0.x1←x3←r1.x; r0.y1←y3←r1.y;
END;
maxX:INTEGER←32000;
kind,topKind,rightKind:RectKind;
x1,y1,x2,y2,x3,y3:Lambda;
r0:Rect;
leftWhite,bottomWhite,topWhite,rightWhite:BOOLEAN←FALSE;
Return[];
ShowPoint["empty point = ",x,y];
[x1,bottomWhite,kind]←FarXExtension[x,y];
IF kind#none THEN Error;
[y1,leftWhite,kind]←FarYExtension[y,x];
IF kind#none THEN Error;
[x2,,topKind]←FarXExtension[x,y1];
[y2,,rightKind]←FarYExtension[y,x1];
x3←MIN[x1,x2];
y3←MIN[y1,y2];
r0←[x,y,x3,y3];
EnumerateCells[ClipStrange];
topWhite←topKind#cell;
rightWhite←rightKind#cell;
NewRect[[x,y],[x3-x,y3-y],NIL];
END;
FarXExtension:PROCEDURE[x,y:Lambda]
RETURNS[x3:Lambda,belowWhite:BOOLEAN,kind:RectKind]=BEGIN
x1,x2:Lambda←problem.chipSize.x;
belowWhite←FALSE;
IF y#0 THEN BEGIN
temp:Lambda;
[temp,kind]←NextXEdge[x,y-1];
belowWhite←kind#cell;
x1←temp;
UNTIL kind#cell DO [temp,kind]←NextXEdge[x1←temp,y-1]; ENDLOOP;
END;
[x2,kind]←NextXEdge[x,y];
x3←MIN[x1,x2];
END;
FarYExtension:PROCEDURE[x,y:Lambda] --call with [y,x] !!!
RETURNS[x3:Lambda,belowWhite:BOOLEAN,kind:RectKind]=BEGIN
x1,x2:Lambda←problem.chipSize.y;
belowWhite←FALSE;
IF y#0 THEN BEGIN
temp:Lambda;
[temp,kind]←NextYEdge[x,y-1];
belowWhite←kind#cell;
x1←temp;
UNTIL kind#cell DO [temp,kind]←NextYEdge[x1←temp,y-1]; ENDLOOP;
END;
[x2,kind]←NextYEdge[x,y];
x3←MIN[x1,x2];
END;
NextXEdge:PROCEDURE[atX,atY:Lambda] RETURNS[INTEGER,RectKind]=BEGIN
--IF [atX,atY] is in a rectangle,
-- THEN return [rightEdge+1,kind] ELSE return [firstEdge to right, none]
best:Lambda←bigLambda;
FOR cl:CellListPtr←problem.cells,cl.t UNTIL cl=NIL DO
p:CoordL←cl.h.pos; s:CoordL←cl.h.sizeL;
IF atY-p.y IN [0..s.y) THEN SELECT atX-p.x FROM
<0=>best←MIN[best,p.x]; <s.x=>RETURN[p.x+s.x,cell];
ENDCASE;
ENDLOOP;
FOR cl:RectangleListPtr←rectangles,cl.t UNTIL cl=NIL DO
rect:RectanglePtr=cl.h;
p:CoordL←rect.pos; s:CoordL←rect.sizeL;
IF atY-p.y IN [0..s.y) THEN SELECT atX-p.x FROM
<0=>best←MIN[best,p.x]; <s.x=>RETURN[p.x+s.x,inter];
ENDCASE;
ENDLOOP;
RETURN[best,none];
END;
NextYEdge:PROCEDURE[atX,atY:Lambda] RETURNS[INTEGER,RectKind]=BEGIN
--called with [y,x]
best:Lambda←bigLambda;
FOR cl:CellListPtr←problem.cells,cl.t UNTIL cl=NIL DO
p:CoordL←cl.h.pos; s:CoordL←cl.h.sizeL;
IF atY-p.x IN [0..s.x) THEN SELECT atX-p.y FROM
<0=>best←MIN[best,p.y]; <s.y=>RETURN[p.y+s.y,cell]; ENDCASE;
ENDLOOP;
FOR cl:RectangleListPtr←rectangles,cl.t UNTIL cl=NIL DO
rect:RectanglePtr=cl.h;
p:CoordL←rect.pos; s:CoordL←rect.sizeL;
IF atY-p.x IN [0..s.x) THEN SELECT atX-p.y FROM
<0=>best←MIN[best,p.y]; <s.y=>RETURN[p.y+s.y,inter];
ENDCASE;
ENDLOOP;
RETURN[best,none];
END;
Overlap:PROCEDURE[a,b:POINTER TO Rect] RETURNS[BOOLEAN]=BEGIN
RETURN[ a.x<b.x1 AND b.x<a.x1 AND a.y<b.y1 AND b.y<a.y1];
END;
SubdivideIfNeeded:PROCEDURE=BEGIN
DO
progress:BOOLEAN←FALSE;
FOR rl:RectangleListPtr←rectangles,rl.t UNTIL rl=NIL DO
rect:RectanglePtr=rl.h;
top:Lambda=rect.pos.y+rect.sizeL.y;
xs:Lambda=rect.pos.x;
xe:Lambda←xs+rect.sizeL.x;
FOR r2:RectangleListPtr←rectangles,r2.t UNTIL r2=NIL DO
rect2:RectanglePtr←r2.h;
xs2:Lambda=rect2.pos.x;
xe2:Lambda=xs2+rect2.sizeL.x;
split:Lambda;
IF top#rect2.pos.y THEN LOOP;
SELECT TRUE FROM
xe2 IN (xs..xe)=>split←xe2;
xs2 IN (xs..xe)=>split←xs2;
ENDCASE=>LOOP;
BEGIN
dx:Lambda←xe-split;
pos:CoordL=[split,rect.pos.y];
sizeL:CoordL=[dx,rect.sizeL.y];
NewRect[pos,sizeL,rl];
rect.sizeL.x←rect.sizeL.x-dx;
xe←split;
progress←TRUE;
END;
ENDLOOP;
ENDLOOP;
IF progress THEN LOOP;
FOR rl:RectangleListPtr←rectangles,rl.t UNTIL rl=NIL DO
rect:RectanglePtr=rl.h;
top:Lambda=rect.pos.x+rect.sizeL.x;
ys:Lambda=rect.pos.y;
ye:Lambda←ys+rect.sizeL.y;
FOR r2:RectangleListPtr←rectangles,r2.t UNTIL r2=NIL DO
rect2:RectanglePtr←r2.h;
ys2:Lambda=rect2.pos.y;
ye2:Lambda=ys2+rect2.sizeL.y;
split:Lambda;
IF top#rect2.pos.x THEN LOOP;
SELECT TRUE FROM
ye2 IN (ys..ye)=>split←ye2;
ys2 IN (ys..ye)=>split←ys2;
ENDCASE=>LOOP;
BEGIN
dy:Lambda←ye-split;
pos:CoordL=[rect.pos.x,split];
sizeL:CoordL=[rect.sizeL.x,dy];
NewRect[pos,sizeL,rl];
rect.sizeL.y←rect.sizeL.y-dy;
ye←split;
progress←TRUE;
END;
ENDLOOP;
ENDLOOP;
IF ~progress THEN EXIT;
ENDLOOP;
END;
NewRect:PROCEDURE[pos,size:CoordL,base:RectangleListPtr]=BEGIN
list:RectangleListPtr←AllocateList[];
rect:RectanglePtr←AllocateRectangle[];
rect.channelNo←nextChannelNo;
nextChannelNo←nextChannelNo+1;
rect.pos←pos;
rect.sizeL←size;
IF base=NIL THEN {list↑←[rect,rectangles]; rectangles←list}
ELSE {list↑←[rect,base.t]; base.t←list};
END;
AddEventsToRectangles:PROCEDURE[rect:RectanglePtr]=BEGIN
k:Side;
EwWall:PROCEDURE[cell:CellPtr,s:SignalPtr]=BEGIN
l:Side=IF k=e THEN w ELSE e;
off:Lambda=s.offset+cell.pos.y-rect.pos.y;
IF s.side=k AND off IN [0..rect.sizeL.y)
THEN BEGIN
AddEvent[rect,[,s.circuit,IF k=w THEN bottom ELSE top,l,s.level,off,s.net]];
IF k=w THEN rect.eSource←TRUE ELSE rect.wSource←TRUE;
END; END;
NsWall:PROCEDURE[cell:CellPtr,s:SignalPtr]=BEGIN
l:Side=IF k=s THEN n ELSE s;
off:Lambda=s.offset+cell.pos.x-rect.pos.x;
IF s.side=k AND off IN [0..rect.sizeL.x)
THEN BEGIN
AddEvent[rect,[,s.circuit,IF k=n THEN bottom ELSE top,l,s.level,off,s.net]];
IF k=s THEN rect.nSource←TRUE ELSE rect.sSource←TRUE;
END; END;
Sub:PROCEDURE[cell:CellPtr]=BEGIN
SELECT TRUE FROM
cell.pos.x=rect.pos.x+rect.sizeL.x=>{k←w; EnumerateSignals[cell,EwWall]};
cell.pos.x+cell.sizeL.x=rect.pos.x=>{k←e; EnumerateSignals[cell,EwWall]};
cell.pos.y=rect.pos.y+rect.sizeL.y=>{k←s; EnumerateSignals[cell,NsWall]};
cell.pos.y+cell.sizeL.y=rect.pos.y=>{k←n; EnumerateSignals[cell,NsWall]};
ENDCASE;
END;
IF rect.events#NIL THEN Error;
EnumerateCells[Sub];
END;
AddEvent:PROCEDURE[chan:RectanglePtr,e:Event]=BEGIN
ep:EventPtr←AllocateEvent[];
list:EventListPtr←AllocateList[];
ep↑←e;
list↑←[ep,chan.events];
chan.events←list;
END;
END.