/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: NetworkHighlighter.java
*
* 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.user;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.HierarchyEnumerator;
import com.sun.electric.database.hierarchy.Nodable;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.network.Network;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.ElectricObject;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.technology.PrimitiveNode;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* This class is used for hierarchical highlighting of networks
*/
public class NetworkHighlighter extends HierarchyEnumerator.Visitor {
private static final boolean TRIMMEDDISPLAY = false;
private Cell cell;
private Netlist netlist;
private Set<Network> nets;
private BitSet netIDs;
private int startDepth;
private int endDepth;
private int currentDepth;
private Highlighter highlighter;
private NetworkHighlighter(Cell cell, Netlist netlist, Set<Network> nets, int startDepth, int endDepth) {
this.cell = cell;
this.netlist = netlist;
this.nets = nets;
this.startDepth = startDepth;
this.endDepth = endDepth;
currentDepth = 0;
highlighter = new Highlighter(Highlighter.SELECT_HIGHLIGHTER, null);
}
/**
* Returns a list of Highlight objects that draw lines and boxes over
* instances that denote the location of objects in that instance that
* are connected to net. The depth of the search is specified by startDepth
* and endDepth, which start at 0. If both are set to zero, only objects in the
* cell Cell are highlighted.
* @param cell the cell in which to highlight objects
* @param netlist the netlist for the cell
* @param nets objects connected to these networks will be highlighted
* @param startDepth to start depth of the hierarchical search
* @return endDepth the end depth of the hierarchical search
*/
public static synchronized List<Highlight> getHighlights(Cell cell, Netlist netlist, Set<Network> nets,
int startDepth, int endDepth)
{
NetworkHighlighter networkHighlighter = new NetworkHighlighter(cell, netlist, nets, startDepth, endDepth);
HierarchyEnumerator.enumerateCell(cell, VarContext.globalContext, networkHighlighter);
return networkHighlighter.highlighter.getHighlights();
}
public boolean enterCell(HierarchyEnumerator.CellInfo info)
{
if (currentDepth == 0) {
// set the global net ID that will be used in sub cells
netIDs = new BitSet();
for (Network net : nets) {
netIDs.set(info.getNetID(net));
}
}
// do not go below depth 0 for schematics
if (cell.isSchematic()) {
if (currentDepth > 0) return false;
}
if (currentDepth >= startDepth) {
if (currentDepth > endDepth) return false; // stop here. No more traversal down.
// highlight connected in current cell. Highlight actual objects if top level
if (currentDepth == 0) {
addNetworkObjects();
} else {
addNetworkPolys(info);
}
}
// increment depth and continue
currentDepth++;
return true;
}
public void exitCell(HierarchyEnumerator.CellInfo info) {
currentDepth--;
}
public boolean visitNodeInst(Nodable ni, HierarchyEnumerator.CellInfo info) {
return true;
}
/**
* Get objects connected to a network in a Cell.
* @param cell the Cell to examine.
* @param netlist the Netlist in the cell being examined.
* @param nets the desired Networks to find in the cell.
* @return Set of ArcInsts, PortInsts and Exports on the desired networs.
*/
private static Set<ElectricObject> getNetworkObjects(Cell cell, Netlist netlist, Set<Network> nets)
{
Set<ElectricObject> objs = new HashSet<ElectricObject>();
// all port instances on the networks
if (!TRIMMEDDISPLAY)
{
for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) {
NodeInst ni = it.next();
if (ni.getNameKey().isBus()) continue;
for (Iterator<PortInst> pit = ni.getPortInsts(); pit.hasNext(); ) {
PortInst pi = pit.next();
PortProto portProto = pi.getPortProto();
if (portProto.getNameKey().isBus()) continue;
if (!nets.contains(netlist.getNetwork(pi))) continue;
objs.add(pi);
}
}
}
// all arcs on the networks
for(Iterator<ArcInst> aIt = cell.getArcs(); aIt.hasNext(); ) {
ArcInst ai = aIt.next();
int width = netlist.getBusWidth(ai);
for(int i=0; i<width; i++) {
if (!nets.contains(netlist.getNetwork(ai, i))) continue;
objs.add(ai);
if (!TRIMMEDDISPLAY)
{
// also highlight end nodes of arc, if they are primitive nodes
PortInst pi = ai.getHeadPortInst();
if (!pi.getNodeInst().isCellInstance()) {
// ignore pins
if (!pi.getNodeInst().getProto().getFunction().isPin())
objs.add(pi);
}
pi = ai.getTailPortInst();
if (!pi.getNodeInst().isCellInstance()) {
if (!pi.getNodeInst().getProto().getFunction().isPin())
objs.add(pi);
}
}
}
}
// show all exports on the networks if at the top level
if (!TRIMMEDDISPLAY)
{
for(Iterator<PortProto> pIt = cell.getPorts(); pIt.hasNext(); ) {
Export pp = (Export)pIt.next();
int width = netlist.getBusWidth(pp);
for(int i=0; i<width; i++) {
if (!nets.contains(netlist.getNetwork(pp, i))) continue;
objs.add(pp);
}
}
}
return objs;
}
/**
* Retrieves the User's preference color for NodeInst objects
* @return
*/
private static Color getNodeOrPortColor()
{
return new Color(User.getColor(User.ColorPrefType.NODE_HIGHLIGHT)); // use to hightlight NodeInsts
}
/**
* Add all network objects (arcs, primitive nodes) to highlighter for current cell.
* Choose MOUSEOVER_HIGHLLIGHT color for non-wire objects and HIGHLIGHT color for wires.
*/
private void addNetworkObjects() {
// highlight objects in this cell
Set<ElectricObject> objs = getNetworkObjects(cell, netlist, nets);
Color nodeColor = getNodeOrPortColor();
for (ElectricObject eObj : objs)
{
Color color = !((eObj instanceof ArcInst)) ? nodeColor : null;
if (eObj instanceof Export)
{
highlighter.addText(eObj, cell, Export.EXPORT_NAME);
} else
{
highlighter.addElectricObject(eObj, cell, false, color);
}
}
}
/**
* Add all network objects (arcs, primitive nodes) as poly
* objects, transformed by trans.
*/
private void addNetworkPolys(HierarchyEnumerator.CellInfo info) {
Netlist netlist = info.getNetlist();
// find all local networks in this cell that corresponds to global id
Set<Network> localNets = new HashSet<Network>();
for (Iterator<Network> it = netlist.getNetworks(); it.hasNext(); ) {
Network aNet = it.next();
if (netIDs.get(info.getNetID(aNet))) {
localNets.add(aNet);
}
}
addNetworkPolys(localNets, info);
}
private void addNetworkPolys(Set<Network> localNets, HierarchyEnumerator.CellInfo info) {
Netlist netlist = info.getNetlist();
// no local net that matches with global network
if (localNets.size() == 0) return;
Cell currentCell = info.getCell();
Set<ElectricObject> objs = getNetworkObjects(currentCell, netlist, localNets);
Color colorN = getNodeOrPortColor();
// get polys for each object and transform them to root
AffineTransform trans = info.getTransformToRoot();
for (ElectricObject o : objs) {
Color color = null;
Poly poly = null;
if (o instanceof ArcInst) {
ArcInst ai = (ArcInst)o;
if (TRIMMEDDISPLAY)
poly = new Poly(new Point2D.Double[]{ai.getHeadLocation().lambdaMutable(), ai.getTailLocation().lambdaMutable()});
else
poly = ai.makeLambdaPoly(ai.getGridBaseWidth(), Poly.Type.CLOSED);
} else if (o instanceof PortInst) {
PortInst pi = (PortInst)o;
NodeInst ni = pi.getNodeInst();
poly = Highlight.getNodeInstOutline(ni);
color = colorN;
} else if (o instanceof Export) {
Export ep = (Export)o;
PortInst pi = ep.getOriginalPort();
NodeInst ni = pi.getNodeInst();
poly = ni.getShapeOfPort(pi.getPortProto());
color = Color.YELLOW;
}
else if (o instanceof NodeInst)
{
color = colorN;
}
poly.transform(trans);
highlighter.addPoly(poly, cell, color);
}
}
}