/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Geometry.java
* Input/output tool: superclass for output modules that write pure geometry.
* Written by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2003 Sun Microsystems and Static Free Software
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.io.output;
import com.sun.electric.database.geometry.GeometryHandler;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.geometry.PolyBase;
import com.sun.electric.database.geometry.GeometryHandler.GHMode;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.HierarchyEnumerator;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.id.CellUsage;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Base class for writing geometry to a file
*/
public abstract class Geometry extends Output
{
/** number of unique cells processed */ protected int numVisited;
/** number of unique cells to process */ protected int numCells;
/** top-level cell being processed */ protected Cell topCell;
/** HashMap of all CellGeoms */ protected HashMap<Cell,CellGeom> cellGeoms;
/**
* Class for managing polygons that are associated with geometry.
*/
protected static class PolyWithGeom
{
Poly poly;
Geometric geom;
PolyWithGeom(Poly poly, Geometric geom)
{
this.poly = poly;
this.geom = geom;
}
}
/** Creates a new instance of Geometry */
Geometry()
{
}
/**
* Write cell to file
* @return true on error
*/
public boolean writeCell(Cell cell, VarContext context)
{
writeCell(cell, context, new Visitor(this, getMaxHierDepth(cell)));
return false;
}
/**
* Write cell to file
* @return true on error
*/
public boolean writeCell(Cell cell, VarContext context, Visitor visitor)
{
// see how many cells we have to write, for progress indication
numVisited = 0;
numCells = HierarchyEnumerator.getNumUniqueChildCells(cell) + 1;
topCell = cell;
cellGeoms = new HashMap<Cell,CellGeom>();
// write out cells
start();
HierarchyEnumerator.enumerateCell(cell, context, visitor);
// HierarchyEnumerator.enumerateCell(cell, context, null, visitor);
done();
return false;
}
/** Abstract method called before hierarchy traversal */
protected abstract void start();
/** Abstract method called after traversal */
protected abstract void done();
/** Abstract method to write CellGeom to disk */
protected abstract void writeCellGeom(CellGeom cellGeom);
/** Overridable method to determine whether or not to merge geometry */
protected boolean mergeGeom(int hierLevelsFromBottom) { return false; }
/** Overridable method to determine whether or not to include the original Geometric with a Poly */
protected boolean includeGeometric() { return false; }
/**
* Class to store polygon geometry of a cell
*/
protected class CellGeom
{
/** HashMap of Poly(gons) in this Cell, keyed by Layer, all polys per layer stored as a List */
protected HashMap<Layer,List<Object>> polyMap;
/** Nodables (instances) in this Cell */ protected List<Nodable> nodables;
/** Cell */ protected Cell cell;
/** true if cell name used in other libraries */ protected boolean nonUniqueName;
/** Constructor */
protected CellGeom(Cell cell)
{
polyMap = new HashMap<Layer,List<Object>>();
nodables = new ArrayList<Nodable>();
this.cell = cell;
nonUniqueName = false;
checkLayoutCell();
}
private void checkLayoutCell()
{
NodeProto universalPin = Generic.tech().universalPinNode;
int numUniversalPins = 0;
for (int i = 0, numNodes = cell.getNumNodes(); i < numNodes; i++) {
NodeInst ni = cell.getNode(i);
NodeProto np = ni.getProto();
if (np == universalPin) numUniversalPins++;
}
if (numUniversalPins > 0)
System.out.println("Geometry: Layout " + cell + " has " + numUniversalPins + " " + universalPin.describe(true) + " nodes");
ArcProto universalArc = Generic.tech().universal_arc;
int numUniversalArcs = 0;
ArcProto unroutedArc = Generic.tech().unrouted_arc;
int numUnroutedArcs = 0;
for (Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
ArcProto ap = ai.getProto();
if (ap == universalArc) numUniversalArcs++;
if (ap == unroutedArc) numUnroutedArcs++;
}
if (numUniversalArcs > 0)
System.out.println("Geometry: Layout " + cell + " has " + numUniversalArcs + " " + universalArc.describe() + " arcs");
if (numUnroutedArcs > 0)
System.out.println("Geometry: Layout " + cell + " has " + numUnroutedArcs + " " + unroutedArc.describe() + " arcs");
}
/** add polys to cell geometry */
protected void addPolys(Poly[] polys, Geometric geom)
{
for (int i=0; i<polys.length; i++)
{
if (polys[i].isPseudoLayer()) continue;
List<Object> list = polyMap.get(polys[i].getLayer());
if (list == null)
{
list = new ArrayList<Object>();
polyMap.put(polys[i].getLayer(), list);
}
if (includeGeometric())
{
PolyWithGeom pg = new PolyWithGeom(polys[i], geom);
list.add(pg);
} else
{
list.add(polys[i]);
}
}
}
}
//------------------HierarchyEnumerator.Visitor Implementation----------------------
public class Visitor extends HierarchyEnumerator.Visitor
{
/** Geometry object this Visitor is enumerating for */ private Geometry outGeom;
/** Current cellGeom */ protected CellGeom cellGeom = null;
/** Geometry stack when descending hierarchy */ private CellGeom [] outGeomStack;
/** hierarchy max depth */ private int maxHierDepth;
/** current hierarchy depth */ private int curHierDepth;
public Visitor(Geometry outGeom, int maxHierDepth)
{
this.outGeom = outGeom;
this.maxHierDepth = maxHierDepth;
this.outGeomStack = new CellGeom[maxHierDepth+1];
curHierDepth = 0;
}
public boolean enterCell(HierarchyEnumerator.CellInfo info)
{
if (curHierDepth > maxHierDepth) return false;
outGeomStack[curHierDepth] = cellGeom;
Cell cell = info.getCell();
if (cellGeoms.containsKey(cell)) return false; // already processed this Cell
cellGeom = new CellGeom(cell);
for(Iterator<Library> lIt = Library.getLibraries(); lIt.hasNext(); )
{
Library lib = lIt.next();
if (lib.isHidden()) continue;
if (lib == cell.getLibrary()) continue;
for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); )
{
Cell oCell = cIt.next();
if (cell.getView() != oCell.getView()) continue;
if (!cell.getName().equalsIgnoreCase(oCell.getName())) continue;
cellGeom.nonUniqueName = true;
break;
}
if (cellGeom.nonUniqueName) break;
}
cellGeoms.put(info.getCell(), cellGeom);
curHierDepth++;
return true;
}
public void exitCell(HierarchyEnumerator.CellInfo info)
{
// add arcs to cellGeom
for (Iterator<ArcInst> it = info.getCell().getArcs(); it.hasNext();)
{
ArcInst ai = it.next();
addArcInst(ai);
}
boolean merge = outGeom.mergeGeom(maxHierDepth - curHierDepth);
if (merge)
{
GeometryHandler gMerge = GeometryHandler.createGeometryHandler(GHMode.ALGO_SWEEP, 1000);
// PolyMerge pMerge = new PolyMerge();
Set<Layer> layers = cellGeom.polyMap.keySet();
for (Layer layer : layers)
{
List<Object> polyList = cellGeom.polyMap.get(layer);
for (Object polyObj : polyList)
{
Poly poly = (Poly)polyObj;
// pMerge.addPolygon(layer, poly);
gMerge.add(layer, poly);
}
}
for (Layer layer : layers)
{
// List polys = pMerge.getMergedPoints(layer, true);
Collection<PolyBase> polysC = gMerge.getObjects(layer, false, false);
List<Object> polys = new ArrayList<Object>();
for(PolyBase pb : polysC) polys.add(pb);
cellGeom.polyMap.put(layer, polys);
}
}
// write cell
outGeom.writeCellGeom(cellGeom);
curHierDepth--;
cellGeom = outGeomStack[curHierDepth];
}
public boolean visitNodeInst(Nodable no, HierarchyEnumerator.CellInfo info)
{
if (!no.isCellInstance())
{
NodeInst ni = (NodeInst)no;
// don't copy Cell-Centers
if (ni.getProto() == Generic.tech().cellCenterNode) return false;
AffineTransform trans = ni.rotateOut();
addNodeInst(ni, trans);
return false;
}
// else just a cell
cellGeom.nodables.add(no);
return true;
}
public void addNodeInst(NodeInst ni, AffineTransform trans)
{
PrimitiveNode prim = (PrimitiveNode)ni.getProto();
Technology tech = prim.getTechnology();
Poly [] polys = tech.getShapeOfNode(ni); //, windowBeingRendered());
for (int i=0; i<polys.length; i++)
polys[i].transform(trans);
cellGeom.addPolys(polys, ni);
}
public void addArcInst(ArcInst ai)
{
ArcProto ap = ai.getProto();
Technology tech = ap.getTechnology();
Poly [] polys = tech.getShapeOfArc(ai); //, windowBeingRendered());
cellGeom.addPolys(polys, ai);
}
}
//----------------------------Utility Methods--------------------------------------
/** get the max hierarchical depth of the hierarchy */
public static int getMaxHierDepth(Cell cell)
{
return hierCellsRecurse(cell, 0, 0);
}
/** Recursive method used to traverse down hierarchy */
private static int hierCellsRecurse(Cell cell, int depth, int maxDepth)
{
if (depth > maxDepth) maxDepth = depth;
EDatabase database = cell.getDatabase();
for (Iterator<CellUsage> uit = cell.getUsagesIn(); uit.hasNext();)
{
CellUsage u = uit.next();
Cell subCell = u.getProto(database);
if (subCell.isIcon()) continue;
maxDepth = hierCellsRecurse(subCell, depth+1, maxDepth);
}
return maxDepth;
}
}