/* * RESTRICTED RIGHTS LEGEND * * BBNT Solutions LLC * A Verizon Company * 10 Moulton Street * Cambridge, MA 02138 * (617) 873-3000 * * Copyright BBNT Solutions LLC 2005 All Rights Reserved * */ package com.bbn.openmap.geo; /** * An abstraction of an arbitrary geographic path. A path is assumed to mean a * chain of points that although it may share a common starting and end point, * it will not not represent an area in that case. * * @author mthome@bbn.com */ public interface GeoPath extends GeoExtent { /** @return an iterator over the segments of the path * */ GeoPath.SegmentIterator segmentIterator(); /** @return an iterator over the points of the path * */ GeoPath.PointIterator pointIterator(); /** Does the segment s come within epsilon (in radians) of us? */ boolean isSegmentNear(GeoSegment s, double epsilon); /** * Return the points that make up the path as an array of Geo object. Closed * paths are not specially marked. Specifically, closed paths do not have * equal first and last Geo points in the returned array. * * @return the Geo points of the Path */ // Geo[] toPointArray(); GeoArray getPoints(); /** * @return the number of points in the path. */ int length(); interface SegmentIterator extends java.util.Iterator { /** Asking if there is another segment. * */ boolean hasNext(); /** * standard implementation of Iterator.next() returns the same value as * nextSegment(), albeit needing casting to GSegment. */ Object next(); /** * Advance to the next pegment. Some implementations will also implement * GSegment, so that #next() returns the iterator instance itself, but * this should not be depended on. * * @return the next GSegment */ GeoSegment nextSegment(); } interface PointIterator extends java.util.Iterator { /** Asking if is there another point. * */ boolean hasNext(); /** * standard implementation of Iterator.next() returns the same value as * nextPoint(), albeit needing casting to GPoint. */ Object next(); /** * Advance to the next point. Some implementations will also implement * GPoint, so that #next() returns the iterator instance itself, but * this should not be depended on. * * @return the next GPoint */ GeoPoint nextPoint(); } /** * An implementation of Path that takes an alternating lat/lon array and * (optionally) an array of altitudes. */ public static class Impl implements GeoPath { protected GeoArray pts; protected int length; protected Object id = GeoPath.Impl.this; protected Impl() {} /** * Create a path of LatLon pairs. * * @param lls alternating lat/lon in decimal degrees. */ public Impl(double[] lls) { this(lls, true); } /** * Create a path of LatLon pairs. * * @param lls alternating lat/lon values. * @param isDegrees true if lat/lon are in degrees, false if in radians. */ public Impl(double[] lls, boolean isDegrees) { if (isDegrees) { setPoints(GeoArray.Double.createFromLatLonDegrees(lls)); } else { setPoints(GeoArray.Double.createFromLatLonRadians(lls)); } } /** * Create a path from a GeoArray. * @param pnts */ public Impl(GeoArray pnts) { setPoints(pnts); } /** * Create a path from Geos. * * @param geos */ public Impl(Geo[] geos) { setPoints(geos); } public void setPoints(GeoArray ga) { pts = ga; if (pts != null) { length = pts.getSize(); } else { length = 0; } } public GeoArray getPoints() { return pts; } /** * Method for subclasses to set pts and length of Geos. * * @param points */ protected void setPoints(Geo[] points) { pts = new GeoArray.Double(points); if (pts != null) { length = pts.getSize(); } else { length = 0; } } // public Geo[] toPointArray() { // return pts.toPointArray(); // } public boolean isSegmentNear(GeoSegment s, double epsilon) { return Intersection.isSegmentNearPoly(s, getPoints(), epsilon) != null; } protected transient BoundingCircle bc = null; public synchronized BoundingCircle getBoundingCircle() { if (bc == null) bc = new BoundingCircle.Impl(this); return bc; } public int length() { return length; } public GeoPath.SegmentIterator segmentIterator() { return new SegIt(); } public GeoPath.PointIterator pointIterator() { return new PointIt(); } /** * Callback for the SegIt to find out how the GeoPath wants the segment * IDed. * * @param i The index of the segment in question. * @return Object that IDs the segment, could be this path, too. Depends * on what the Intersection Algorithm wants to do in consider(). */ protected Object getSegID(int i) { return new Integer(i); } /** * Callback for the PointIt to find out how the GeoPath wants the points * IDed. * * @param i The index of the point in question. * @return Object that IDs the point, could be this path, too. Depends * on what the Intersection Algorithm wants to do in consider(). */ protected Object getPointID(int i) { return new Integer(i); } protected class SegIt implements GeoPath.SegmentIterator, GeoSegment { int i = -1; Geo[] seg = new Geo[] { new Geo(), new Geo() }; public SegIt() { pts.get(0, seg[1]); } /** Constructs a new bounding circle instance each call. * */ public BoundingCircle getBoundingCircle() { Geo c = Intersection.center(seg); return new BoundingCircle.Impl(c, c.distance(seg[0])); } public boolean hasNext() { return i < (length - 2); } public Object next() { return nextSegment(); } public GeoSegment nextSegment() { i++; seg[0].initialize(seg[1]); pts.get(i + 1, seg[1]); return this; } public void remove() { throw new UnsupportedOperationException("Path.SegmentIterator doesn't support remove"); } /** * GSegment method. * * @return the current segment as a two-element array of Geo The * first point is the "current point" and the second is the * next. TODO If there isn't another point available, will * throw an indexOutOfBounds exception. */ public Geo[] getSeg() { return seg; } /** * @return the current segment as a float[]. The first point is the * "current point" and the second is the next. TODO If there * isn't another point available, will throw an * indexOutOfBounds exception. */ public double[] getSegArray() { return new double[] { seg[0].getLatitude(), seg[0].getLongitude(), seg[1].getLatitude(), seg[1].getLongitude() }; } /** * Return Object ID for current segment. * * @deprecated */ public Object getSegId() { return GeoPath.Impl.this.getSegID(i); } /** * GeoExtent method * * @return Object ID for current segment. */ public Object getID() { return GeoPath.Impl.this.getSegID(i); } } protected class PointIt implements GeoPath.PointIterator, GeoPoint { int i = -1; Geo pt = new Geo(); public PointIt() {} public boolean hasNext() { return i < (length - 1); // need -1, because of the i++ in // nextPoint. } public Object next() { return nextPoint(); } public GeoPoint nextPoint() { i++; return this; } public void remove() { throw new UnsupportedOperationException("Path.Iterator doesn't support remove"); } public Geo getPoint() { return pts.get(i, pt); } /** * @deprecated use getID() instead. */ public Object getPointId() { return GeoPath.Impl.this.getPointID(i); } /** * GeoExtent method * * @return Object ID for current point. */ public Object getID() { return GeoPath.Impl.this.getPointID(i); } public BoundingCircle getBoundingCircle() { return new BoundingCircle.Impl(pts.get(i), 0.0); } } /** * @deprecated use getID() instead. */ public Object getPathID() { return id; } public Object getID() { return id; } public void setID(Object id) { this.id = id; } } }