/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Example.java
* Technology Editor, helper class during conversion of libraries to technologies
* Written by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2005 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.tecEdit;
import com.sun.electric.database.geometry.DBMath;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.RTBounds;
import com.sun.electric.technology.technologies.Generic;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* This class defines graphical node and arc examples during conversion of libraries to technologies.
*/
public class Example implements Serializable
{
/** head of list of samples in example */ List<Sample> samples;
/** sample under analysis */ Sample studySample;
/** bounding box of example */ double lx, hx, ly, hy;
public Example()
{
samples = new ArrayList<Sample>();
}
/**
* Method to parse the node examples in cell "np" and return a list of
* EXAMPLEs (one per example). "isNode" is true if this is a node
* being examined. Returns NOEXAMPLE on error.
*/
public static List<Example> getExamples(Cell np, boolean isNode, TechConversionResult tcr, List<Example> variations)
{
Map<NodeInst,Object> nodeExamples = new HashMap<NodeInst,Object>();
for(Iterator<NodeInst> it = np.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
// ignore special nodes with function information
int funct = Manipulate.getOptionOnNode(ni);
if (funct != Info.LAYERPATCH && funct != Info.PORTOBJ && funct != Info.HIGHLIGHTOBJ)
{
nodeExamples.put(ni, new Integer(0));
}
}
List<Example> neList = new ArrayList<Example>();
for(Iterator<NodeInst> it = np.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (nodeExamples.get(ni) != null) continue;
// get a new cluster of nodes
Example ne = new Example();
neList.add(ne);
Poly poly = new Poly(ni.getAnchorCenterX(), ni.getAnchorCenterY(),
ni.getLambdaBaseXSize(), ni.getLambdaBaseYSize());
poly.transform(ni.rotateOut());
Rectangle2D soFar = poly.getBounds2D();
// now find all others that touch this area
boolean gotBBox = false;
boolean foundOne = true;
int hCount = 0;
while (foundOne)
{
foundOne = false;
// begin to search the area so far
List<NodeInst> sortedNodes = new ArrayList<NodeInst>();
for(Iterator<RTBounds> oIt = np.searchIterator(soFar); oIt.hasNext(); )
{
RTBounds geom = oIt.next();
if (geom == null) break;
if (geom instanceof NodeInst)
sortedNodes.add((NodeInst)geom);
}
for(NodeInst otherNi: sortedNodes)
{
Poly oPoly = new Poly(otherNi.getAnchorCenterX(), otherNi.getAnchorCenterY(),
otherNi.getLambdaBaseXSize(), otherNi.getLambdaBaseYSize());
oPoly.transform(otherNi.rotateOut());
Rectangle2D otherRect = oPoly.getBounds2D();
if (!DBMath.rectsIntersect(otherRect, soFar)) continue;
// make sure the node is valid
Object otherAssn = nodeExamples.get(otherNi);
if (otherAssn != null)
{
if (otherAssn instanceof Integer) continue;
if ((Example)otherAssn == ne) continue;
String error = "Examples are too close. Found " + neList.size() + " examples at:";
for(Example nee : neList)
{
error += " [" + TextUtils.formatDistance(nee.lx) + "<=X<=" + TextUtils.formatDistance(nee.hx) +
" and " + TextUtils.formatDistance(nee.ly) + "<=Y<=" + TextUtils.formatDistance(nee.hy) + "]";
}
tcr.markError(otherNi, np, error);
return null;
}
nodeExamples.put(otherNi, ne);
// add it to the cluster
Sample ns = new Sample();
ns.node = otherNi;
ns.values = null;
ns.msg = null;
ns.parent = ne;
ne.samples.add(ns);
ns.assoc = null;
ns.xPos = otherRect.getCenterX();
ns.yPos = otherRect.getCenterY();
int funct = Manipulate.getOptionOnNode(otherNi);
switch (funct)
{
case Info.PORTOBJ:
if (!isNode)
{
tcr.markError(otherNi, np, "Ports can only exist in nodes");
return null;
}
ns.layer = Generic.tech().portNode;
break;
case Info.CENTEROBJ:
if (!isNode)
{
tcr.markError(otherNi, np, "Grab points can only exist in nodes");
return null;
}
ns.layer = Generic.tech().cellCenterNode;
break;
case Info.HIGHLIGHTOBJ:
hCount++;
break;
default:
ns.layer = Manipulate.getLayerCell(otherNi);
if (ns.layer == null)
{
Manipulate.getLayerCell(otherNi);
tcr.markError(otherNi, np, "Node has no layer information");
return null;
}
break;
}
// accumulate state if this is not a "grab point" mark
if (otherNi.getProto() != Generic.tech().cellCenterNode)
{
if (!gotBBox)
{
ne.lx = otherRect.getMinX(); ne.hx = otherRect.getMaxX();
ne.ly = otherRect.getMinY(); ne.hy = otherRect.getMaxY();
gotBBox = true;
} else
{
if (otherRect.getMinX() < ne.lx) ne.lx = otherRect.getMinX();
if (otherRect.getMaxX() > ne.hx) ne.hx = otherRect.getMaxX();
if (otherRect.getMinY() < ne.ly) ne.ly = otherRect.getMinY();
if (otherRect.getMaxY() > ne.hy) ne.hy = otherRect.getMaxY();
}
soFar.setRect(ne.lx, ne.ly, ne.hx-ne.lx, ne.hy-ne.ly);
}
foundOne = true;
}
}
if (hCount == 0)
{
tcr.markError(null, np, "No highlight layer found");
return null;
}
if (hCount != 1)
{
tcr.markError(null, np, "Too many highlight layers found");
return null;
}
}
if (neList == null)
{
tcr.markError(null, np, "No examples found");
return neList;
}
// put variations in a separate list
if (variations != null)
{
for(int i=0; i<neList.size(); i++)
{
Example e = neList.get(i);
for(Sample s : e.samples)
{
if (!s.node.getNameKey().isTempname())
{
// named a layer: this is a variation
variations.add(e);
neList.remove(i);
i--;
break;
}
}
}
if (neList.size() == 0 && variations.size() > 0)
{
tcr.markError(null, np, "All examples have text on them...text should be used only in variations");
return neList;
}
}
// now search the list for the smallest, most upper-left example (the "main" example)
double sizeX = 0;
double sizeY = 0;
double locX = 0;
double locY = 0;
Example bestNe = null;
for(Example ne : neList)
{
double newSize = ne.hx-ne.lx;
newSize *= ne.hy-ne.ly;
if (bestNe != null)
{
if (newSize > sizeX*sizeY) continue;
if (newSize == sizeX*sizeY && (ne.lx+ne.hx)/2 >= locX && (ne.ly+ne.hy)/2 <= locY)
continue;
}
sizeX = ne.hx - ne.lx;
sizeY = ne.hy - ne.ly;
locX = (ne.lx + ne.hx) / 2;
locY = (ne.ly + ne.hy) / 2;
bestNe = ne;
}
// place the main example at the top of the list
if (bestNe != null && bestNe != neList)
{
neList.remove(bestNe);
neList.add(0, bestNe);
}
// done
return neList;
}
}