com.sun.electric.tool.routing.Route Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Route.java
*
* 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.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.sun.electric.database.geometry.PolyMerge;
import com.sun.electric.database.hierarchy.Cell;
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;
/**
* Specifies a route to be created. Note that the order if items
* in a route is meaningless. The only thing that specifies order is the
* start and end of the route.
*
* Author: gainsley
*/
public class Route extends ArrayList {
private RouteElementPort routeStart; // start of route
private RouteElementPort routeEnd; // end of route
private boolean routeReversed; // if the route has been reversed
// ---------------------- Constructors ---------------------------
/** Constructs an empty route */
public Route() {
super();
routeStart = null;
routeEnd = null;
routeReversed = false;
}
/** Constructs a route containing the elements of the passed route,
* in the order they are returned by the route iterator, and having
* the same start and end RouteElement (if Collection is a Route).
*/
public Route(Collection c) {
super(c);
if (c instanceof Route) {
Route r = (Route)c;
routeStart = r.getStart();
routeEnd = r.getEnd();
} else {
routeStart = null;
routeEnd = null;
}
}
// ------------------------------- Route Methods -----------------------------------
// public RouteElement get(int index) {
// // return get(index);
// int count = 0;
// for (Iterator it = iterator(); it.hasNext();)
// {
// if (count == index) return it.next();
// count++;
// }
// return null;
// }
/** Sets the start of the Route */
public void setStart(RouteElementPort startRE) {
if (!contains(startRE)) {
add(startRE);
//System.out.println("Route.setStart Error: argument not part of list");
//return;
}
routeStart = startRE;
}
/** Get the start of the Route */
public RouteElementPort getStart() { return routeStart; }
/** Sets the end of the Route */
public void setEnd(RouteElementPort endRE) {
if (!contains(endRE)) {
add(endRE);
//System.out.println("Route.setEnd Error: argument not part of list");
//return;
}
routeEnd = endRE;
}
/** Get the end of the Route */
public RouteElementPort getEnd() { return routeEnd; }
/**
* Reverse the Route. This just swaps and the start and end
* RouteElements, because the order of the list does not matter.
*/
public void reverseRoute() {
RouteElementPort re = routeStart;
routeStart = routeEnd;
routeEnd = re;
routeReversed = !routeReversed;
}
/** True if the route is reversed, false if it is not reversed */
public boolean isRouteReversed() { return routeReversed; }
/**
* Attempts to replace pin with replacement. See replaceBisectPin and
* replaceExistingRedundantPin for details.
* @param pin the pin to replace
* @param replacement the replacement
* @param stayInside a polygonal area in which the new arc must reside (if not null).
* @param ep EditingPreferences with default sizes
* @return true if any replacement done, false otherwise.
*/
public boolean replacePin(RouteElementPort pin, RouteElementPort replacement, PolyMerge stayInside, EditingPreferences ep) {
if (replaceBisectPin(pin, replacement)) return true;
if (replaceExistingRedundantPin(pin, replacement, stayInside, ep)) return true;
return false;
}
/**
* Attempts to replace the bisectPin by replacement. Returns true
* if any replacements done, and bisect pin is no longer used.
* otherwise returns false. This method currently requires both
* bisectPin and replacement to be part of this Route when this
* method is called.
* @param bisectPin the port pin to replace
* @param replacement the port pin to replace bisectPin with.
* @return true if any replacements done and bisectPin no longer used,
* false otherwise.
*/
public boolean replaceBisectPin(RouteElementPort bisectPin, RouteElementPort replacement) {
if (!bisectPin.isBisectArcPin()) return false;
assert(contains(bisectPin));
boolean success = true;
for (Iterator it = iterator(); it.hasNext(); ) {
RouteElement re = it.next();
if (re instanceof RouteElementArc) {
RouteElementArc reArc = (RouteElementArc)re;
if (!reArc.replaceArcEnd(bisectPin, replacement))
success = false; // reArc still contains reference to bisectPin
}
}
return success;
}
/**
* Attempts to replace an existing pin that has been made redundant by
* some node in the route, such as a contact cut. If replacable, all
* arcs that used to connect to the pin will connect to the replacement node.
* Note that this does not remove pinRE from the route, nor does it add
* replacementRE.
* @param pinRE the pin to replace
* @param replacementRE the replacement
* @param stayInside a polygonal area in which the new arc must reside (if not null).
* @param ep EditingPreferences with default sizes
* @return true if replacement done, false otherwise.
*/
public boolean replaceExistingRedundantPin(RouteElementPort pinRE, RouteElementPort replacementRE, PolyMerge stayInside, EditingPreferences ep) {
// only replace existing pins
if (pinRE.getAction() != RouteElement.RouteElementAction.existingPortInst) return false;
PortInst pi = pinRE.getPortInst();
NodeInst ni = pi.getNodeInst();
// only replace pins
if (!ni.getProto().getFunction().isPin()) return false;
// if the pins is exported, do not replace
if (pi.getExports().hasNext()) return false;
List newElements = new ArrayList();
Cell cell = replacementRE.getCell();
boolean replace = true;
// Iterator it2 = pi.getConnections();
// if there are no connections, check if it's at the same location
if (!pi.hasConnections()) {
// if (!it2.hasNext()) {
if (!ni.getTrueCenter().equals(replacementRE.getLocation()))
return false;
}
// if any connection cannot be remade to replacement, abort
for (Iterator it = pi.getConnections(); it.hasNext(); ) {
Connection conn = it.next();
if (replacementRE.getPortProto().connectsTo(conn.getArc().getProto())) {
// possible to connect, check location
if (conn.getLocation().equals(replacementRE.getLocation())) {
// can reconnect
// get other end point connection
ArcInst ai = conn.getArc();
int otherEnd = 1 - conn.getEndIndex();
// Connection otherConn = ai.getHead();
// if (otherConn == conn) otherConn = ai.getTail();
RouteElementPort otherPort = RouteElementPort.existingPortInst(ai.getPortInst(otherEnd),
ai.getPortInst(otherEnd).getPoly(), ep);
// build new arc
RouteElementArc newArc;
if (conn.getEndIndex() == 1) {
// head
newArc = RouteElementArc.newArc(cell, ai.getProto(),
ai.getLambdaBaseWidth(), replacementRE, otherPort,
conn.getLocation(), ai.getLocation(otherEnd), ai.getName(),
ai.getTextDescriptor(ArcInst.ARC_NAME), ai, ai.isHeadExtended(), ai.isTailExtended(), stayInside);
} else {
// tail
newArc = RouteElementArc.newArc(cell, ai.getProto(),
ai.getLambdaBaseWidth(), otherPort, replacementRE,
ai.getLocation(otherEnd), conn.getLocation(), ai.getName(),
ai.getTextDescriptor(ArcInst.ARC_NAME), ai, ai.isHeadExtended(), ai.isTailExtended(), stayInside);
}
newArc.setArcAngle(ai.getAngle());
RouteElementArc delArc = RouteElementArc.deleteArc(ai, ep);
newElements.add(newArc);
newElements.add(delArc);
} else {
replace = false;
break;
}
} else {
replace = false;
break;
}
}
if (replace) {
//System.out.println("Replacing "+pinRE+" with "+replacementRE);
RouteElementPort delPort = RouteElementPort.deleteNode(ni, ep);
add(delPort);
for (RouteElement e : newElements) {
add(e);
}
}
return replace;
}
}