StretchCMosB.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Don Curry May 31, 1989 11:03:35 pm PDT
DIRECTORY
CDInstances, CDBasics, CDTexts, CDAtomicObjects, CD, CDCells, CDCommandOps, CDDirectory, CDOps, CDRects, CDSequencer, IO, Rope, TerminalIO;
StretchCMosB: CEDAR PROGRAM
IMPORTS CDInstances, CDBasics, CDTexts, CDAtomicObjects, CD, CDCells, CDCommandOps, CDDirectory, CDOps, CDRects, Rope, TerminalIO =
BEGIN
MenuHeader:   Rope.ROPE ← "Layers to be stretched";
AllLayersItem:  Rope.ROPE ← "All Layers";
CondLayersItem:  Rope.ROPE ← "Conductive Layers Only";
RoutLayersItem:  Rope.ROPE ← "Routing Layers Only";
MenuSelections: LIST OF Rope.ROPELIST[AllLayersItem, CondLayersItem, RoutLayersItem];
LayerKeyFilter: TYPE = PROC[key: ATOM] RETURNS[ok: BOOL];
AllLayers:  LayerKeyFilter = {RETURN[TRUE]};
RouteLayers: LayerKeyFilter = {RETURN[
SELECT key FROM
$pol,
$met,    $met2   => TRUE,
ENDCASE       => FALSE ]};
CondLayers: LayerKeyFilter = {RETURN[
SELECT key FROM
$pol,
$met,    $met2,
$ndif,    $pdif,
$nwel,   $pwel,
$nwelCont,  $pwelCont => TRUE
ENDCASE       => FALSE]};
ExpliciteLayers: LayerKeyFilter = {RETURN[
SELECT key FROM
$comment,
$pol,
$met,    $met2,
$ndif,    $pdif,
$wndif,   $wpdif,
$nwel,   $pwel,
$nwelCont,  $pwelCont,
$cut,    $cut2,
$wNWellCont, $wPWellCont,
$ovg,    $imp,
$bur,    $bond  => TRUE,
ENDCASE      => FALSE ]};
StretchProc: PROC [comm: CDSequencer.Command] = {
design: CD.Design ← comm.design;
pos:  CD.Position ← comm.pos;
new:  CD.Object;
inst:  CD.Instance ← CDOps.TheInstance[design];
filter:  LayerKeyFilter;
width:  INT;
TerminalIO.PutRope["Stretch Selected CMosB Object \n"];
IF inst=NIL THEN
{TerminalIO.PutRope["Must select exactly one object for stretching \n"]; RETURN};
filter  ← SELECT TerminalIO.RequestSelection[MenuHeader, MenuSelections] FROM
1   => AllLayers,
2   => CondLayers,
3   => RouteLayers,
ENDCASE => NIL;
IF filter=NIL THEN {TerminalIO.PutRope["Stretch Command Aborted \n"]; RETURN};
width  ← TerminalIO.RequestInt["Stretch Size (Lambda): "];
new  ← GetStretchedObj[inst.ob, design, width*design.technology.lambda, filter];
[]   ← CDOps.PlaceInst[design, new, comm]};
GetStretchedObj: PROC
[ref: CD.Object, design: CD.Design, width: INT, layerKeyFilter: LayerKeyFilter ← AllLayers]
RETURNS[new: CD.Object ← NIL] = {
name:  IO.ROPE   ← CDDirectory.Name[ref, design];
left:  CD.InstanceList ← NIL;
right:  CD.InstanceList ← NIL;
btm:  CD.InstanceList ← NIL;
top:  CD.InstanceList ← NIL;
insts:  CD.InstanceList ← NIL;
irr:  CD.Rect  ← CD.InterestRect[ref];
irrSz:  CD.Position ← CD.InterestSize[ref];
rectProc: EachItemProc = {
IF CDRects.IsBareRect[obj] THEN {
Add: PROC[list: CD.InstanceList, iPos, iSize: CD.Position]
RETURNS[newLst: CD.InstanceList] = {
rectObj: CD.Object ← CDRects.CreateRect[iSize, obj.layer];
newLst ← CONS [CDInstances.NewInst[ob: rectObj, trans: [iPos]], list]};
key: ATOMCD.LayerKey[obj.layer];
IF layerKeyFilter[key] THEN {
ir:   CD.Rect  ← CDBasics.MapRect[CD.InterestRect[obj], trans];
size:  CD.Position;
ir   ← CDBasics.Intersection[ir, irr];
size  ← CDBasics.SizeOfRect[ir];
IF size#[0,0] THEN {
IF ir.x1=irr.x1  THEN left ← Add[left, [0, ir.y1-irr.y1], [width, size.y]];
IF ir.x2=irr.x2  THEN right ← Add[right, [0, ir.y1-irr.y1], [width, size.y]];
IF ir.y1=irr.y1 THEN btm ← Add[btm, [ir.x1-irr.x1, 0], [size.x, width]];
IF ir.y2=irr.y2 THEN top  ← Add[top, [ir.x1-irr.x1, 0], [size.x, width]] }}} };
AddSide: PROC[list: CD.InstanceList, sSz, sPos: CD.Position] = {
sideObj: CD.Object ← CDCells.CreateCell[il: list, ir: [0, 0, sSz.x, sSz.y]];
CDCells.ToSequenceMode[sideObj];
insts ← CONS [CDInstances.NewInst[ob: sideObj, trans: [sPos]], insts] };
EnumerateObject[ref, rectProc];
AddSide[left,  [width, irrSz.y], [0, width]];
AddSide[right, [width, irrSz.y], [irrSz.x+width, width]];
AddSide[top,  [irrSz.x, width], [width, irrSz.y+width]];
AddSide[btm, [irrSz.x, width], [width, 0]];
insts ← CONS [CDInstances.NewInst[ob: ref, trans: [[width-irr.x1, width-irr.y1]]], insts] ;
new ← CDCells.CreateCell[il: insts, ir: [0, 0, irrSz.x+2*width, irrSz.y+2*width]];
CDCells.ToSequenceMode[new];
IF name.Length[]#0 THEN []�irectory.Include[design, new, name.Cat["X"]]};
EachItemProc: TYPE = PROC[obj: CD.Object, trans: CD.Transformation];
EnumerateObject: PROC[obj: CD.Object, eachItem: EachItemProc, trans: CD.Transformation ← []] ={
IF obj=NIL THEN RETURN;
SELECT TRUE FROM
CDRects.IsBareRect[obj] => {eachItem[obj, trans]};
CDCells.IsCell[obj]  => {
doInst: PROC[inst: CD.Instance] RETURNS[quit: BOOLFALSE] = {
EnumerateObject[inst.ob, eachItem, CDBasics.ComposeTransform[inst.trans, trans]]};
[] ← CDCells.EnumerateInstances[obj, doInst]};
CDTexts.IsText[obj]     => {}; -- throw away
CDAtomicObjects.IsAtomicOb[obj] => {
geom: CDAtomicObjects.DrawList ←
NARROW[obj.specific, CDAtomicObjects.AtomicObsSpecific].rList;
FOR geom ← geom, geom.rest WHILE geom # NIL DO
size: CD.Position   ← CDBasics.SizeOfRect[geom.first.r];
pos: CD.Position   ← CDBasics.BaseOfRect[geom.first.r];
rect: CD.Object    ← CDRects.CreateRect[size, geom.first.layer];
xfrm: CD.Transformation ← CDBasics.ComposeTransform[[pos], trans];
eachItem[rect, xfrm];
ENDLOOP};
ENDCASE => {
obj ← CDDirectory.Expand1[obj, NIL, NIL].new;
EnumerateObject[obj, eachItem, trans]}};
CDCommandOps.RegisterWithMenu[$SpecialMenu,
"Stretch CMosB Object", "Adds tabs on all sides of a cell", NIL, StretchProc, dontQueue];
END.