/*
* RoutePlotter.java
*
* Created on 09 November 2006, 09:38
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package com.xoetrope.svg;
import com.kitfox.svg.Circle;
import com.kitfox.svg.Group;
import com.kitfox.svg.Path;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGElementException;
import com.kitfox.svg.SVGRoot;
import com.kitfox.svg.Text;
import com.kitfox.svg.Tspan;
import com.kitfox.svg.animation.AnimationElement;
import com.xoetrope.carousel.build.BuildProperties;
import com.xoetrope.svg.XSvgImageMap;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
/**
*
*
* <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
* the GNU Public License (GPL), please see license.txt for more details. If
* you make commercial use of this software you must purchase a commercial
* license from Xoetrope.</p>
* <p> $Revision: 1.2 $</p>
*/
public class XRoutePlotter
{
protected XSvgImageMap imageMap;
protected ArrayList waypoints, routeWaypoints, waypointFlags;
protected ArrayList lines;
protected Path route;
protected Circle circle, circle2;
/**
* Creates a new instance of RoutePlotter
* Used to plot a route on the svg map.
* @param imageMap the <CODE>XSvgImageMap</CODE> instance that the routes will be plotted on.
* @param waypoints an <CODE>ArrayList</CODE> of waypoints used to construct routes.
*/
public XRoutePlotter( XSvgImageMap imageMap, ArrayList waypoints )
{
this.imageMap = imageMap;
this.waypoints = waypoints;
lines = new ArrayList();
waypointFlags = new ArrayList();
}
/**
* Plots a route from the current location to the selected waypoint.
* i.e. the destination
* @param startWaypoint an <CODE>int<CODE> specifying the the index of the starting waypoint.
* @param destinationWaypoint an <CODE>int<CODE> specifying the the index of the destination waypoint.
* @return a boolean stating whether a route can be plotted or not.
*/
public boolean plotRoute(int startWaypoint, int destinationWaypoint)
{
routeWaypoints = shortestPath( (XWaypoint)waypoints.get( startWaypoint ), (XWaypoint)waypoints.get( destinationWaypoint ) );
if(routeWaypoints == null)
return false;
SVGDiagram diagram = imageMap.getSvgDiagram ();
SVGRoot root = diagram.getRoot ();
try{
route = new Path();
route.addAttribute ( "fill", AnimationElement.AT_XML, "none" );
route.addAttribute ( "stroke", AnimationElement.AT_XML, "#0033ff" );
route.addAttribute ( "stroke-width", AnimationElement.AT_XML, "1" );
XWaypoint current = (XWaypoint)routeWaypoints.get( 0 );
String d = "M " + Double.toString ( current.getX () ) + " " + Double.toString ( current.getY () );
for(int i = 1; i < routeWaypoints.size (); i++){
current = (XWaypoint)routeWaypoints.get (i);
d = d + " L " + Double.toString ( current.getX ()) + " " + Double.toString ( current.getY () );
}
route.addAttribute ( "d", AnimationElement.AT_XML, d );
root.loaderAddChild( null, route );
current = (XWaypoint)routeWaypoints.get (0);
XWaypointFlag waypointFlag1 = new XWaypointFlag( root );
waypointFlag1.drawFlag( current.getX (), current.getY (), null, XWaypointFlag.START_WAYPOINT );
waypointFlags.add( waypointFlag1 );
int waypointNum = 1;
for(int i = 1; i < routeWaypoints.size ()-1; i++){
current = (XWaypoint)routeWaypoints.get ( i );
XWaypoint previous = (XWaypoint)routeWaypoints.get ( i - 1 );
XWaypoint next = (XWaypoint)routeWaypoints.get ( i + 1 );
int check = 0;
if( ( previous.getX() <= ( next.getX() + 5.0 ) ) && ( previous.getX() >= ( next.getX() - 5.0 ) ) ){
check += 1;
}
if( ( previous.getY() <= ( next.getY() + 5.0 ) ) && ( previous.getY() >= ( next.getY() - 5.0 ) ) ){
check += 1;
}
if( check == 0 ){
XWaypointFlag waypointFlag2 = new XWaypointFlag( root );
waypointFlag2.drawFlag( current.getX (), current.getY (), Integer.toString( waypointNum ), XWaypointFlag.MARKER_WAYPOINT );
waypointFlags.add( waypointFlag2 );
waypointNum += 1;
}
}
current = (XWaypoint)routeWaypoints.get ( routeWaypoints.size ()-1 );
XWaypointFlag waypointFlag3 = new XWaypointFlag(root);
waypointFlag3.drawFlag( current.getX (), current.getY (), null, XWaypointFlag.END_WAYPOINT );
waypointFlags.add(waypointFlag3);
root.updateTime ( 0.0 );
imageMap.resetBuffer();
imageMap.repaint();
}
catch ( Exception ex ){
if ( BuildProperties.DEBUG )
ex.printStackTrace();
}
return true;
}
/**
* Shortest path algorithm used to determine the shortest path between two waypoints.
* @param start <code>Waypoint</code> object specifying the starting waypoint.
* @param goal <code>Waypoint</code> object specifying the destination waypoint.
*/
private ArrayList shortestPath( XWaypoint start, XWaypoint goal )
{
ArrayList closed = new ArrayList();
ArrayList q = new ArrayList();
ArrayList successors = null;
q.add( start );
while( q.size() > 0 ){
XWaypoint current = (XWaypoint)q.remove( 0 );
// if the destination node is found.
if( current.getName().equals( goal.getName() ) ){
// construct path
ArrayList route = new ArrayList();
while( current.getParent() != null ){
route.add( 0, current );
current = current.getParent();
}
route.add( 0, start );
return route;
}
/**
* Iterates through all successors of the current node.
* If a node has already been added to the queue, its parent is not
* set to the current node. Therefore the path between a node and
* the start node is always the shortest path.
*/
successors = current.getNeighbours();
for( int i = 0; i < successors.size(); i++ ){
XWaypoint neighbour = (XWaypoint)successors.get(i);
boolean isOpen = q.contains( neighbour );
boolean isClosed = closed.contains( neighbour );
if(( !isOpen ) && ( !isClosed )){
neighbour.setParent( current );
q.add( neighbour );
}
}
closed.add( current );
}
return null;
}
/**
* Remove the currently drawn route from the svg image.
*/
public void undoRoute()
{
SVGDiagram diagram = imageMap.getSvgDiagram ();
SVGRoot root = diagram.getRoot ();
try{
if( route != null ){
root.removeChild ( route );
for(int i = 0; i < waypointFlags.size(); i++){
XWaypointFlag waypointFlag = (XWaypointFlag)waypointFlags.get( i );
root.removeChild( waypointFlag );
}
waypointFlags.clear();
root.updateTime (0.0);
imageMap.repaint ();
for(int i = 0; i < waypoints.size(); i++){
((XWaypoint)waypoints.get(i)).setParent(null);
}
}
}
catch(Exception ex){
if ( BuildProperties.DEBUG )
ex.printStackTrace();
}
}
/**
* Returns the bounding rectangle of the currently drawn route.
* @return <CODE>Rectangle2D.Double</CODE> which bounds the current route.
*/
public Rectangle2D.Double getRouteRect()
{
if(routeWaypoints != null){
double minX, minY, maxX = 0, maxY = 0;
minX = ( (XWaypoint)routeWaypoints.get( 0 ) ).getX();
minY = ( (XWaypoint)routeWaypoints.get( 0 ) ).getY();
for(int i = 0; i < routeWaypoints.size(); i++){
XWaypoint w = (XWaypoint)routeWaypoints.get(i);
if(w.getX() < minX)
minX = w.getX();
if(w.getY() < minY)
minY = w.getY();
if(w.getX() > maxX)
maxX = w.getX();
if(w.getY() > maxY)
maxY = w.getY();
}
Rectangle2D.Double rect2D = new Rectangle2D.Double( minX-10, minY-20, ( maxX-minX )+20, ( maxY-minY )+40 );
return rect2D;
}
return null;
}
}
|