/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: AStarRegionMachine.java * Written by: Christian Harnisch, Ingo Besenfelder, Michael Neumann (Team 3) * * 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.experimentalAStar2.machine; import java.util.List; import com.sun.electric.tool.routing.experimentalAStar2.algorithm.AStar; import com.sun.electric.tool.routing.experimentalAStar2.algorithm.AStarGoalBase; import com.sun.electric.tool.routing.experimentalAStar2.algorithm.AStarMapBase; import com.sun.electric.tool.routing.experimentalAStar2.algorithm.AStarMapVisitorBase; import com.sun.electric.tool.routing.experimentalAStar2.algorithm.AStarNode; import com.sun.electric.tool.routing.experimentalAStar2.algorithm.AStarRegionNode; import com.sun.electric.tool.routing.experimentalAStar2.memorymanager.ObjectPool; import com.sun.electric.tool.routing.experimentalAStar2.storage.AStarClosedListReferencing; import com.sun.electric.tool.routing.experimentalAStar2.storage.AStarOpenListCheapList; public class AStarRegionMachine implements AStarMachine<AStarRegionNode>, AStarMapVisitorBase<AStarRegionNode> { private ObjectPool<AStarRegionNode> nodePool; private AStarOpenListCheapList<AStarRegionNode> openList; private AStarClosedListReferencing<AStarRegionNode> closedList; private AStarMapBase<AStarRegionNode> map = null; private AStarGoalBase<AStarRegionNode> goal = null; public AStarRegionMachine(ObjectPool<AStarRegionNode> nodePool) { this.nodePool = nodePool; this.openList = new AStarOpenListCheapList<AStarRegionNode>(); this.closedList = new AStarClosedListReferencing<AStarRegionNode>(); } /* * (non-Javadoc) * * @see * com.sun.electric.tool.routing.astar.t3.machine.AStarMachine#findPath(int, * int, int, int, int, int) */ public List<AStarRegionNode> findPath(int startX, int startY, int startZ, int goalX, int goalY, int goalZ) { if (map == null) throw new IllegalStateException("The searched map must be specified before path search can be done."); if (this.goal == null) throw new IllegalStateException("The goal object must be specified before path search can be done."); AStarRegionNode startRegion = map.nodeAt(startX, startY, startZ); AStarRegionNode goalRegion = map.nodeAt(goalX, goalY, goalZ); assert (startRegion != null); assert (goalRegion != null); this.goal.setGoalNode(goalRegion); int goalDistance = this.goal.distanceToGoal(startX, startY, startZ); goalRegion.initialize(null, goalDistance, 0, goalDistance, goalX, goalY, goalZ); startRegion.initialize(null, 0, goalDistance, goalDistance, startX, startY, startZ); // openList.clearOpenList(); // closedList.clearClosedList(); openList.addNodeToOpenList(startRegion); return AStar.findPath(openList, closedList, map, this.goal, nodePool, this); } /* * (non-Javadoc) * * @see * com.sun.electric.tool.routing.astar.t3.machine.AStarMachine#setUpSearchSpace * (com.sun.electric.tool.routing.astar.t3.algorithm.AStarMapBase, * com.sun.electric.tool.routing.astar.t3.algorithm.AStarGoalBase) */ public void setUpSearchSpace(AStarMapBase<AStarRegionNode> newMap, AStarGoalBase<AStarRegionNode> newGoal) { if (newMap == null) throw new IllegalArgumentException("The map to search may not be null."); if (newGoal == null) throw new IllegalArgumentException("The goal object may not be null."); this.map = newMap; openList.setMap(map); closedList.setMap(map); this.goal = newGoal; this.goal.setNodeStorage(this.openList); } /** * Searches are done in a bounding rectangle around start and goal region, and * on a limited number of layers.<br> * By default, this rectangle and the number of layers is minimal. With * setting the margin width to non-zero, an additional margin of regions and * layers is used for search.<br> * It is also possible to define a minimum number of additional layers. This * is usefol to ensure that routing may switch to other layers, even when * start and end node are located on the same. * * @param marginWidth The new margin width. * @param minimumLayerMargin The new number of additional layers to use. */ /* * public void setMarginWidth(int marginWidth, int minimumLayerMargin) { if * (marginWidth < 0) throw new * IllegalArgumentException("Margin width must be greater or equal 0, but was " * + marginWidth); if (minimumLayerMargin < 0) throw new * IllegalArgumentException * ("Minimum layer margin must be greater or equal 0, but was " + * minimumLayerMargin); } */ /* * (non-Javadoc) * * @seecom.sun.electric.tool.routing.astar.t3.algorithm.AStarMapVisitorBase# * visitNeighbour * (com.sun.electric.tool.routing.astar.t3.algorithm.AStarNodeBase, int, int, * int) */ public void visitNeighbour(AStarRegionNode origin, int x, int y, int z) { // If there's no capacity into this direction, don't visit. if (origin.getX() == x) if ((!origin.isTerminalRegion() && origin.getVerticalCapacity() == 0) || (!map.nodeAt(x, y, z).isTerminalRegion() && map.nodeAt(x, y, z).getVerticalCapacity() == 0)) return; if (origin.getY() == y) if ((!origin.isTerminalRegion() && origin.getHorizontalCapacity() == 0) || (!map.nodeAt(x, y, z).isTerminalRegion() && map.nodeAt(x, y, z).getHorizontalCapacity() == 0)) return; int costFromStart = origin.getCostFromStart() + goal.getNodeCost(origin, x, y, z); int costToGoal = goal.distanceToGoal(x, y, z); int totalCost = costFromStart + costToGoal; // Check if on open/closed list // If yes, check if new path is more efficient (lower f value) // and update path if so. AStarRegionNode foundNode = openList.findOpenNode(x, y, z); AStarNode portal = null; boolean foundCheaperPath = false; if (foundNode != null) { if (totalCost < foundNode.getTotalCost()) { // If no portal can be found, don't visit. portal = this.findPortal(origin, foundNode);// TODO: Do // it! if (portal != null) { foundCheaperPath = true; openList.removeNodeFromOpenList(foundNode); } } } else { foundNode = closedList.findClosedNode(x, y, z); if (foundNode != null) { if (totalCost < foundNode.getTotalCost()) { // If no portal can be found, don't visit. portal = this.findPortal(origin, foundNode); // TODO: Do // it! if (portal != null) { foundCheaperPath = true; closedList.removeNodeFromClosedList(foundNode); } } } else { foundNode = map.nodeAt(x, y, z); // If no portal can be found, don't visit. portal = this.findPortal(origin, foundNode); if (portal != null) { // Node not found in open and closed list, thus put a // new one on the open list. foundCheaperPath = true; } } } if (foundCheaperPath) { foundNode.initialize(origin, costFromStart, costToGoal, totalCost, x, y, z); foundNode.setEntryPoint(portal); openList.addNodeToOpenList(foundNode); } } public AStarNode findPortal(AStarRegionNode originRegion, AStarRegionNode targetRegion) { /* * TODO: hier werden die entry points gesetzt. Die exit points kann man erst * nachdem die komplette regionen-route feststeht, setzen. */ AStarNode result = null; if (originRegion.getZ() != targetRegion.getZ()) { // if one of the regions contains start or finish point, don't put a via // here, because it is possible that the via-spacing leads to an error. if (targetRegion.isTileBlocked(originRegion.getEntryPoint().getX(), originRegion.getEntryPoint().getY())) return null; // if found region is on different layer, the portal is trivial return originRegion.getEntryPoint(); } int ox = originRegion.getX(); int fx = targetRegion.getX(); int oy = originRegion.getY(); int fy = targetRegion.getY(); // if foundNode is to the east if (ox == fx - 1) { int targetX = 0; int originX = originRegion.width - 1; int y = originRegion.getEntryPoint().getY(); int count = 0; while (y + count < originRegion.height || y - count >= 0) { if (y + count < originRegion.height && originRegion.isPortalWithPath(originX, y + count, false) && targetRegion.isPortalWithPath(targetX, y + count, false)) return targetRegion.getMap(false).nodeAt(targetX, y + count, 0); if (y - count >= 0 && originRegion.isPortalWithPath(originX, y - count, false) && targetRegion.isPortalWithPath(targetX, y - count, false)) return targetRegion.getMap(false).nodeAt(targetX, y - count, 0); count++; } } // if foundNode is to the west else if (ox == fx + 1) { int targetX = originRegion.width - 1; int originX = 0; int y = originRegion.getEntryPoint().getY(); int count = 0; while (y + count < originRegion.height || y - count >= 0) { if (y + count < originRegion.height && originRegion.isPortalWithPath(originX, y + count, false) && targetRegion.isPortalWithPath(targetX, y + count, false)) return targetRegion.getMap(false).nodeAt(targetX, y + count, 0); if (y - count >= 0 && originRegion.isPortalWithPath(originX, y - count, false) && targetRegion.isPortalWithPath(targetX, y - count, false)) return targetRegion.getMap(false).nodeAt(targetX, y - count, 0); count++; } } // if foundNode is to the north else if (oy == fy + 1) { int targetY = originRegion.height - 1; int originY = 0; int x = originRegion.getEntryPoint().getX(); int count = 0; while (x + count < originRegion.width || x - count >= 0) { if (x + count < originRegion.width && originRegion.isPortalWithPath(x + count, originY, true) && targetRegion.isPortalWithPath(x + count, targetY, true)) return targetRegion.getMap(false).nodeAt(x + count, targetY, 0); if (x - count >= 0 && originRegion.isPortalWithPath(x - count, originY, true) && targetRegion.isPortalWithPath(x - count, targetY, true)) return targetRegion.getMap(false).nodeAt(x - count, targetY, 0); count++; } } // if foundNode is to the south else if (oy == fy - 1) { int targetY = 0; int originY = originRegion.height - 1; int x = originRegion.getEntryPoint().getX(); int count = 0; while (x + count < originRegion.width || x - count >= 0) { if (x + count < originRegion.width && originRegion.isPortalWithPath(x + count, originY, true) && targetRegion.isPortalWithPath(x + count, targetY, true)) return targetRegion.getMap(false).nodeAt(x + count, targetY, 0); if (x - count >= 0 && originRegion.isPortalWithPath(x - count, originY, true) && targetRegion.isPortalWithPath(x - count, targetY, true)) return targetRegion.getMap(false).nodeAt(x - count, targetY, 0); count++; } } return result; } }