/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: RoutingArray.java * Written by: Andreas Uebelhoer, Alexander Bieles, Emre Selegin (Team 6) * * Copyright (c) 2010, 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.experimentalLeeMoore1.LeeMoore; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.util.*; import com.sun.electric.database.geometry.ERectangle; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.tool.routing.RoutingFrame.RoutingGeometry; import com.sun.electric.tool.routing.experimentalLeeMoore1.ThreadBorders; import com.sun.electric.tool.routing.experimentalLeeMoore1.yana; /** * class representing the routing grid * array value * =0 free field * =Integer.MIN_VALUE field blocked * >0 field used while Lee-More algorithm * =-1 starting field * =-2 ending field */ public class RoutingArray { public int size_x, size_y, numLayers; private int[][][] array; final int ARRAY_OVERSIZE = 80; // make array bigger than cell so that wires can be routed around final int NET_ID_OFFSET = 10; // change net id when written into the array to avoid conflicts with start and end final int START_POINT = -1; final int END_POINT = -2; final int EMPTY_POINT = 0; final int RESERVED_POINT = Integer.MIN_VALUE + 1; final int BLOCKED_POINT = Integer.MIN_VALUE; double minWidth; private final boolean DEBUG = false; private final boolean USE_MULTI_TERMINAL_ALGORITHM=false; //multiterminal algorithm is not yet doing correct wires in electric /** * set size of array and blocked tupels * @param size_x size in x direction * @param size_y size in y direction * @param numLayers size in z direction * @param blocked blocked tupels */ public RoutingArray(int size_x, int size_y, int numLayers, Tupel[] blocked) { this.size_x = size_x; this.size_y = size_y; this.numLayers = numLayers; array = new int[size_x][size_y][numLayers]; setBlocked(blocked); } /** * set size of array and blocked rectangles * @param c Cell * @param numLayers count of layers * @param blocked blocked RoutingGeometries * @param minWidth width of wires */ public RoutingArray(Cell c, int numLayers, List<RoutingGeometry> blocked, double minWidth) { ERectangle r = c.getBounds(); int distanceBetweenWires = (yana.distanceBetweenWires == 0) ? 3 : yana.distanceBetweenWires; this.size_x = (int) (r.getLambdaWidth() + ARRAY_OVERSIZE) / distanceBetweenWires; this.size_y = (int) (r.getLambdaHeight() + ARRAY_OVERSIZE) / distanceBetweenWires; this.numLayers = numLayers; this.minWidth = minWidth; if (DEBUG) System.out.println("scaling grid from " + (r.getLambdaWidth() + ARRAY_OVERSIZE) + " x " + (r.getLambdaHeight() + ARRAY_OVERSIZE) + " -> " + size_x + " x " + size_y + "\n with scaling factor=" + distanceBetweenWires + " and oversize=" + ARRAY_OVERSIZE); array = new int[size_x][size_y][numLayers]; setBlocked(blocked); } /** * set array element to given value * @param t Tupel representing location * @param val value */ private void setValue(Tupel t, int val) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); array[x][y][l] = val; } /** * Returns array value * @param t Tupel representing location * @return value */ private int getValue(Tupel t){ return array[t.getX_InsideRoutingArray()][t.getY_InsideRoutingArray()][t.getLayer()]; } /** * set array element to given value and check borders so that a thread can't set values that do not belong to its WorkPartition * @param t Tupel representing location * @param val * @param tb */ private void setValue(Tupel t, int val, ThreadBorders tb) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (DEBUG&&(!(tb.getLowIndexX() <= x && x <= tb.getHighIndexX() && tb.getLowIndexY() <= y && y <= tb.getHighIndexY()))) { System.out.println("Thread out of bounds!"); } array[x][y][l] = val; } /** * mark tupels in array as blocked * @param blocked blocked tupels */ public void setBlocked(Tupel[] blocked) { for (int i = 0; i < blocked.length; i++) { setValue(blocked[i], BLOCKED_POINT); } } /** * mark tupels as used using val * @param route tupels to mark * @param val value to use for marking */ private void markUsed(Tupel[] route, int val) { if (DEBUG) { System.out.println("Marking route as used with " + val); } for (int i = 0; i < route.length; i++) { setValue(route[i], val); } } /** * Reserves Tupels for routing. Tupels reserved by two nets are marked as blocked. * @param tupels Tupels to reserve * @param netID segment which reserves tupels */ public void reserveForRouting(Tupel[] tupels, int netID) { for (Tupel tupel : tupels) { int x = tupel.getX_InsideRoutingArray(); int y = tupel.getY_InsideRoutingArray(); int l = tupel.getLayer(); if (array[x][y][l] == 0 || array[x][y][l] == netID) { setValue(tupel, netID); } else { setValue(tupel, BLOCKED_POINT); } } } /** * * @return a list of the blocked and reserved tupels */ public ArrayList<Tupel> getBlocked() { ArrayList<Tupel> blocked = new ArrayList<Tupel>(); for (int i = 0; i < size_x; i++) { for (int j = 0; j < size_y; j++) { for (int k = 0; k < numLayers; k++) { if (array[i][j][k] < 0) { blocked.add(new Tupel(i, j, k, false)); } } } } return blocked; } /** * Set RoutingGeometries as blocked * @param blockages routing geometries */ public void setBlocked(List<RoutingGeometry> blockages) { for (RoutingGeometry rg : blockages) { setBlocked(grow(rg.getBounds(), minWidth), rg.getLayer().getMetalNumber() - 1); } } /** * Grows a rectangle by a given size. * @param r Rectangle * @param size size to grow * @return grown rectangle */ private Rectangle2D grow(Rectangle2D r, double size) { double spacing = size / 2; int x = (int) (r.getX() - spacing); int y = (int) (r.getY() - spacing); int width = (int) Math.floor(r.getWidth() + size); int height = (int) Math.floor(r.getHeight() + size); return new Rectangle(x, y, width, height); } /** * Mark rectangle in array as blocked. Sets only the outer shape as blocked, as inner elements can't be reached * @param r Rectangle * @param layer Layer cotaining blockage */ private void setBlocked(Rectangle2D r, int layer) { int x = (int) r.getX(); int y = (int) r.getY(); int width = (int) Math.floor(r.getWidth()); int height = (int) Math.floor(r.getHeight()); List<Tupel> blocked = new ArrayList<Tupel>(); int h_border = x + width; int v_border = y + height; //horizontal borders for (int i = x; i < h_border; i++) { blocked.add(new Tupel(i, y, layer, true)); blocked.add(new Tupel(i, v_border - 1, layer, true)); } //vertical borders for (int i = y; i < v_border; i++) { blocked.add(new Tupel(x, i, layer, true)); blocked.add(new Tupel(h_border - 1, i, layer, true)); } setBlocked(blocked.toArray(new Tupel[0])); } /** * Mark a found route as blocked. * @param r found route * @param netID id of route */ private void setBlocked(Route r, int netID) { if (r == null) { return; } List<Tupel> l = r.getRoutingList(); markUsed(l.toArray(new Tupel[0]), -1 * (netID + NET_ID_OFFSET)); } /** * Mark points in array around start and end as reserved * @param start start tupel * @param end end tupel * @param border ThreadBorders */ private void createBlockingsAroundStartEnd(Tupel start,Tupel end,ThreadBorders border) { if(isStartEndTupel(start)){ if(getLeftNeighbour(start, border)==EMPTY_POINT){ setValue(leftNeighbour(start),RESERVED_POINT,border); } if(getRightNeighbour(start, border)==EMPTY_POINT){ setValue(rightNeighbour(start),RESERVED_POINT,border); } if(getTopNeighbour(start, border)==EMPTY_POINT){ setValue(topNeighbour(start),RESERVED_POINT,border); } if(getBottomNeighbour(start, border)==EMPTY_POINT){ setValue(bottomNeighbour(start),RESERVED_POINT,border); } } if (isStartEndTupel(end)) { if (getLeftNeighbour(end, border) == EMPTY_POINT) { setValue(leftNeighbour(end), RESERVED_POINT, border); } if (getRightNeighbour(end, border) == EMPTY_POINT) { setValue(rightNeighbour(end), RESERVED_POINT, border); } if (getTopNeighbour(end, border) == EMPTY_POINT) { setValue(topNeighbour(end), RESERVED_POINT, border); } if (getBottomNeighbour(end, border) == EMPTY_POINT) { setValue(bottomNeighbour(end), RESERVED_POINT, border); } } } /** * delete all temporary created routing values * @param tb ThreadBorders */ private void clearRouting(ThreadBorders tb) { for (int i = tb.getLowIndexX(); i <= tb.getHighIndexX(); i++) { for (int j = tb.getLowIndexY(); j <= tb.getHighIndexY(); j++) { for (int k = 0; k < numLayers; k++) { if (array[i][j][k] > 0) { array[i][j][k] = EMPTY_POINT; } else if (array[i][j][k] < 0 && array[i][j][k] > -3) { //start and end point may not be used array[i][j][k] = BLOCKED_POINT; } } } } //checkClearing(tb); } // //DEBUG // private void checkClearing(ThreadBorders tb) { // for (int i = tb.getLowIndexX(); i <= tb.getHighIndexX(); i++) { // for (int j = tb.getLowIndexY(); j <= tb.getHighIndexY(); j++) { // for (int k = 0; k < numLayers; k++) { // if (array[i][j][k] == END_POINT || array[i][j][k] == START_POINT || array[i][j][k] > EMPTY_POINT) { // if(DEBUG)System.out.println("Clearing not successful!"); // } // } // } // } // } /** * this method is only used for compability with single threaded algorithm * @param start * @param end * @param netID * @return */ @Deprecated public Route route(Tupel start, Tupel end, int netID) { ThreadBorders border = new ThreadBorders(0, array.length - 1, 0, array[0].length - 1); return route(start, end, border, netID); } /** * Start routing between start and end in given borders * @param start start point * @param end end point * @param border border to route in * @param netID id of the route * @return */ public Route route(Tupel start, Tupel end, ThreadBorders border, int netID) { if(start.isEqualPosition(end)){ //TODO: isEqualPosition doesn't check on same layer. return null too conservative? if(DEBUG)System.out.println("START==END! => Length of wire==0..."); return null; } boolean useMultiTerminalAlgorithm; if (USE_MULTI_TERMINAL_ALGORITHM) { if (getValue(start) > RESERVED_POINT) { //start point was already routed once, multiterminal algorithm can not use it as start point if (getValue(end) > RESERVED_POINT) { //same for end point, so don't use multiterminal algorithm useMultiTerminalAlgorithm = false; } else { //switch start and end point Tupel temp = start; start = end; end = temp; useMultiTerminalAlgorithm = true; } } else { //none of the points was already routed once so don't use multiterminal algorithm to make sure that both will be connected useMultiTerminalAlgorithm = false; } } else { useMultiTerminalAlgorithm = false; } prepareStartEndPoint(start, end, border); Queue<Tupel> start_queue = new LinkedList<Tupel>(); start_queue.offer(start); start_queue.offer(null); SearchResult res = search(start_queue, border, end, -1 * (netID + NET_ID_OFFSET), useMultiTerminalAlgorithm); int length = res.getLength(); Tupel foundEnd = res.getFoundEnd(); if (length >= 0) { Route r = new Route(); r.setReversed(useMultiTerminalAlgorithm); //create a new Tupel out of routing array coordinates so that wiring algorithm can calculate rectangular wires to the end point r.addFieldInFront(new Tupel(foundEnd.getX_InsideRoutingArray(), foundEnd.getY_InsideRoutingArray(), foundEnd.getLayer(), false)); r = trace(r, length, border); setBlocked(r, netID); if (DEBUG) { r.printRoute(r.getEdgePoints()); } clearRouting(border); createBlockingsAroundStartEnd(start, end, border); //this is only needed if route was found return r; } else { if (DEBUG) { System.out.println("Routing from " + start.toString() + " to " + end.toString() + " (netID=" + netID + ") in borders " + border.toString() + " has no solution!"); } clearRouting(border); return null; } } /** * Mark points around start and end as free if they are reserved. * @param start start point * @param end end point * @param border border of routing */ private void prepareStartEndPoint(Tupel start, Tupel end, ThreadBorders border) { setValue(start, START_POINT, border); //prepare neighbours (were marked as reserved) if start point is original start point of a routing segment if (isStartEndTupel(start)) { if (getLeftNeighbour(start, border) == RESERVED_POINT) { setValue(leftNeighbour(start), EMPTY_POINT, border); } if (getRightNeighbour(start, border) == RESERVED_POINT) { setValue(rightNeighbour(start), EMPTY_POINT, border); } if (getTopNeighbour(start, border) == RESERVED_POINT) { setValue(topNeighbour(start), EMPTY_POINT, border); } if (getBottomNeighbour(start, border) == RESERVED_POINT) { setValue(bottomNeighbour(start), EMPTY_POINT, border); } } setValue(end, END_POINT, border); //same for end point if(isStartEndTupel(end)){ if(getLeftNeighbour(end, border)==RESERVED_POINT){ setValue(leftNeighbour(end),EMPTY_POINT,border); } if(getRightNeighbour(end, border)==RESERVED_POINT){ setValue(rightNeighbour(end),EMPTY_POINT,border); } if(getTopNeighbour(end, border)==RESERVED_POINT){ setValue(topNeighbour(end),EMPTY_POINT,border); } if(getBottomNeighbour(end, border)==RESERVED_POINT){ setValue(bottomNeighbour(end),EMPTY_POINT,border); } } } /** * Return whether the given tupel is a start or end point. * In this case the conversion between Electric coordinates to routing array coordinates and back again should give another result. * @param t Tupel to check * @return whether Tupel t is a start or end point of a routing segment */ private boolean isStartEndTupel(Tupel t){ return (t.getX_InsideElectric()!=Tupel.convertRoutingArrayToElectricCoordinates_X(t.getX_InsideRoutingArray())) ||t.getY_InsideElectric()!=Tupel.convertRoutingArrayToElectricCoordinates_Y(t.getY_InsideRoutingArray()); } /** * Trace up route marked by search * @param r route to save the result in * @param length length of the route to find * @param b borders to trace in * @return */ private Route trace(Route r, int length, ThreadBorders b) { if (DEBUG) { System.out.println("Length: " + length); } while (true) { Tupel t = r.getFirstTupel(); // starting field is reached if (length == -2) { return r; } // adapt search value for search of starting element if (length == 0) { length = START_POINT; } if ((t.getLayer() % 2) == 0) { // check neighbours // left neighbour if (getLeftNeighbour(t, b) == length) { r.addFieldInFront(leftNeighbour(t)); length--; continue; } // right neighbour if (getRightNeighbour(t, b) == length) { r.addFieldInFront(rightNeighbour(t)); length--; continue; } } else { // top neighbour if (getTopNeighbour(t, b) == length) { r.addFieldInFront(topNeighbour(t)); length--; continue; } // lower neighbour if (getBottomNeighbour(t, b) == length) { r.addFieldInFront(bottomNeighbour(t)); length--; continue; } } // layer up neighbour if (getLayerUpNeighbour(t) == length) { r.addFieldInFront(layerUpNeighbour(t)); length--; continue; } // layer down neighbour if (getLayerDownNeighbour(t) == length) { r.addFieldInFront(layerDownNeighbour(t)); length--; continue; } //no neighbour was found if(DEBUG)System.out.println("ERROR IN TRACE: no neighbour was found!"); printNeighbourhood(b, t); if(DEBUG)System.out.println("Route so far: "); if(DEBUG)r.printRoute(); //printArrayNonZero(b,length); if(DEBUG)System.out.println(); } } //DEBUG private void printNeighbourhood(ThreadBorders b, Tupel t) { if(DEBUG) return; System.out.println("Neighbourhood around " + t); System.out.println("left: " + getLeftNeighbour(t, b)); System.out.println("right: " + getRightNeighbour(t, b)); System.out.println("top: " + getTopNeighbour(t, b)); System.out.println("bottom: " + getBottomNeighbour(t, b)); System.out.println("layerup: " + getLayerUpNeighbour(t)); System.out.println("layerdown: " + getLayerDownNeighbour(t)); System.out.println("self: " + array[t.getX_InsideRoutingArray()][t.getY_InsideRoutingArray()][t.getLayer()]); } /** * Search for a route to tupel end. * @param queue queue already containing start tupel * @param b borders in which it should search * @param end tupel to find * @param netID id oft the net * @param multiTerminal use multiterminal algorithm * @return SearchResult (length and found tupel) */ private SearchResult search(Queue<Tupel> queue, ThreadBorders b, Tupel end, int netID, boolean multiTerminal) { int val = 1; Tupel foundEnd = null; boolean found = false; while (!found) { Tupel t = queue.poll(); //null object means that value has to be incremented if (t == null) { if (queue.size() == 0) { //System.out.println("No solution found!"); return new SearchResult(end, -1); } queue.offer(null); val++; //printArray(); continue; } int neighbourValue; if ((t.getLayer() % 2) == 0) { //check neighbours //left neighbour neighbourValue = getLeftNeighbour(t, b); switch (neighbourValue) { case START_POINT: break; //starting point: do nothing case END_POINT: //end point: route found found = true; foundEnd = leftNeighbour(t); break; case EMPTY_POINT: Tupel neighbour = leftNeighbour(t); queue.offer(neighbour); setValue(neighbour, val, b); //mark as visited break; default: if (multiTerminal && neighbourValue == netID) { found = true; foundEnd = leftNeighbour(t); } break; //already visited or blocked } //right neighbour neighbourValue = getRightNeighbour(t, b); switch (neighbourValue) { case START_POINT: break; //starting point: do nothing case END_POINT: //end point: route found found = true; foundEnd = rightNeighbour(t); break; case EMPTY_POINT: Tupel neighbour = rightNeighbour(t); queue.offer(neighbour); setValue(neighbour, val, b); //mark as visited break; default: if (multiTerminal && neighbourValue == netID) { found = true; foundEnd = rightNeighbour(t); } break; //already visited or blocked } } else { //top neighbour neighbourValue = getTopNeighbour(t, b); switch (neighbourValue) { case START_POINT: break; //starting point: do nothing case END_POINT: //end point: route found found = true; foundEnd = topNeighbour(t); break; case EMPTY_POINT: Tupel neighbour = topNeighbour(t); queue.offer(neighbour); setValue(neighbour, val, b); //mark as visited break; default: if (multiTerminal && neighbourValue == netID) { found = true; foundEnd = topNeighbour(t); } break; //already visited or blocked } //lower neighbour neighbourValue = getBottomNeighbour(t, b); switch (neighbourValue) { case START_POINT: break; //starting point: do nothing case END_POINT: //end point: route found found = true; foundEnd = bottomNeighbour(t); break; case EMPTY_POINT: Tupel neighbour = bottomNeighbour(t); queue.offer(neighbour); setValue(neighbour, val, b); //mark as visited break; default: if (multiTerminal && neighbourValue == netID) { found = true; foundEnd = bottomNeighbour(t); } break; //already visited or blocked } } //layer up neighbour neighbourValue = getLayerUpNeighbour(t); switch (neighbourValue) { case START_POINT: break; //starting point: do nothing case END_POINT: //end point: route found found = true; foundEnd = layerUpNeighbour(t); break; case EMPTY_POINT: Tupel neighbour = layerUpNeighbour(t); queue.offer(neighbour); setValue(neighbour, val, b); //mark as visited break; default: if (multiTerminal && neighbourValue == netID) { found = true; foundEnd = layerUpNeighbour(t); } break; //already visited or blocked } //layer down neighbour neighbourValue = getLayerDownNeighbour(t); switch (neighbourValue) { case START_POINT: break; //starting point: do nothing case END_POINT: //end point: route found found = true; foundEnd = layerDownNeighbour(t); break; case EMPTY_POINT: Tupel neighbour = layerDownNeighbour(t); queue.offer(neighbour); setValue(neighbour, val, b); //mark as visited break; default: if (multiTerminal && neighbourValue == netID) { found = true; foundEnd = layerDownNeighbour(t); } break; //already visited or blocked } if (found) { if (!foundEnd.isEqual(end)) { if(DEBUG)System.out.println("INFO: Multiterminal algorithm used."); } if (val == 1) { if(DEBUG)System.out.println("ERROR: Length of route is 0!"); } return new SearchResult(foundEnd, val - 1); } } if(DEBUG)System.out.println("ERROR: Reached anreachable statement!"); //should never be reached return new SearchResult(end, -1); } /** * Return value of left neighbour * @param t tupel which neighbours to check * @param b borders * @return value of left neighbour or blocked if out of borders */ private int getLeftNeighbour(Tupel t, ThreadBorders b) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (x > b.getLowIndexX()) { return array[x - 1][y][l]; } else { return BLOCKED_POINT; } } /** * Return value of right neighbour * @param t tupel which neighbours to check * @param b borders * @return value of right neighbour or blocked if out of borders */ private int getRightNeighbour(Tupel t, ThreadBorders b) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (x < b.getHighIndexX()) { return array[x + 1][y][l]; } else { return BLOCKED_POINT; } } /** * Return value of bottom neighbour * @param t tupel which neighbours to check * @param b borders * @return value of bottom neighbour or blocked if out of borders */ private int getBottomNeighbour(Tupel t, ThreadBorders b) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (y > b.getLowIndexY()) { return array[x][y - 1][l]; } else { return BLOCKED_POINT; } } /** * Return value of top neighbour * @param t tupel which neighbours to check * @param b borders * @return value of top neighbour or blocked if out of borders */ private int getTopNeighbour(Tupel t, ThreadBorders b) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (y < b.getHighIndexY()) { return array[x][y + 1][l]; } else { return BLOCKED_POINT; } } /** * Return value of layer up neighbour * @param t tupel which neighbours to check * @param b borders * @return value of layer up neighbour or blocked if out of borders */ private int getLayerUpNeighbour(Tupel t) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (l < array[0][0].length - 1) { return array[x][y][l + 1]; } else { return BLOCKED_POINT; } } /** * Return value of layer down neighbour * @param t tupel which neighbours to check * @param b borders * @return value of layer down neighbour or blocked if out of borders */ private int getLayerDownNeighbour(Tupel t) { int x = t.getX_InsideRoutingArray(); int y = t.getY_InsideRoutingArray(); int l = t.getLayer(); if (l > 0) { return array[x][y][l - 1]; } else { return BLOCKED_POINT; } } /** * Return tupel left to the given one * @param t Tupel * @return left neighbour */ private Tupel leftNeighbour(Tupel t) { return new Tupel(t.getX_InsideRoutingArray() - 1, t.getY_InsideRoutingArray(), t.getLayer(), false); } /** * Return tupel right to the given one * @param t Tupel * @return right neighbour */ private Tupel rightNeighbour(Tupel t) { return new Tupel(t.getX_InsideRoutingArray() + 1, t.getY_InsideRoutingArray(), t.getLayer(), false); } /** * Return upper tupel to the given one * @param t Tupel * @return top neighbour */ private Tupel topNeighbour(Tupel t) { return new Tupel(t.getX_InsideRoutingArray(), t.getY_InsideRoutingArray() + 1, t.getLayer(), false); } /** * Return lower tupel to the given one * @param t Tupel * @return bottom neighbour */ private Tupel bottomNeighbour(Tupel t) { return new Tupel(t.getX_InsideRoutingArray(), t.getY_InsideRoutingArray() - 1, t.getLayer(), false); } /** * Return tupel a layer up to the given one * @param t Tupel * @return layer up neighbour */ private Tupel layerUpNeighbour(Tupel t) { return new Tupel(t.getX_InsideRoutingArray(), t.getY_InsideRoutingArray(), t.getLayer() + 1, false); } /** * Return tupel a layer down to the given one * @param t Tupel * @return layer down neighbour */ private Tupel layerDownNeighbour(Tupel t) { return new Tupel(t.getX_InsideRoutingArray(), t.getY_InsideRoutingArray(), t.getLayer() - 1, false); } /** * This class represents a result returned by search. It contains the length and the found tupel. * (This tupel is only different if multiterminal is true, which is not by default) * @author Andreas * */ class SearchResult{ Tupel foundEnd; int length; public Tupel getFoundEnd() { return foundEnd; } public int getLength() { return length; } public SearchResult(Tupel foundEnd, int length) { super(); this.foundEnd = foundEnd; this.length = length; } } /** * Converts initial reservations of start and end points with their netID to the representation needed by algorithm. */ public void markReserved() { for (int i = 0; i < array.length; i++) { for (int j = 0; j < array[0].length; j++) { for (int k = 0; k < numLayers; k++) { if (array[i][j][k] > 0) { array[i][j][k] = RESERVED_POINT; } } } } } }