// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: // /cvs/distapps/openmap/src/openmap/com/bbn/openmap/tools/roads/Road.java,v // $ // $RCSfile: Road.java,v $ // $Revision: 1.5 $ // $Date: 2005/12/09 21:09:11 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.tools.roads; import java.awt.Point; import java.io.Serializable; import java.util.logging.Logger; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.proj.GreatCircle; import com.bbn.openmap.proj.coords.LatLonPoint; public class Road implements RoadObject, Serializable { transient Logger logger = Logger.getLogger(this.getClass().getName()); /** * The points along the road. The first and last points are always * Intersections. */ private Waypoint[] points; /** * The lines between the points. */ private RoadLine[] lines; /** * The class of this road. A Road's class implies what kind of road it is. * For now this governs its visual appearance of color and width. */ private RoadClass roadClass; private boolean isRoute = false; private boolean blocked = false; /** * The id of this road. */ private int id; /** * The name of this road. */ private String name; /** * True if this road has been modified (points added or removed). */ private boolean modified = false; /** * The RoadLayer we belong to so we can invoke its services. */ private transient RoadLayer roadLayer; /** * Selection flag for this road. */ private boolean selected = false; /** * Blink flag for this road. */ private boolean blinkState = false; /** * Create a road between two Intersections. The detailed segments between * the intersections may be filled in later. * * @param id a unique, integer identifier of this road. * @param name a name for this road. * @param from the intersection from which this road leaves. * @param to the intersection to which this road goes. * @param roadClass the class of this road. * @param roadLayer the RoadLayer we belong to. */ public Road(int id, String name, Intersection from, Intersection to, RoadClass roadClass, RoadLayer roadLayer) { this.id = id; this.name = name; this.roadLayer = roadLayer; points = new Waypoint[2]; setIntersections(from, to); this.roadClass = roadClass; createLines(); modified = false; } public double getLengthInKilometers() { double kilometers = 0.0; LatLonPoint prevPoint = points[0].getLocation(); // logger.warning ("" + this + " pt 0 " + points[0] + " pt 1 " // + points[1] + " getSecondInter " + getSecondIntersection // ()); for (int i = 1; i < points.length; i++) { LatLonPoint thisPoint = points[i].getLocation(); kilometers += GreatCircle.sphericalDistance(prevPoint.getY(), prevPoint.getX(), thisPoint.getY(), thisPoint.getX()); prevPoint = thisPoint; } return kilometers; } public double getTraverseHours() { if (isBlocked()) return Float.MAX_VALUE; return getLengthInKilometers() / getRoadClass().getConvoySpeed(); } public LatLonPoint getLocationAtKilometer(double kilometers) { LatLonPoint prevPoint = points[0].getLocation(); double prevLat = prevPoint.getY(); double prevLon = prevPoint.getX(); for (int i = 1; i < points.length; i++) { LatLonPoint thisPoint = points[i].getLocation(); double thisLat = thisPoint.getY(); double thisLon = thisPoint.getX(); double thisLength = GreatCircle.sphericalDistance(prevLat, prevLon, thisLat, thisLon); if (thisLength >= kilometers) { double fraction = kilometers / thisLength; double deltaLat = thisLat - prevLat; double deltaLon = thisLon - prevLon; if (deltaLon < -180f) deltaLon += 360f; else if (deltaLon > 180f) deltaLon -= 360f; return new LatLonPoint.Double(prevLat + fraction * deltaLat, prevLon + fraction * deltaLon); } kilometers -= thisLength; prevPoint = thisPoint; prevLat = thisLat; prevLon = thisLon; } return prevPoint; } private void createLines() { lines = new RoadLine[points.length - 1]; for (int i = 0; i < lines.length; i++) { lines[i] = new RoadLine(this, i); } blinkLines(); } private void blinkLines() { for (int i = 0; i < lines.length; i++) lines[i].blink(blinkState); } /** * Set the state of the modified flag. Setting the modified flag to false * also sets the modified flag of all the points to false as well. * * @param newValue the new setting. */ public void setModified(boolean newValue) { modified = newValue; if (newValue == false) { for (int i = 0; i < points.length; i++) points[i].setModified(false); } } /** * Get the state of the modified flag. * * @return true if the road or its points have been modified. */ public boolean getModified() { if (modified) return true; for (int i = 0; i < points.length; i++) if (points[i].getModified()) return true; return false; } public void block() { blocked = true; updateLines(); } public void unblock() { blocked = false; updateLines(); } public boolean isBlocked() { return blocked; } public void blink(boolean newState) { blinkState = newState; if (lines != null) blinkLines(); blinkPoints(); } /** * Accessor for the ID property. * * @return the road ID. */ public int getID() { return id; } public String getName() { return name; } public void setName(String newName) { name = newName; } public RoadClass getRoadClass() { return roadClass; } public void setRoadClass(RoadClass newClass) { roadClass = newClass; setModified(true); updateLines(); } public String getRoadClassName() { return roadClass.getName().toString(); } public void isRoute(boolean yes) { isRoute = yes; updateLines(); } public boolean isRoute() { return isRoute; } public RoadLayer getRoadLayer() { return roadLayer; } public void setIntersections(Intersection from, Intersection to) { if (from == null) { logger.warning("from is null."); Thread.dumpStack(); } if (to == null) { logger.warning("to is null."); Thread.dumpStack(); } points[0] = from; points[points.length - 1] = to; checkPoints(); createLines(); setModified(true); } public void setRoadPoints(RoadPoint[] innerPoints) { Waypoint[] oldPoints = points; points = new Waypoint[2 + innerPoints.length]; points[0] = oldPoints[0]; System.arraycopy(innerPoints, 0, points, 1, innerPoints.length); points[points.length - 1] = oldPoints[oldPoints.length - 1]; if (points[points.length - 1] == null) { logger.warning("to is null."); Thread.dumpStack(); } checkPoints(); createLines(); // blinkPoints(); setModified(true); } public void checkPoints() { for (int i = 0; i < points.length; i++) { if (points[i] == null) { logger.warning("found null point at " + i); Thread.dumpStack(); } } } public RoadPoint[] getRoadPoints() { RoadPoint[] innerPoints = new RoadPoint[points.length - 2]; System.arraycopy(points, 1, innerPoints, 0, innerPoints.length); return innerPoints; } public void insertRoadPointAt(RoadPoint wp, int ix) { Waypoint[] oldPoints = points; points = new Waypoint[1 + oldPoints.length]; System.arraycopy(oldPoints, 0, points, 0, ix); points[ix] = wp; if (wp == null) { logger.warning("wp is null."); Thread.dumpStack(); } checkPoints(); System.arraycopy(oldPoints, ix, points, ix + 1, oldPoints.length - ix); createLines(); // blinkPoints(); setModified(true); } public void deleteRoadPoint(RoadPoint rp) { for (int ix = 1; ix < points.length - 1; ix++) { if (points[ix] == rp) { Waypoint[] oldPoints = points; points = new Waypoint[oldPoints.length - 1]; System.arraycopy(oldPoints, 0, points, 0, ix); System.arraycopy(oldPoints, ix + 1, points, ix, oldPoints.length - ix - 1); createLines(); setModified(true); return; } } checkPoints(); } public Intersection getFirstIntersection() { return (Intersection) points[0]; } public Intersection getSecondIntersection() { return (Intersection) points[points.length - 1]; } public Intersection getOtherIntersection(Intersection intersection) { if (intersection == points[0]) return (Intersection) points[points.length - 1]; return (Intersection) points[0]; } public void changeIntersection(Intersection oldIntersection, Intersection newIntersection) { if (oldIntersection == points[0]) { setIntersections(newIntersection, getSecondIntersection()); } else if (oldIntersection == points[points.length - 1]) { setIntersections(getFirstIntersection(), newIntersection); } checkPoints(); } public Waypoint getWaypoint(int ix) { return points[ix]; } public Waypoint[] getPoints() { return points; } public RoadPoint[] getPointsBefore(RoadPoint wp) { for (int i = 1; i < points.length - 1; i++) { if (points[i] == wp) { RoadPoint[] answer = new RoadPoint[i - 1]; System.arraycopy(points, 1, answer, 0, answer.length); return answer; } } return new RoadPoint[0]; } public RoadPoint[] getPointsAfter(RoadPoint wp) { for (int i = 1; i < points.length - 1; i++) { if (points[i] == wp) { RoadPoint[] answer = new RoadPoint[points.length - i - 2]; System.arraycopy(points, i + 1, answer, 0, answer.length); return answer; } } RoadPoint[] answer = new RoadPoint[points.length - 2]; System.arraycopy(points, 1, answer, 0, answer.length); return answer; } private void blinkPoints() { for (int i = 1; i < points.length - 1; i++) { points[i].blink(blinkState); } } /** * Mark this Road as needing a new visual representation. */ public synchronized void updateLines() { for (int i = 0; i < lines.length; i++) lines[i].update(); } public void moveTo(Point loc) { } public synchronized void render(OMGraphicList gl, boolean projectionIsNew) { if (roadLayer.isEditing()) { for (int i = 1; i < points.length - 1; i++) { points[i].render(gl, projectionIsNew); } } for (int i = 0; i < lines.length; i++) lines[i].render(gl, projectionIsNew); } public String toString() { return name + " from " + getFirstIntersection() + " to " + getSecondIntersection() + " " + points.length + " points."; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } }