/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.routing.algorithm2; import gnu.trove.map.hash.TObjectIntHashMap; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.util.Collection; import org.simantics.g2d.routing.Constants; import org.simantics.g2d.routing.IConnection; import org.simantics.g2d.routing.IConnection.Connector; import org.simantics.g2d.routing.IRouter2; public class Router4 implements IRouter2 { LocalRouter localRouter; public Router4() { this(false); } public Router4(boolean roundCorners) { this.localRouter = new LocalRouter(roundCorners); } private Path2D route(double beginX, double beginY, int sDir, Rectangle2D beginObstacle, double endX, double endY, int tDir, Rectangle2D endObstacle) { localRouter.sx = beginX; localRouter.sy = beginY; if(beginObstacle == null) { localRouter.aMinX = beginX; localRouter.aMinY = beginY; localRouter.aMaxX = beginX; localRouter.aMaxY = beginY; } else { localRouter.aMinX = beginObstacle.getMinX(); localRouter.aMinY = beginObstacle.getMinY(); localRouter.aMaxX = beginObstacle.getMaxX(); localRouter.aMaxY = beginObstacle.getMaxY(); } localRouter.sourceDirection = sDir; localRouter.tx = endX; localRouter.ty = endY; if(endObstacle == null) { localRouter.bMinX = endX; localRouter.bMinY = endY; localRouter.bMaxX = endX; localRouter.bMaxY = endY; } else { localRouter.bMinX = endObstacle.getMinX(); localRouter.bMinY = endObstacle.getMinY(); localRouter.bMaxX = endObstacle.getMaxX(); localRouter.bMaxY = endObstacle.getMaxY(); } localRouter.targetDirection = tDir; localRouter.route(); return localRouter.path; } @Override public void route(IConnection connection) { Collection segments = connection.getSegments(); if(segments.size() == 1) for(Object seg : segments) { Connector begin = connection.getBegin(seg); Connector end = connection.getEnd(seg); double bestLength = Double.POSITIVE_INFINITY; Path2D bestPath = null; for(int sDir : Constants.POSSIBLE_DIRECTIONS[begin.allowedDirections]) for(int tDir : Constants.POSSIBLE_DIRECTIONS[end.allowedDirections]) { Path2D path = route(begin.x, begin.y, sDir, begin.parentObstacle, end.x, end.y, tDir, end.parentObstacle); double length = pathCost(path); if(length < bestLength) { bestLength = length; bestPath = localRouter.path; } } if(bestPath != null) connection.setPath(seg, bestPath); } else { TObjectIntHashMap leftSegments = new TObjectIntHashMap(); TObjectIntHashMap rightSegments = new TObjectIntHashMap(); TObjectIntHashMap upSegments = new TObjectIntHashMap(); TObjectIntHashMap downSegments = new TObjectIntHashMap(); TObjectIntHashMap horizontalCount = new TObjectIntHashMap(); for(Object seg : segments) { Connector begin = connection.getBegin(seg); Connector end = connection.getEnd(seg); if(begin.x < end.x) { leftSegments.adjustOrPutValue(end, 1, 1); rightSegments.adjustOrPutValue(begin, 1, 1); } else { leftSegments.adjustOrPutValue(begin, 1, 1); rightSegments.adjustOrPutValue(end, 1, 1); } if(begin.y < end.y) { upSegments.adjustOrPutValue(end, 1, 1); downSegments.adjustOrPutValue(begin, 1, 1); } else { upSegments.adjustOrPutValue(begin, 1, 1); downSegments.adjustOrPutValue(end, 1, 1); } if((begin.allowedDirections & 5) != 0) horizontalCount.adjustOrPutValue(end, 1, 1); if((begin.allowedDirections & 10) != 0) horizontalCount.adjustOrPutValue(end, -1, -1); if((end.allowedDirections & 5) != 0) horizontalCount.adjustOrPutValue(begin, 1, 1); if((end.allowedDirections & 10) != 0) horizontalCount.adjustOrPutValue(begin, -1, -1); } for(Object seg : segments) { Connector begin = connection.getBegin(seg); Connector end = connection.getEnd(seg); int allowedBegin = begin.allowedDirections; int allowedEnd = end.allowedDirections; if(horizontalCount.get(begin) + horizontalCount.get(end) >= 0) { //System.out.println("horizontal"); if(begin.x < end.x) { if(allowedBegin == 0xf) { if(rightSegments.get(begin) <= 1) allowedBegin = 1; else allowedBegin = 11; } if(allowedEnd == 0xf) { if(leftSegments.get(end) <= 1) allowedEnd = 4; else allowedEnd = 14; } } else { if(allowedBegin == 0xf) { if(leftSegments.get(begin) <= 1) allowedBegin = 4; else allowedBegin = 14; } if(allowedEnd == 0xf) { if(rightSegments.get(end) <= 1) allowedEnd = 1; else allowedEnd = 11; } } } else { //System.out.println("vertical"); if(begin.y < end.y) { if(allowedBegin == 0xf) { if(downSegments.get(begin) <= 1) allowedBegin = 2; else allowedBegin = 7; } if(allowedEnd == 0xf) { if(upSegments.get(end) <= 1) allowedEnd = 8; else allowedEnd = 13; } } else { if(allowedBegin == 0xf) { if(upSegments.get(begin) <= 1) allowedBegin = 8; else allowedBegin = 13; } if(allowedEnd == 0xf) { if(downSegments.get(end) <= 1) allowedEnd = 2; else allowedEnd = 7; } } } //System.out.println(allowedBegin + " " + allowedEnd); double bestLength = Double.POSITIVE_INFINITY; Path2D bestPath = null; for(int sDir : Constants.POSSIBLE_DIRECTIONS[allowedBegin]) for(int tDir : Constants.POSSIBLE_DIRECTIONS[allowedEnd]) { Path2D path = route(begin.x, begin.y, sDir, begin.parentObstacle, end.x, end.y, tDir, end.parentObstacle); double length = pathCost(path); if(length < bestLength) { bestLength = length; bestPath = localRouter.path; } } if(bestPath != null) connection.setPath(seg, bestPath); } } } final static AffineTransform IDENTITY = new AffineTransform(); static double pathCost(Path2D path) { double length = 0.0; PathIterator it = path.getPathIterator(IDENTITY); double[] temp = new double[6]; double x=0.0, y=0.0; double bendCount = 0.0; while(!it.isDone()) { bendCount += 1.0; if(it.currentSegment(temp) != PathIterator.SEG_MOVETO) length += Math.abs(x - temp[0] + y - temp[1]); x = temp[0]; y = temp[1]; it.next(); } //return length * (6.0 + bendCount); return bendCount - 1.0 / length; } }