/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Goal.java * Written by: Christian Julg, Jonas Thedering (Team 1) * * 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.experimentalAStar1; import java.util.List; /** * Gives the A* movement information to AStarWorker to direct the routing * * @author Jonas Thedering * @author Christian Jülg */ public class Goal { private boolean DEBUG = false; int[] startX, startY; int[] finishX, finishY; int currentStartZ = -1, currentFinishZ = -1; int index = -1; private Net net; private Map map; private int scalingFactor; // These values are for the case left/below, so right and above cases have to shift the values private static final int[] xValuesArea = new int[]{-1, 0, -1, 0}; private static final int[] yValuesArea = new int[]{-1, -1, 0, 0}; private static final int[] xValuesSurrounding = new int[]{-2, -1, 0, 1, -2, 1, -2, 1, -2, -1, 0, 1}; private static final int[] yValuesSurrounding = new int[]{-2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 1, 1}; //TODO: optimize this value to reflect actual cost during manufacturing public static final int LAYER_TRAVERSL_COST = 20; public Goal(Net net, Map map) { List<Path> paths = net.getPaths(); int n = paths.size(); startX = new int[n]; startY = new int[n]; finishX = new int[n]; finishY = new int[n]; this.net = net; this.map = map; //currently scalingFactors are assumed to be integer-aligned this.scalingFactor = (int) map.getScalingFactor(); for (int i = 0; i < n; ++i) { startX[i] = paths.get(i).startX; startY[i] = paths.get(i).startY; finishX[i] = paths.get(i).finishX; finishY[i] = paths.get(i).finishY; } DEBUG &= AStarRoutingFrame.getInstance().isOutputEnabled(); if (DEBUG) { // System.out.printf("Goal: finishLoc is (%2.1f : %2.1f)\n", // finishLoc.getX(), finishLoc.getY()); for (int i = 0; i < paths.size(); i++) { System.out.printf("Goal: finishX/Y/Z is (%d : %d), dispX:%d, dispY:%d\n", finishX[i], finishY[i], map.getDispX(), map.getDispY()); } } } /** @return true if the given position is inside the area of the start or finish point of segment i */ private boolean insideStartOrFinishArea(int x, int y, int z, int i) { Path path = net.getPaths().get(i); int startDiffX = path.startRight ? 1 : 0; int startDiffY = path.startAbove ? 1 : 0; int finishDiffX = path.finishRight ? 1 : 0; int finishDiffY = path.finishAbove ? 1 : 0; return (x >= startX[i]-1+startDiffX && x <= startX[i]+startDiffX && y >= startY[i]-1+startDiffY && y <= startY[i]+startDiffY) || (x >= finishX[i]-1+finishDiffX && x <= finishX[i]+finishDiffX && y >= finishY[i]-1+finishDiffY && y <= finishY[i]+finishDiffY); } /** @return true if the given move is allowed */ public boolean isTileOK(int fromX, int fromY, int fromZ, int toX, int toY, int toZ) { int netID = net.getNetID(); int fromStatus = map.getStatus(fromX, fromY, fromZ); int toStatus = map.getStatus(toX, toY, toZ); if(fromStatus == Map.CLEAR && toStatus == Map.CLEAR) return true; else if((fromStatus == netID && (toStatus == Map.CLEAR || toStatus == netID)) || (toStatus == netID && (fromStatus == Map.CLEAR || fromStatus == netID))) { // ensure netIDs >0 for this to be reliable! // Are we in our own end area? if(insideStartOrFinishArea(toX, toY, toZ, index) || insideStartOrFinishArea(fromX, fromY, fromZ, index)) return toZ == fromZ; for(int i = 0; i < net.getPaths().size(); ++i) { // Are we inside the area of an end we don't possess? if(i == index) continue; if(insideStartOrFinishArea(toX, toY, toZ, i) || insideStartOrFinishArea(fromX, fromY, fromZ, i)) return false; } // We are outside of end areas return true; } else return false; } /** @return the cost for the given move */ public int getTileCost(int fromX, int fromY, int fromZ, int toX, int toY, int toZ) { return scalingFactor * ( Math.abs(toX - fromX) + Math.abs(toY - fromY) ) + LAYER_TRAVERSL_COST * Math.abs(toZ - fromZ); } /** @return an estimate for the cost to reach the finish from the given position */ public int distanceToGoal(int x, int y, int z) { return scalingFactor * (Math.abs(finishX[index] - x) + Math.abs(finishY[index] - y)) + LAYER_TRAVERSL_COST*Math.abs(currentFinishZ - z); } /** @return true if the given position is the finish position */ public boolean isFinishPosition(int x, int y, int z) { return (x == finishX[index]) && (y == finishY[index]) && (z == currentFinishZ); } /** * used by worker for debug, to find out if finish has been overwritten */ public int getFinishPositionStatus() { return map.getStatus(finishX[index], finishY[index], currentFinishZ); } /** Switches to the next segment to route and returns the corresponding start coordinates */ public int[] getNextStart() { String debug = ""; do { debug += index+" "; assert index < (startX.length - 1) : debug+"/"+startX.length; ++index; } while (net.pathDone[index]); Path path = net.getPaths().get(index); int maxStartOpenness = -1; currentStartZ = -1; for(int i=0; i < path.startZ.length; ++i) { int openness = getSurroundingOpenness(path.startX, path.startY, path.startZ[i], path.startRight, path.startAbove); if(openness > maxStartOpenness) { currentStartZ = path.startZ[i]; maxStartOpenness = openness; } } int maxFinishOpenness = -1; currentFinishZ = -1; for(int i=0; i < path.finishZ.length; ++i) { int openness = getSurroundingOpenness(path.finishX, path.finishY, path.finishZ[i], path.finishRight, path.finishAbove); if(path.finishZ[i] == currentStartZ && Math.abs(path.finishX - path.startX) <= 1 && Math.abs(path.finishY - path.startY) <= 1) { // Start and finish are too close together, only use this layer if we must openness = 0; } if(openness > maxFinishOpenness) { currentFinishZ = path.finishZ[i]; maxFinishOpenness = openness; } } return new int[] { startX[index], startY[index], currentStartZ}; } /** @return true if all segments have been routed */ public boolean isRoutingComplete() { for (int i = index+1; i < net.pathDone.length; i++) { if (!net.pathDone[i]) return false; } return true; } /** Counts the free points around the given endpoint and checks for dangerous overlaps */ private int getSurroundingOpenness(int x, int y, int z, boolean right, boolean above) { int diffX = right ? 1 : 0; int diffY = above ? 1 : 0; for(int i=0; i < 4; ++i) { int testX = x + xValuesArea[i] + diffX; int testY = y + yValuesArea[i] + diffY; for(int j = 0; j < net.getPaths().size(); ++j) { // Are we inside the area of an end we don't possess? if(j == index) continue; if(insideStartOrFinishArea(testX, testY, z, j)) { Path otherPath = net.getPaths().get(j); if(!(otherPath.startX == startX[index] && otherPath.startY == startY[index]) && !(otherPath.finishX == startX[index] && otherPath.finishY == startY[index]) && !(otherPath.startX == finishX[index] && otherPath.startY == finishY[index]) && !(otherPath.finishX == finishX[index] && otherPath.finishY == finishY[index])) { // We would overlap with another endpoint's area, avoid this! return 0; } } } } int sum = 0; for(int i=0; i < 12; ++i) { int status = map.getStatus(x + xValuesSurrounding[i] + diffX, y + yValuesSurrounding[i] + diffY, z); if(status == Map.CLEAR || status == net.getNetID()) ++sum; } return sum; } }