Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.electric.tool.routing.MimicStitch Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: MimicStitch.java
* Routing tool: Mimic Stitcher (duplicates user's routes elsewhere in the cell).
* Written by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* 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.routing;
import com.sun.electric.database.EditingPreferences;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.id.ArcProtoId;
import com.sun.electric.database.network.Netlist;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Connection;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.EditWindow_;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.user.Highlight;
import com.sun.electric.tool.user.User;
import com.sun.electric.tool.user.UserInterfaceMain;
import com.sun.electric.tool.user.dialogs.EDialog;
import com.sun.electric.tool.user.ui.TopLevel;
import com.sun.electric.util.math.DBMath;
/**
* This is the Mimic Stitching tool.
*/
public class MimicStitch
{
/** router to use */ private static InteractiveRouter router = null/*new SimpleWirer()*/;
private static final int NUMSITUATIONS = 7;
private static final int LIKELYDIFFPORT = 1;
private static final int LIKELYDIFFPORTWIDTH = 2;
private static final int LIKELYDIFFARCCOUNT = 4;
private static final int LIKELYDIFFNODETYPE = 8;
private static final int LIKELYDIFFNODESIZE = 16;
private static final int LIKELYARCSSAMEDIR = 32;
private static final int LIKELYALREADYCONNECTED = 64;
private static int situations[] = null;
private static void buildLikelySituations()
{
if (situations != null) return;
int numSituations = 1 << NUMSITUATIONS;
List allSituations = new ArrayList();
for(int i=0; i
{
public int compare(Integer r1, Integer r2)
{
int i1 = r1.intValue();
int i2 = r2.intValue();
int b1 = 0, b2 = 0;
for(int i=0; i 1 && lastActivity.numCreatedNodes > 0)
{
// find the ends of arcs that do not attach to the intermediate pins
HashSet gotOne = new HashSet();
HashSet gotMany = new HashSet();
for(int i=0; i width)
width = ai.getLambdaBaseWidth();
}
foundEnds++;
}
}
// if exactly two ends are found, mimic that connection
if (foundEnds == 2)
{
double prefX = 0, prefY = 0;
if (lastActivity.numCreatedNodes == 1)
{
Poly portPoly0 = ends[0].getPortInst().getPoly();
double x0 = portPoly0.getCenterX();
double y0 = portPoly0.getCenterY();
Poly portPoly1 = ends[1].getPortInst().getPoly();
double x1 = portPoly1.getCenterX();
double y1 = portPoly1.getCenterY();
prefX = lastActivity.createdNodes[0].anchor.getLambdaX() - (x0+x1) / 2;
prefY = lastActivity.createdNodes[0].anchor.getLambdaY() - (y0+y1) / 2;
} else if (lastActivity.numCreatedNodes == 2)
{
Poly portPoly0 = ends[0].getPortInst().getPoly();
double x0 = portPoly0.getCenterX();
double y0 = portPoly0.getCenterY();
Poly portPoly1 = ends[1].getPortInst().getPoly();
double x1 = portPoly1.getCenterX();
double y1 = portPoly1.getCenterY();
prefX = (lastActivity.createdNodes[0].anchor.getLambdaX() +
lastActivity.createdNodes[1].anchor.getLambdaX()) / 2 - (x0+x1) / 2;
prefY = (lastActivity.createdNodes[0].anchor.getLambdaY() +
lastActivity.createdNodes[1].anchor.getLambdaY()) / 2 - (y0+y1) / 2;
}
new MimicStitchJob(ends[0].getArc(), ends[0].getEndIndex(), ends[1].getArc(), ends[1].getEndIndex(),
width, null, prefX, prefY, forced);
}
lastActivity.numCreatedArcs = 0;
return;
}
}
/**
* Method to mimic the deletion of an arc.
*/
private static void mimicdelete(Routing.Activity activity, EditingPreferences ep)
{
UserInterface ui = Job.getUserInterface();
EditWindow_ wnd = ui.needCurrentEditWindow_();
if (wnd == null) return;
// determine information about deleted arc
ImmutableArcInst mimicAi = activity.deletedArc;
Cell cell = Cell.inCurrentThread(activity.deletedArcParent);
if (cell == null) return; // cell killed
NodeInst mimicNiHead = cell.getNodeById(mimicAi.headNodeId);
NodeInst mimicNiTail = cell.getNodeById(mimicAi.tailNodeId);
if (mimicNiHead == null || mimicNiTail == null) return; // arc end killed
ArcProtoId typ = mimicAi.protoId;
Point2D pt0 = mimicAi.headLocation;
Point2D pt1 = mimicAi.tailLocation;
double dist = pt0.distance(pt1);
int angle = 0;
if (dist != 0) angle = DBMath.figureAngle(pt0, pt1);
// look for a similar situation to delete
List arcKills = new ArrayList();
for(Iterator it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
// arc must be of the same type
if (ai.getProto().getId() != typ) continue;
// must be the same length and angle
Point2D end0 = ai.getHeadLocation();
Point2D end1 = ai.getTailLocation();
double thisDist = end0.distance(end1);
if (dist != thisDist) continue;
if (dist != 0)
{
int thisAngle = DBMath.figureAngle(end0, end1);
if ((angle%1800) != (thisAngle%1800)) continue;
}
PossibleArc pa = new PossibleArc();
pa.ai = ai;
pa.situation = 0;
// arc must connect to the same type of port
boolean matchPort = false;
if (ai.getHeadPortInst().getPortProto().getId() == activity.deletedPorts[0] &&
ai.getTailPortInst().getPortProto().getId() == activity.deletedPorts[1]) matchPort = true;
if (ai.getHeadPortInst().getPortProto().getId() == activity.deletedPorts[1] &&
ai.getTailPortInst().getPortProto().getId() == activity.deletedPorts[0]) matchPort = true;
if (!matchPort) pa.situation |= LIKELYDIFFPORT;
// arcs must have the same bus width
NodeInst niHead = ai.getHeadPortInst().getNodeInst();
NodeInst niTail = ai.getTailPortInst().getNodeInst();
int con1 = mimicNiHead.getNumConnections() + mimicNiTail.getNumConnections() + 2;
int con2 = niHead.getNumConnections() + niTail.getNumConnections();
if (con1 != con2) pa.situation |= LIKELYDIFFARCCOUNT;
// arc must connect to the same type of node
boolean matchNode = false;
if (niHead.getProto() == mimicNiHead.getProto() && niTail.getProto() == mimicNiTail.getProto())
matchNode = true;
if (niHead.getProto() == mimicNiTail.getProto() && niTail.getProto() == mimicNiHead.getProto())
matchNode = true;
if (!matchNode) pa.situation |= LIKELYDIFFNODETYPE;
// determine size of nodes on mimic arc
double mimicWidHead = mimicNiHead.getLambdaBaseXSize();
double mimicHeiHead = mimicNiHead.getLambdaBaseYSize();
double mimicWidTail = mimicNiTail.getLambdaBaseXSize();
double mimicHeiTail = mimicNiTail.getLambdaBaseYSize();
// determine size of nodes on possible deleted arc
double widHead = niHead.getLambdaBaseXSize();
double heiHead = niHead.getLambdaBaseYSize();
double widTail = niTail.getLambdaBaseXSize();
double heiTail = niTail.getLambdaBaseYSize();
// flag if the sizes differ
if (widHead != mimicWidHead || heiHead != mimicHeiHead) pa.situation |= LIKELYDIFFNODESIZE;
if (widTail != mimicWidTail || heiTail != mimicHeiTail) pa.situation |= LIKELYDIFFNODESIZE;
// the same! queue it for deletion
arcKills.add(pa);
}
MimicOptions prefs = new MimicOptions();
prefs.getOptionsFromPreferences();
processPossibilities(cell, arcKills, 0, 0, Job.Type.CLIENT_EXAMINE, true, ep, prefs);
}
/**
* Class to examine a circuit and find mimic opportunities in a new thread.
*/
private static class MimicStitchJob extends Job
{
private ArcInst ai1, ai2;
private int end1, end2;
private double oWidth;
private ArcProto oProto;
private double prefX, prefY;
private boolean forced;
private MimicOptions prefs;
private MimicStitchJob(ArcInst ai1, int end1, ArcInst ai2, int end2, double oWidth, ArcProto oProto,
double prefX, double prefY, boolean forced)
{
super("Mimic-Stitch", Routing.getRoutingTool(), Job.Type.CLIENT_EXAMINE, null, null, Job.Priority.USER);
this.ai1 = ai1;
this.end1 = end1;
this.ai2 = ai2;
this.end2 = end2;
this.oWidth = oWidth;
this.oProto = oProto;
this.prefX = prefX;
this.prefY = prefY;
this.forced = forced;
setReportExecutionFlag(true);
prefs = new MimicOptions();
prefs.getOptionsFromPreferences();
startJob();
}
public boolean doIt() throws JobException
{
mimicOneArc(ai1, end1, ai2, end2, oWidth, oProto, prefX, prefY, forced, Job.Type.CLIENT_EXAMINE, getEditingPreferences(), prefs, this);
return true;
}
}
/**
* Method to do mimic stitching.
* It can be used during batch processing to mimic directly.
* @param ai1 the arc connected to the first port of the connection to mimic.
* @param end1 the end of "ai1" that defines the first port of the connection to mimic.
* @param ai2 the arc connected to the second port of the connection to mimic.
* @param end2 the end of "ai2" that defines the second port of the connection to mimic.
* @param oWidth the width of the arc to run.
* @param oProto the type of arc to run.
* @param prefX the preferred X position of the mimic (if there is a choice).
* @param prefY the preferred Y position of the mimic (if there is a choice).
* @param forced true if this was an explicitly requested mimic.
* @param method the type of job that is running (CHANGE or EXAMINE).
* @param ep EditingPreferences
* @param prefs stitching preferences.
* @param theJob the job that is running this mimic operation
*/
public static void mimicOneArc(ArcInst ai1, int end1, ArcInst ai2, int end2, double oWidth, ArcProto oProto,
double prefX, double prefY, boolean forced, Job.Type method, EditingPreferences ep, MimicOptions prefs, Job theJob)
{
if (forced) System.out.println("Mimicing last arc...");
buildLikelySituations();
PortInst [] endPi = new PortInst[2];
Connection conn1 = ai1.getConnection(end1);
Connection conn2 = ai2.getConnection(end2);
endPi[0] = conn1.getPortInst(); endPi[1] = conn2.getPortInst();
Point2D [] endPts = new Point2D[2];
endPts[0] = conn1.getLocation(); endPts[1] = conn2.getLocation();
Cell cell = endPi[0].getNodeInst().getParent();
Netlist netlist = cell.getNetlist();
if (netlist == null)
{
System.out.println("Sorry, a deadlock aborted mimic-routing (network information unavailable). Please try again");
return;
}
int busWidth = netlist.getBusWidth(ai1);
// make list of possible arc connections
List possibleArcs = new ArrayList();
// count the number of other arcs on the ends
int con1 = endPi[0].getNodeInst().getNumConnections() + endPi[1].getNodeInst().getNumConnections() - 2;
// precompute polygon information about every port in the cell
HashMap cachedPortPoly = new HashMap();
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
for(Iterator pIt = ni.getPortInsts(); pIt.hasNext(); )
{
PortInst pi = pIt.next();
if (oProto != null)
{
if (!pi.getPortProto().connectsTo(oProto)) continue;
}
cachedPortPoly.put(pi, pi.getPoly());
}
}
if (cachedPortPoly.size() == 0) return;
// search from both ends
for(int end=0; end<2; end++)
{
PortInst pi0 = endPi[end];
PortInst pi1 = endPi[1-end];
NodeInst node0 = pi0.getNodeInst();
NodeInst node1 = pi1.getNodeInst();
PortProto port0 = pi0.getPortProto();
PortProto port1 = pi1.getPortProto();
Point2D pt0 = endPts[end];
Point2D pt1 = endPts[1-end];
double dist = pt0.distance(pt1);
double distX = pt1.getX() - pt0.getX();
double distY = pt1.getY() - pt0.getY();
int angle = 0;
if (dist != 0) angle = DBMath.figureAngle(pt0, pt1);
boolean useFAngle = false;
double angleRadians = 0;
if ((angle%900) != 0)
{
angleRadians = DBMath.figureAngleRadians(pt0, pt1);
useFAngle = true;
}
Poly port0Poly = pi0.getPoly();
double end0Offx = pt0.getX() - port0Poly.getCenterX();
double end0Offy = pt0.getY() - port0Poly.getCenterY();
double node0Wid = node0.getLambdaBaseXSize();
double node0Hei = node0.getLambdaBaseYSize();
double node1Wid = node1.getLambdaBaseXSize();
double node1Hei = node1.getLambdaBaseYSize();
// now search every node in the cell
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
Rectangle2D bounds = ni.getBounds();
if (theJob != null && theJob.checkAbort())
{
System.out.println("Mimic Arc Job aborted");
return;
}
// now look for another node that matches the situation
for(Iterator oIt = cell.getNodes(); oIt.hasNext(); )
{
NodeInst oNi = oIt.next();
Rectangle2D oBounds = oNi.getBounds();
// ensure that intra-node wirings stay that way
if (node0 == node1)
{
if (ni != oNi) continue;
} else
{
if (ni == oNi) continue;
}
// make sure the distances are sensible
if (distX > 0)
{
if (bounds.getMaxX() + distX < oBounds.getMinX()) continue;
if (bounds.getMinX() + distX > oBounds.getMaxX()) continue;
} else
{
if (bounds.getMinX() + distX > oBounds.getMaxX()) continue;
if (bounds.getMaxX() + distX < oBounds.getMinX()) continue;
}
if (distY > 0)
{
if (bounds.getMaxY() + distY < oBounds.getMinY()) continue;
if (bounds.getMinY() + distY > oBounds.getMaxY()) continue;
} else
{
if (bounds.getMinY() + distY > oBounds.getMaxY()) continue;
if (bounds.getMaxY() + distY < oBounds.getMinY()) continue;
}
// compare each port
for(Iterator pIt = ni.getPortInsts(); pIt.hasNext(); )
{
PortInst pi = pIt.next();
PortProto pp = pi.getPortProto();
// if this port is not cached, it cannot connect, so ignore it
Poly poly = cachedPortPoly.get(pi);
if (poly == null) continue;
double x0 = poly.getCenterX();
double y0 = poly.getCenterY();
x0 += end0Offx; y0 += end0Offy;
double wantX1 = x0;
double wantY1 = y0;
if (dist != 0)
{
if (useFAngle)
{
wantX1 = x0 + Math.cos(angleRadians) * dist;
wantY1 = y0 + Math.sin(angleRadians) * dist;
} else
{
wantX1 = x0 + DBMath.cos(angle) * dist;
wantY1 = y0 + DBMath.sin(angle) * dist;
}
}
Point2D xy0 = new Point2D.Double(x0, y0);
Point2D want1 = new Point2D.Double(wantX1, wantY1);
for(Iterator oPIt = oNi.getPortInsts(); oPIt.hasNext(); )
{
PortInst oPi = oPIt.next();
PortProto oPp = oPi.getPortProto();
if (ni == oNi && pp == oPp) continue;
// if this port is not cached, it cannot connect, so ignore it
Poly thisPoly = cachedPortPoly.get(oPi);
if (thisPoly == null) continue;
// don't replicate what is already done
if (pi == pi0 && oPi == pi1) continue;
// see if they are the same distance apart
boolean ptInPoly = thisPoly.isInside(want1);
if (!ptInPoly) continue;
// figure out the wiring situation here
int situation = 0;
// if there is a network that already connects these, ignore
if (netlist.sameNetwork(ni, pp, oNi, oPp))
{
situation |= LIKELYALREADYCONNECTED;
}
// see if there are already wires going in this direction
int desiredAngle = -1;
if (x0 != wantX1 || y0 != wantY1)
desiredAngle = DBMath.figureAngle(xy0, want1);
for(Iterator pII = ni.getConnections(); pII.hasNext(); )
{
Connection con = pII.next();
PortInst aPi = con.getPortInst();
if (aPi.getPortProto() != pp) continue;
ArcInst oAi = con.getArc();
if (desiredAngle < 0)
{
if (oAi.getHeadLocation().getX() == oAi.getTailLocation().getX() &&
oAi.getHeadLocation().getY() == oAi.getTailLocation().getY())
{
situation |= LIKELYARCSSAMEDIR;
break;
}
} else
{
if (oAi.getHeadLocation().getX() == oAi.getTailLocation().getX() &&
oAi.getHeadLocation().getY() == oAi.getTailLocation().getY())
continue;
int thisend = 0;
if (oAi.getTailPortInst() == aPi) thisend = 1;
int existingAngle = DBMath.figureAngle(oAi.getLocation(thisend),
oAi.getLocation(1-thisend));
if (existingAngle == desiredAngle)
{
situation |= LIKELYARCSSAMEDIR;
break;
}
}
}
desiredAngle = -1;
if (x0 != wantX1 || y0 != wantY1)
desiredAngle = DBMath.figureAngle(want1, xy0);
for(Iterator pII = oNi.getConnections(); pII.hasNext(); )
{
Connection con = pII.next();
PortInst aPi = con.getPortInst();
if (aPi.getPortProto() != oPp) continue;
ArcInst oAi = con.getArc();
if (desiredAngle < 0)
{
if (oAi.getHeadLocation().getX() == oAi.getTailLocation().getX() &&
oAi.getHeadLocation().getY() == oAi.getTailLocation().getY())
{
situation |= LIKELYARCSSAMEDIR;
break;
}
} else
{
if (oAi.getHeadLocation().getX() == oAi.getTailLocation().getX() &&
oAi.getHeadLocation().getY() == oAi.getTailLocation().getY())
continue;
int thisend = 0;
if (oAi.getTailPortInst() == aPi) thisend = 1;
int existingAngle = DBMath.figureAngle(oAi.getLocation(thisend),
oAi.getLocation(1-thisend));
if (existingAngle == desiredAngle)
{
situation |= LIKELYARCSSAMEDIR;
break;
}
}
}
if (pp instanceof Export && oPp instanceof Export)
{
int e0Wid = netlist.getBusWidth((Export)pp);
int e1Wid = netlist.getBusWidth((Export)oPp);
if (e0Wid != busWidth || e1Wid != busWidth)
situation |= LIKELYDIFFPORTWIDTH;
} else
{
if (busWidth != 1) situation |= LIKELYDIFFPORTWIDTH;
}
int con2 = ni.getNumConnections() + oNi.getNumConnections();
if (con1 != con2) situation |= LIKELYDIFFARCCOUNT;
if (ni.getProto() != node0.getProto() || oNi.getProto() != node1.getProto())
{
situation |= LIKELYDIFFNODETYPE;
} else
{
if (pp != port0 || oPp != port1)
situation |= LIKELYDIFFPORT;
}
double wid = ni.getLambdaBaseXSize();
double hei = ni.getLambdaBaseYSize();
if (wid != node0Wid || hei != node0Hei) situation |= LIKELYDIFFNODESIZE;
wid = oNi.getLambdaBaseXSize();
hei = oNi.getLambdaBaseYSize();
if (wid != node1Wid || hei != node1Hei) situation |= LIKELYDIFFNODESIZE;
// see if this combination has already been considered
PossibleArc found = null;
for(PossibleArc pa : possibleArcs)
{
if (pa.ni1 == ni && pa.pp1 == pp && pa.ni2 == oNi && pa.pp2 == oPp)
{ found = pa; break; }
if (pa.ni2 == ni && pa.pp2 == pp && pa.ni1 == oNi && pa.pp1 == oPp)
{ found = pa; break; }
}
if (found != null)
{
if (found.situation == situation) continue;
int foundIndex = -1;
for(int k=0; k= 0 && found.situation == situations[foundIndex])
continue;
}
if (found == null)
{
found = new PossibleArc();
possibleArcs.add(found);
}
found.ni1 = ni; found.pp1 = pp;
found.ni2 = oNi; found.pp2 = oPp;
found.situation = situation;
}
}
}
}
}
// now create the mimiced arcs
processPossibilities(cell, possibleArcs, prefX, prefY, method, forced, ep, prefs);
}
private static void processPossibilities(Cell cell, List possibleArcs, double prefX, double prefY,
Job.Type method, boolean forced, EditingPreferences ep, MimicOptions prefs)
{
router = new SimpleWirer(ep);
if (prefs.mimicInteractive)
{
// do this in a separate thread so that this examine job can finish
MimicInteractive task = new MimicInteractive(cell, possibleArcs, prefX, prefY);
SwingUtilities.invokeLater(task);
return;
}
// not interactive: follow rules in the Preferences
int ifIgnorePorts = 0, ifIgnorePortWidth = 0, ifIgnoreArcCount = 0, ifIgnoreNodeType = 0;
int ifIgnoreNodeSize = 0, ifIgnoreOtherSameDir = 0, ifAlreadyConnected = 0;
int count = 0;
boolean deletion = false;
for(int j=0; j allRoutes = new ArrayList();
List allKills = new ArrayList();
int total = 0;
for(PossibleArc pa : possibleArcs)
{
if (pa.ai != null) deletion = true;
if (pa.situation != situations[j]) continue;
total++;
if (pa.ai != null)
{
// plan an arc deletion
allKills.add(pa.ai);
} else
{
// plan an arc creation
Poly portPoly1 = pa.ni1.getShapeOfPort(pa.pp1);
Poly portPoly2 = pa.ni2.getShapeOfPort(pa.pp2);
Point2D bend = new Point2D.Double((portPoly1.getCenterX() + portPoly2.getCenterX()) / 2 + prefX,
(portPoly1.getCenterY() + portPoly2.getCenterY()) / 2 + prefY);
PortInst pi1 = pa.ni1.findPortInstFromProto(pa.pp1);
PortInst pi2 = pa.ni2.findPortInstFromProto(pa.pp2);
Route route = router.planRoute(pa.ni1.getParent(), pi1, pi2, bend, null, ep, true, true, null, null);
if (route.size() == 0)
{
System.out.println("Problem creating arc");
continue;
}
allRoutes.add(route);
}
}
if (total == 0) continue;
// make sure this situation is the desired one
if (prefs.matchPorts && (situations[j]&LIKELYDIFFPORT) != 0) { ifIgnorePorts += total; continue; }
if (prefs.matchPortWidth && (situations[j]&LIKELYDIFFPORTWIDTH) != 0) { ifIgnorePortWidth += total; continue; }
if (prefs.matchArcCount && (situations[j]&LIKELYDIFFARCCOUNT) != 0) { ifIgnoreArcCount += total; continue; }
if (prefs.matchNodeType && (situations[j]&LIKELYDIFFNODETYPE) != 0) { ifIgnoreNodeType += total; continue; }
if (prefs.matchNodeSize && (situations[j]&LIKELYDIFFNODESIZE) != 0) { ifIgnoreNodeSize += total; continue; }
if (prefs.noOtherArcsThisDir && (situations[j]&LIKELYARCSSAMEDIR) != 0) { ifIgnoreOtherSameDir += total; continue; }
if (prefs.notAlreadyConnected && (situations[j]&LIKELYALREADYCONNECTED) != 0) { ifAlreadyConnected += total; continue; }
// create the routes
if (method == Job.Type.CLIENT_EXAMINE)
{
// since this is an examine job, queue a change job to make the wires
new MimicWireJob(allRoutes, allKills, false, prefs);
} else
{
// since this is a change job, do the wires now
runTheWires(allRoutes, ep);
}
count += total;
}
if (count == 0)
{
if (forced)
{
String activity = deletion ? "deleted" : "added";
String msg = "No wires " + activity;
if (ifIgnorePorts != 0)
msg += ", might have " + activity + " " + ifIgnorePorts + " wires if 'ports must match' were off";
if (ifIgnorePortWidth != 0)
msg += ", might have " + activity + " " + ifIgnorePortWidth + " wires if 'ports must match width' were off";
if (ifIgnoreArcCount != 0)
msg += ", might have " + activity + " " + ifIgnoreArcCount + " wires if 'number of existing arcs must match' were off";
if (ifIgnoreNodeType != 0)
msg += ", might have " + activity + " " + ifIgnoreNodeType + " wires if 'node types must match' were off";
if (ifIgnoreNodeSize != 0)
msg += ", might have " + activity + " " + ifIgnoreNodeSize + " wires if 'nodes sizes must match' were off";
if (ifIgnoreOtherSameDir != 0)
msg += ", might have " + activity + " " + ifIgnoreOtherSameDir + " wires if 'cannot have other arcs in the same direction' were off";
if (ifAlreadyConnected != 0)
msg += ", might have " + activity + " " + ifAlreadyConnected + " wires if 'ignore if already connected elsewhere' were off";
System.out.println(msg);
if (ifIgnorePorts + ifIgnoreArcCount + ifIgnoreNodeType + ifIgnoreNodeSize + ifIgnoreOtherSameDir != 0)
System.out.println(" (settings are in the Tools / Routing tab of the Preferences)");
}
}
}
private static List runTheWires(List allRoutes, EditingPreferences ep)
{
// create the routes
List portsToHighlight = new ArrayList();
Map arcsCreatedMap = new HashMap();
Map nodesCreatedMap = new HashMap();
for (Route route : allRoutes)
{
RouteElement re = route.get(0);
Cell c = re.getCell();
Router.createRouteNoJob(route, c, arcsCreatedMap, nodesCreatedMap, ep);
RouteElementPort finalRE = route.getEnd();
if (finalRE != null)
{
PortInst showThis = finalRE.getPortInst();
if (showThis != null) portsToHighlight.add(showThis);
}
}
boolean beep = User.isPlayClickSoundsWhenCreatingArcs();
Router.reportRoutingResults("MIMIC ROUTING", arcsCreatedMap, nodesCreatedMap, beep);
return portsToHighlight;
}
/**
* Class to implement actual wire creation/deletion in a new thread.
*/
private static class MimicWireJob extends Job
{
private List allRoutes;
private List allKills;
private boolean redisplay;
private List portsToHighlight;
private MimicOptions prefs;
private MimicWireJob(List allRoutes, List allKills, boolean redisplay, MimicOptions prefs)
{
super("Mimic-Stitch", Routing.getRoutingTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.allRoutes = allRoutes;
this.allKills = allKills;
this.redisplay = redisplay;
this.prefs = prefs;
if (this.prefs == null)
{
this.prefs = new MimicOptions();
this.prefs.getOptionsFromPreferences();
}
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
if (allRoutes.size() > 0)
{
// create the routes
portsToHighlight = runTheWires(allRoutes, ep);
fieldVariableChanged("portsToHighlight");
} else
{
// delete the arcs
for (ArcInst ai : allKills)
{
NodeInst h = ai.getHeadPortInst().getNodeInst();
NodeInst t = ai.getTailPortInst().getNodeInst();
ai.kill();
// also delete freed pin nodes
if (h.getProto().getFunction().isPin() &&
!h.hasConnections() && !h.hasExports() && !prefs.mimicPinsKept)
{
h.kill();
}
if (t.getProto().getFunction().isPin() &&
!t.hasConnections() && !t.hasExports() && !prefs.mimicPinsKept)
{
t.kill();
}
}
}
return true;
}
@Override
public void terminateOK()
{
if (redisplay)
{
UserInterface ui = Job.getUserInterface();
EditWindow_ wnd = ui.getCurrentEditWindow_();
if (wnd != null)
{
wnd.clearHighlighting();
for(PortInst pi : portsToHighlight)
{
wnd.addElectricObject(pi, pi.getNodeInst().getParent());
}
wnd.finishedHighlighting();
}
ui.repaintAllWindows();
}
}
}
/****************************** INTERACTIVE MIMIC SELECTION ******************************/
/**
* Class to present the next mimic opportunity and let the user choose whether to do it.
* This class runs in the Swing thread.
*/
private static class MimicInteractive implements Runnable
{
private Cell cell;
private List possibleArcs;
private double prefX, prefY;
private MimicInteractive(Cell cell, List possibleArcs, double prefX, double prefY)
{
this.cell = cell;
this.possibleArcs = possibleArcs;
this.prefX = prefX;
this.prefY = prefY;
}
public void run()
{
// interactive mode: show paths before creating arcs
presentNextSituation(0, 0, possibleArcs, cell, prefX, prefY, UserInterfaceMain.getEditingPreferences());
}
}
/**
* Method to interactively present a mimicing situation to the user.
* @param count the number of arcs created so far.
* @param situationNumber the starting "situation" number (class of mimics that are allowed).
* @param possibleArcs a list of possible arcs to route
* @param cell the Cell where routing is going on.
* @param wnd the highlighter window.
* @param prefX preferred X coordinate when arcs bend.
* @param prefY preferred Y coordinate when arcs bend.
* @param ep EditingPreferences
*/
private static void presentNextSituation(int count, int situationNumber, List possibleArcs,
Cell cell, double prefX, double prefY, EditingPreferences ep)
{
// find the next situation
for(int j=situationNumber; j allRoutes = new ArrayList();
List allKills = new ArrayList();
int total = 0;
for(PossibleArc pa : possibleArcs)
{
if (pa.situation != situations[j]) continue;
total++;
if (pa.ai != null)
{
// consider a deletion
allKills.add(pa.ai);
} else
{
// consider a creation
Poly portPoly1 = pa.ni1.getShapeOfPort(pa.pp1);
Poly portPoly2 = pa.ni2.getShapeOfPort(pa.pp2);
Point2D bend = new Point2D.Double((portPoly1.getCenterX() + portPoly2.getCenterX()) / 2 + prefX,
(portPoly1.getCenterY() + portPoly2.getCenterY()) / 2 + prefY);
PortInst pi1 = pa.ni1.findPortInstFromProto(pa.pp1);
PortInst pi2 = pa.ni2.findPortInstFromProto(pa.pp2);
Route route = router.planRoute(pa.ni1.getParent(), pi1, pi2, bend, null, ep, true, true, null, null);
if (route.size() == 0)
{
System.out.println("Problem creating arc");
continue;
}
allRoutes.add(route);
}
}
if (total == 0) continue;
// save what is highlighted
UserInterface ui = Job.getUserInterface();
EditWindow_ wnd = ui.getCurrentEditWindow_();
List saveHighlights = wnd.saveHighlightList();
// show the wires to be created/deleted
wnd.clearHighlighting();
for(Route route : allRoutes)
{
// determine the actual endpoints of the route
Poly sPi = route.getStart().getPortInst().getPoly();
Poly ePi = route.getEnd().getPortInst().getPoly();
double fX = sPi.getCenterX(); double fY = sPi.getCenterY();
double tX = ePi.getCenterX(); double tY = ePi.getCenterY();
if (fX == tX && fY == tY)
{
Rectangle2D pointRect = new Rectangle2D.Double(fX-1, fY-1, 2, 2);
wnd.addHighlightArea(pointRect, cell);
} else
{
wnd.addHighlightLine(new Point2D.Double(fX, fY), new Point2D.Double(tX, tY), cell, false, false);
}
}
for(ArcInst ai : allKills)
{
wnd.addHighlightLine(ai.getHeadLocation().lambdaMutable(), ai.getTailLocation().lambdaMutable(), cell, false, false);
}
wnd.finishedHighlighting();
// ask if the user wants to do it
new MimicDialog(TopLevel.getCurrentJFrame(), count, allRoutes, allKills, saveHighlights, wnd, j+1, possibleArcs, cell, prefX, prefY);
return;
}
// done with all situations: report any arcs created
if (count != 0)
System.out.println("MIMIC ROUTING: Created " + count + " arcs");
}
/**
* Class to handle the "Interactive Mimic" dialog.
*/
private static class MimicDialog extends EDialog
{
private int count;
private List allRoutes;
private List allKills;
private List saveHighlights;
private EditWindow_ wnd;
private int nextSituationNumber;
private List possibleArcs;
private Cell cell;
private double prefX, prefY;
private EditingPreferences ep;
private MimicDialog(Frame parent, int count, List allRoutes, List allKills, List saveHighlights,
EditWindow_ wnd, int nextSituationNumber, List possibleArcs, Cell cell, double prefX, double prefY)
{
super(parent, false);
this.count = count;
this.allRoutes = allRoutes;
this.allKills = allKills;
this.saveHighlights = saveHighlights;
this.wnd = wnd;
this.nextSituationNumber = nextSituationNumber;
this.possibleArcs = possibleArcs;
this.cell = cell;
this.prefX = prefX;
this.prefY = prefY;
ep = UserInterfaceMain.getEditingPreferences();
String activity = (allKills.size() > 0 ? "Delete" : "Create");
getContentPane().setLayout(new GridBagLayout());
setTitle(activity + " wires?");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
JLabel question = new JLabel(activity + " " + (allRoutes.size()+allKills.size()) + " wires shown here?");
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 0;
gbc.gridwidth = 4;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(question, gbc);
JButton yes = new JButton("Yes");
yes.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { yes(); }
});
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 1;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(yes, gbc);
getRootPane().setDefaultButton(yes);
JButton no = new JButton("No");
no.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { no(); }
});
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 1;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(no, gbc);
JButton noAndStop = new JButton("No, and stop");
noAndStop.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { noAndStopActionPerformed(); }
});
gbc = new GridBagConstraints();
gbc.gridx = 2; gbc.gridy = 1;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(noAndStop, gbc);
JButton yesAndStop = new JButton("Yes, then stop");
yesAndStop.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { yesAndStopActionPerformed(); }
});
gbc = new GridBagConstraints();
gbc.gridx = 3; gbc.gridy = 1;
gbc.insets = new Insets(4, 4, 4, 4);
getContentPane().add(yesAndStop, gbc);
pack();
finishInitialization();
setVisible(true);
}
protected void escapePressed() { no(); }
private void yesAndStopActionPerformed()
{
wnd.clearHighlighting();
wnd.restoreHighlightList(saveHighlights);
wnd.finishedHighlighting();
new MimicWireJob(allRoutes, allKills, false, null);
count += allRoutes.size() + allKills.size();
presentNextSituation(count, situations.length, possibleArcs, cell, prefX, prefY, ep);
setVisible(false);
dispose();
}
private void noAndStopActionPerformed()
{
wnd.clearHighlighting();
wnd.restoreHighlightList(saveHighlights);
wnd.finishedHighlighting();
presentNextSituation(count, situations.length, possibleArcs, cell, prefX, prefY, ep);
setVisible(false);
dispose();
}
private void yes()
{
wnd.clearHighlighting();
wnd.restoreHighlightList(saveHighlights);
wnd.finishedHighlighting();
new MimicWireJob(allRoutes, allKills, false, null);
count += allRoutes.size() + allKills.size();
presentNextSituation(count, nextSituationNumber, possibleArcs, cell, prefX, prefY, ep);
setVisible(false);
dispose();
}
private void no()
{
wnd.clearHighlighting();
wnd.restoreHighlightList(saveHighlights);
wnd.finishedHighlighting();
presentNextSituation(count, nextSituationNumber, possibleArcs, cell, prefX, prefY, ep);
setVisible(false);
dispose();
}
}
/**
* Class to package Preferences for the server.
*/
public static class MimicOptions implements Serializable
{
public boolean mimicPinsKept;
public boolean mimicInteractive;
public boolean matchPorts;
public boolean matchPortWidth;
public boolean matchArcCount;
public boolean matchNodeType;
public boolean matchNodeSize;
public boolean noOtherArcsThisDir;
public boolean notAlreadyConnected;
public MimicOptions()
{
mimicPinsKept = false;
mimicInteractive = false;
matchPorts = false;
matchPortWidth = false;
matchArcCount = false;
matchNodeType = true;
matchNodeSize = false;
noOtherArcsThisDir = true;
notAlreadyConnected = true;
}
public void getOptionsFromPreferences()
{
mimicPinsKept = Routing.isMimicStitchPinsKept();
mimicInteractive = Routing.isMimicStitchInteractive();
matchPorts = Routing.isMimicStitchMatchPorts();
matchPortWidth = Routing.isMimicStitchMatchPortWidth();
matchArcCount = Routing.isMimicStitchMatchNumArcs();
matchNodeType = Routing.isMimicStitchMatchNodeType();
matchNodeSize = Routing.isMimicStitchMatchNodeSize();
noOtherArcsThisDir = Routing.isMimicStitchNoOtherArcsSameDir();
notAlreadyConnected = Routing.isMimicStitchOnlyNewTopology();
}
}
}