/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: GlobalRouterPathFinder.java
* Written by: Alexander Herzog (Team 4)
*
* 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.experimentalLeeMoore2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class GlobalRouterPathFinder {
GlobalRouterV3 glr;
int[] fields;
public GlobalRouterPathFinder(GlobalRouterV3 router){
glr = router;
fields = new int[glr.regions_x * glr.regions_y];
for(int i = 0; i < fields.length; ++i){
fields[i] = Integer.MAX_VALUE;
}
}
private int GetFieldIndex(int x, int y){
return y * glr.regions_x + x;
}
private void SetField(int x, int y, int value){
fields[GetFieldIndex(x, y)] = value;
}
private int GetField(int x, int y){
return fields[GetFieldIndex(x, y)];
}
public ArrayList<Vector2i> ConvertToPath(ArrayList<RegionDirection> dirs, Vector2i start){
ArrayList<Vector2i> ret = new ArrayList<Vector2i>();
Vector2i pos = new Vector2i(start);
//add start
ret.add(pos);
Iterator<RegionDirection> it = dirs.iterator();
while(it.hasNext()){
RegionDirection rd = it.next();
Vector2i nb = glr.GetNeighborPos(pos, rd);
assert(glr.IsCoordinateValid(nb.x, nb.y));
ret.add(nb);
}
return ret;
}
private class LeeMooreJob{
Vector2i pos;
int length;
private LeeMooreJob(Vector2i p, int l){
pos = p;
length = l;
}
}
// XXX [fschmidt] could not find shortest path on small designs
private ArrayList<RegionDirection> FindShortestPathLeeMoore(int seg_id){
Vector2i start = glr.segments[seg_id].start;
Vector2i end = glr.segments[seg_id].end;
LinkedList<LeeMooreJob> jobs = new LinkedList<LeeMooreJob>();
LeeMooreJob cj = new LeeMooreJob(new Vector2i(start), 0);
SetField(start.x, start.y, 0);
while(cj != null && !cj.pos.equals(end)){
/** consider neighbors */
for(RegionDirection dir : RegionDirection.values()){
if(dir == RegionDirection.rd_undefined){
continue;
}
if(!glr.IsCoordinateValid(glr.GetNeighborX(cj.pos.x, dir),
glr.GetNeighborY(cj.pos.y, dir))){
continue;
}
// check if neighbor has shorter backpath
Vector2i neighbor = glr.GetNeighborPos(cj.pos, dir);
int n = GetField(neighbor.x, neighbor.y);
if(n >= 0 && n < Integer.MAX_VALUE && n <= cj.length + 1){
continue;
}
// check if border is blocked
if(glr.RegionAt(cj.pos.x, cj.pos.y).GetRegionBorder(dir).IsBlocked()){
continue;
}
// else pass border and offer job
SetField(neighbor.x, neighbor.y, cj.length + 1);
jobs.offer(new LeeMooreJob(neighbor, cj.length + 1));
}
/** poll next job */
cj = jobs.poll();
}
if(cj == null || !cj.pos.equals(end)){
//could not get to end
return null;
}
int l = cj.length;
/** backtrace */
ArrayList<RegionDirection> ret_list = new ArrayList<RegionDirection>();
Vector2i it = new Vector2i(end);
while(!it.equals(start)){
int min = Integer.MAX_VALUE;
RegionDirection min_dir = RegionDirection.rd_undefined;
RegionDirection[] directions = RegionDirection.values();
List<RegionDirection> dir_list = Arrays.asList(directions);
Collections.shuffle(dir_list);
for(int i= 0; i < dir_list.size(); ++i){
directions[i] = dir_list.get(i);
}
for(RegionDirection dir : directions){
if(dir == RegionDirection.rd_undefined){
continue;
}
if(!glr.IsCoordinateValid(glr.GetNeighborX(it.x, dir),
glr.GetNeighborY(it.y, dir))){
continue;
}
int w = GetField(glr.GetNeighborX(it.x, dir), glr.GetNeighborY(it.y, dir));
if(w >= 0 && w < min){
min = w;
min_dir = dir;
}
}
if(min_dir == RegionDirection.rd_undefined){
// should never happen
assert(min_dir != RegionDirection.rd_undefined);
return null;
}
ret_list.add(0, GlobalRouterV3.GetOppositeDir(min_dir));
assert(ret_list.size() <= l);
it = glr.GetNeighborPos(it, min_dir);
}
return ret_list;
}
public List<RegionDirection> FindShortestPath(int seg_id){
return FindShortestPathLeeMoore(seg_id);
}
}