001: /*
002: * RoutePlotter.java
003: *
004: * Created on 09 November 2006, 09:38
005: *
006: * To change this template, choose Tools | Template Manager
007: * and open the template in the editor.
008: */
009:
010: package com.xoetrope.svg;
011:
012: import com.kitfox.svg.Circle;
013: import com.kitfox.svg.Group;
014: import com.kitfox.svg.Path;
015: import com.kitfox.svg.SVGDiagram;
016: import com.kitfox.svg.SVGElementException;
017: import com.kitfox.svg.SVGRoot;
018: import com.kitfox.svg.Text;
019: import com.kitfox.svg.Tspan;
020: import com.kitfox.svg.animation.AnimationElement;
021: import com.xoetrope.carousel.build.BuildProperties;
022: import com.xoetrope.svg.XSvgImageMap;
023: import java.awt.BasicStroke;
024: import java.awt.Color;
025: import java.awt.Graphics;
026: import java.awt.Graphics2D;
027: import java.awt.Rectangle;
028: import java.awt.RenderingHints;
029: import java.awt.Stroke;
030: import java.awt.geom.Arc2D;
031: import java.awt.geom.Ellipse2D;
032: import java.awt.geom.Line2D;
033: import java.awt.geom.Point2D;
034: import java.awt.geom.Rectangle2D;
035: import java.util.ArrayList;
036: import javax.swing.JComponent;
037:
038: /**
039: *
040: *
041: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
042: * the GNU Public License (GPL), please see license.txt for more details. If
043: * you make commercial use of this software you must purchase a commercial
044: * license from Xoetrope.</p>
045: * <p> $Revision: 1.2 $</p>
046: */
047: public class XRoutePlotter {
048: protected XSvgImageMap imageMap;
049: protected ArrayList waypoints, routeWaypoints, waypointFlags;
050: protected ArrayList lines;
051: protected Path route;
052: protected Circle circle, circle2;
053:
054: /**
055: * Creates a new instance of RoutePlotter
056: * Used to plot a route on the svg map.
057: * @param imageMap the <CODE>XSvgImageMap</CODE> instance that the routes will be plotted on.
058: * @param waypoints an <CODE>ArrayList</CODE> of waypoints used to construct routes.
059: */
060: public XRoutePlotter(XSvgImageMap imageMap, ArrayList waypoints) {
061: this .imageMap = imageMap;
062: this .waypoints = waypoints;
063: lines = new ArrayList();
064: waypointFlags = new ArrayList();
065: }
066:
067: /**
068: * Plots a route from the current location to the selected waypoint.
069: * i.e. the destination
070: * @param startWaypoint an <CODE>int<CODE> specifying the the index of the starting waypoint.
071: * @param destinationWaypoint an <CODE>int<CODE> specifying the the index of the destination waypoint.
072: * @return a boolean stating whether a route can be plotted or not.
073: */
074: public boolean plotRoute(int startWaypoint, int destinationWaypoint) {
075: routeWaypoints = shortestPath((XWaypoint) waypoints
076: .get(startWaypoint), (XWaypoint) waypoints
077: .get(destinationWaypoint));
078: if (routeWaypoints == null)
079: return false;
080:
081: SVGDiagram diagram = imageMap.getSvgDiagram();
082: SVGRoot root = diagram.getRoot();
083:
084: try {
085: route = new Path();
086: route.addAttribute("fill", AnimationElement.AT_XML, "none");
087: route.addAttribute("stroke", AnimationElement.AT_XML,
088: "#0033ff");
089: route.addAttribute("stroke-width", AnimationElement.AT_XML,
090: "1");
091:
092: XWaypoint current = (XWaypoint) routeWaypoints.get(0);
093:
094: String d = "M " + Double.toString(current.getX()) + " "
095: + Double.toString(current.getY());
096:
097: for (int i = 1; i < routeWaypoints.size(); i++) {
098: current = (XWaypoint) routeWaypoints.get(i);
099: d = d + " L " + Double.toString(current.getX()) + " "
100: + Double.toString(current.getY());
101: }
102: route.addAttribute("d", AnimationElement.AT_XML, d);
103: root.loaderAddChild(null, route);
104:
105: current = (XWaypoint) routeWaypoints.get(0);
106: XWaypointFlag waypointFlag1 = new XWaypointFlag(root);
107: waypointFlag1.drawFlag(current.getX(), current.getY(),
108: null, XWaypointFlag.START_WAYPOINT);
109: waypointFlags.add(waypointFlag1);
110:
111: int waypointNum = 1;
112: for (int i = 1; i < routeWaypoints.size() - 1; i++) {
113: current = (XWaypoint) routeWaypoints.get(i);
114:
115: XWaypoint previous = (XWaypoint) routeWaypoints
116: .get(i - 1);
117: XWaypoint next = (XWaypoint) routeWaypoints.get(i + 1);
118:
119: int check = 0;
120: if ((previous.getX() <= (next.getX() + 5.0))
121: && (previous.getX() >= (next.getX() - 5.0))) {
122: check += 1;
123: }
124:
125: if ((previous.getY() <= (next.getY() + 5.0))
126: && (previous.getY() >= (next.getY() - 5.0))) {
127: check += 1;
128: }
129:
130: if (check == 0) {
131: XWaypointFlag waypointFlag2 = new XWaypointFlag(
132: root);
133: waypointFlag2.drawFlag(current.getX(), current
134: .getY(), Integer.toString(waypointNum),
135: XWaypointFlag.MARKER_WAYPOINT);
136: waypointFlags.add(waypointFlag2);
137: waypointNum += 1;
138: }
139: }
140:
141: current = (XWaypoint) routeWaypoints.get(routeWaypoints
142: .size() - 1);
143: XWaypointFlag waypointFlag3 = new XWaypointFlag(root);
144: waypointFlag3.drawFlag(current.getX(), current.getY(),
145: null, XWaypointFlag.END_WAYPOINT);
146: waypointFlags.add(waypointFlag3);
147:
148: root.updateTime(0.0);
149:
150: imageMap.resetBuffer();
151: imageMap.repaint();
152: } catch (Exception ex) {
153: if (BuildProperties.DEBUG)
154: ex.printStackTrace();
155: }
156: return true;
157: }
158:
159: /**
160: * Shortest path algorithm used to determine the shortest path between two waypoints.
161: * @param start <code>Waypoint</code> object specifying the starting waypoint.
162: * @param goal <code>Waypoint</code> object specifying the destination waypoint.
163: */
164: private ArrayList shortestPath(XWaypoint start, XWaypoint goal) {
165: ArrayList closed = new ArrayList();
166: ArrayList q = new ArrayList();
167: ArrayList successors = null;
168:
169: q.add(start);
170: while (q.size() > 0) {
171: XWaypoint current = (XWaypoint) q.remove(0);
172:
173: // if the destination node is found.
174: if (current.getName().equals(goal.getName())) {
175: // construct path
176: ArrayList route = new ArrayList();
177: while (current.getParent() != null) {
178: route.add(0, current);
179: current = current.getParent();
180: }
181: route.add(0, start);
182: return route;
183: }
184:
185: /**
186: * Iterates through all successors of the current node.
187: * If a node has already been added to the queue, its parent is not
188: * set to the current node. Therefore the path between a node and
189: * the start node is always the shortest path.
190: */
191: successors = current.getNeighbours();
192: for (int i = 0; i < successors.size(); i++) {
193: XWaypoint neighbour = (XWaypoint) successors.get(i);
194: boolean isOpen = q.contains(neighbour);
195: boolean isClosed = closed.contains(neighbour);
196:
197: if ((!isOpen) && (!isClosed)) {
198: neighbour.setParent(current);
199: q.add(neighbour);
200: }
201: }
202: closed.add(current);
203: }
204: return null;
205: }
206:
207: /**
208: * Remove the currently drawn route from the svg image.
209: */
210: public void undoRoute() {
211: SVGDiagram diagram = imageMap.getSvgDiagram();
212: SVGRoot root = diagram.getRoot();
213:
214: try {
215: if (route != null) {
216: root.removeChild(route);
217:
218: for (int i = 0; i < waypointFlags.size(); i++) {
219: XWaypointFlag waypointFlag = (XWaypointFlag) waypointFlags
220: .get(i);
221: root.removeChild(waypointFlag);
222: }
223: waypointFlags.clear();
224:
225: root.updateTime(0.0);
226: imageMap.repaint();
227:
228: for (int i = 0; i < waypoints.size(); i++) {
229: ((XWaypoint) waypoints.get(i)).setParent(null);
230: }
231: }
232: } catch (Exception ex) {
233: if (BuildProperties.DEBUG)
234: ex.printStackTrace();
235: }
236: }
237:
238: /**
239: * Returns the bounding rectangle of the currently drawn route.
240: * @return <CODE>Rectangle2D.Double</CODE> which bounds the current route.
241: */
242: public Rectangle2D.Double getRouteRect() {
243: if (routeWaypoints != null) {
244: double minX, minY, maxX = 0, maxY = 0;
245: minX = ((XWaypoint) routeWaypoints.get(0)).getX();
246: minY = ((XWaypoint) routeWaypoints.get(0)).getY();
247:
248: for (int i = 0; i < routeWaypoints.size(); i++) {
249: XWaypoint w = (XWaypoint) routeWaypoints.get(i);
250:
251: if (w.getX() < minX)
252: minX = w.getX();
253: if (w.getY() < minY)
254: minY = w.getY();
255:
256: if (w.getX() > maxX)
257: maxX = w.getX();
258: if (w.getY() > maxY)
259: maxY = w.getY();
260: }
261:
262: Rectangle2D.Double rect2D = new Rectangle2D.Double(
263: minX - 10, minY - 20, (maxX - minX) + 20,
264: (maxY - minY) + 40);
265: return rect2D;
266: }
267: return null;
268: }
269: }
|