package com.aerodynelabs.map; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; /** * A 3d path * * @author Ethan Harstad * */ public class MapPath { private String name; private double boundNorth = 0.0; private double boundSouth = 0.0; private double boundEast = 0.0; private double boundWest = 0.0; private double maxAlt = 0.0; private long startTime = 0; private long endTime = 0; private LinkedList<MapPoint> path; private ArrayList<MapPoint> markers; /** * Create a new path. */ public MapPath() { path = new LinkedList<MapPoint>(); markers = new ArrayList<MapPoint>(); } /** * Create a new path with the given name. * @param name */ public MapPath(String name) { this(); this.name = name; } /** * Create a path from the given sequence of points. * @param path */ public MapPath(List<MapPoint> in) { this(); Iterator<MapPoint> itr = in.iterator(); while(itr.hasNext()) { add(itr.next()); } } /** * Add the given marker to the path. * @param mark */ public void addMarker(MapPoint mark) { markers.add(mark); } /** * Add the given named marker to the path. * @param name * @param lat * @param lon */ public void addMarker(String name, double lat, double lon) { markers.add(new MapPoint(lat, lon, 0, 0, name)); } /** * Get the first point of this path. * @return */ public MapPoint getFirst() { return path.getFirst(); } /** * Get the last ponit of this path. * @return */ public MapPoint getLast() { return path.getLast(); } /** * Get the distance between the start and end of this path. * @return Distance in meters */ public double getDistance() { try { double dLat = Math.toRadians(path.getLast().getLatitude() - path.getFirst().getLatitude()); double dLon = Math.toRadians(path.getLast().getLongitude() - path.getFirst().getLongitude()); double sLat = Math.toRadians(path.getFirst().getLatitude()); double fLat = Math.toRadians(path.getLast().getLatitude()); double a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(sLat) * Math.cos(fLat); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return c * 6371000; } catch(Exception e) { return 0.0d; } } /** * Get the name of this path. * @return */ public String getName() { return name; } /** * Set the name of this path. * @param name */ public void setName(String name) { this.name = name; } /** * Get the maximum altitude of this path. * @return */ public double getMaxAlt() { return maxAlt; } /** * Get the first time in the path. * @return */ public long getStartTime() { return startTime; } /** * Get the last time in the path. * @return */ public long getEndTime() { return endTime; } /** * Get the time between the start and end of the path. * @return */ public long getElapsedTime() { return endTime - startTime; } private void updateBounds(double lat, double lon) { if(lat > boundNorth) { boundNorth = lat; } else if(lat < boundSouth) { boundSouth = lat; } if(lon > boundEast) { boundEast = lon; } else if(lon < boundWest) { boundWest = lon; } } /** * Append the point to the end of this path. * @param point */ public void add(MapPoint point) { updateBounds(point.getLatitude(), point.getLongitude()); if(point.getAltitude() > 0) { double alt = point.getAltitude(); if(alt > maxAlt) maxAlt = alt; } if(point.getTime() > 0) { long time = point.getTime(); if(time < startTime || startTime == 0) startTime = time; if(time > endTime) endTime = time; } path.add(point); } /** * Append the point to the end of this path. * @param lat * @param lon */ public void add(double lat, double lon) { updateBounds(lat, lon); path.add(new MapPoint(lat, lon)); } /** * Append the point to the end of this path. * @param lat * @param lon * @param alt */ public void add(double lat, double lon, double alt) { updateBounds(lat, lon); if(alt > maxAlt) maxAlt = alt; path.add(new MapPoint(lat, lon, alt)); } /** * Append the point to the end of this path. * @param lat * @param lon * @param alt * @param time */ public void add(double lat, double lon, double alt, long time) { updateBounds(lat, lon); if(alt > maxAlt) maxAlt = alt; if(time < startTime || startTime == 0) startTime = time; if(time > endTime) endTime = time; path.add(new MapPoint(lat, lon, alt, time)); } /** * Append the sequence of points to the end of this path. * @param path */ public void addAll(List<MapPoint> in) { Iterator<MapPoint> itr = in.iterator(); while(itr.hasNext()) { add(itr.next()); } } /** * Get the northernmost point of this path. * @return */ public double getNorthBound() { return boundNorth; } /** * Get the southernmost point of this path. * @return */ public double getSouthBound() { return boundSouth; } /** * Get the easternmost point of this path. * @return */ public double getEastBound() { return boundEast; } /** * Get the westernmost point of this path. * @return */ public double getWestBound() { return boundWest; } /** * Get the path. * @return */ public LinkedList<MapPoint> getPath() { return path; } /** * Get a list of the markers in the path. * @return */ public List<MapPoint> getMarkers() { return markers; } /** * Test if this path extends into the given bounds. * @param north * @param east * @param south * @param west * @return */ public boolean inBounds(double north, double east, double south, double west) { if(south > boundNorth) return false; // Region is above of bounds if(north < boundSouth) return false; // Region is below of bounds if(east < boundWest) return false; // Region is left of bounds if(west > boundEast) return false; // Region is right of bounds return true; } /** * Get an iterator over the path. * @return */ public ListIterator<MapPoint> iterator() { return path.listIterator(); } /** * Export the path to a CSV file. * @param file * @return */ public boolean export(File file) { try( FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw); PrintWriter out = new PrintWriter(bw); ) { ListIterator<MapPoint> itr = path.listIterator(); while(itr.hasNext()) { out.println(itr.next()); } out.flush(); } catch (IOException e) { e.printStackTrace(); return false; } return true; } /** * Export the path to a KML file. * @param file * @return */ public boolean exportKML(File file) { KML kml = new KML(); kml.addPath(path, name); ListIterator<MapPoint> itr = markers.listIterator(); while(itr.hasNext()) { kml.addMark(itr.next()); } return kml.writeFile(file); } }