Package aimax.osm.data

Source Code of aimax.osm.data.Position

package aimax.osm.data;

import java.util.Collection;
import java.util.List;

import aimax.osm.data.entities.MapEntity;
import aimax.osm.data.entities.MapNode;
import aimax.osm.data.entities.MapWay;
import aimax.osm.data.entities.WayRef;

/**
* Maintains a latitude longitude pair and provides some useful methods for
* distance calculations.
*
* @author Ruediger Lunde
*/
public class Position {

  /** Earth's mean radius in km. */
  public static double EARTH_RADIUS = 6371.0;
  protected float lat;
  protected float lon;

  public Position(float lat, float lon) {
    this.lat = lat;
    this.lon = lon;
  }

  public Position(MapNode node) {
    lat = node.getLat();
    lon = node.getLon();
  }

  public float getLat() {
    return lat;
  }

  public float getLon() {
    return lon;
  }

  /**
   * Computes the distance in kilometer from this position to a specified map
   * node.
   */
  public double getDistKM(MapEntity entity) {
    if (entity instanceof MapNode) {
      return getDistKM(lat, lon, ((MapNode) entity).getLat(),
          ((MapNode) entity).getLon());
    } else if (entity instanceof MapWay) {
      MapWay way = (MapWay) entity;
      BoundingBox bb = way.computeBoundingBox();
      float bbLat = (Math.abs(lat - bb.getLatMin()) < Math.abs(lat
          - bb.getLatMax())) ? bb.getLatMin() : bb.getLatMax();
      float bbLon = (Math.abs(lon - bb.getLonMin()) < Math.abs(lon
          - bb.getLonMax())) ? bb.getLonMin() : bb.getLonMax();
      return getDistKM(lat, lon, bbLat, bbLon);
    }
    return Double.NaN;
  }

  public boolean insertInAscendingDistanceOrder(List<MapEntity> nodes,
      MapNode node) {
    int pos = getInsertPosition(nodes, node);
    if (pos != -1)
      nodes.add(pos, node);
    return pos != -1;
  }
 
  public boolean insertInAscendingDistanceOrder(List<MapEntity> ways,
      MapWay way) {
    int pos = getInsertPosition(ways, way);
    if (pos != -1)
      ways.add(pos, way);
    return pos != -1;
  }
 
  private int getInsertPosition(List<?> entities, MapEntity entity) {
    int pos1 = 0;
    int pos2 = entities.size();
    double newDistance = getDistKM(entity);
    while (pos1 < pos2) {
      int pos3 = (pos1 + pos2) / 2;
      double dist3 = getDistKM((MapEntity) entities.get(pos3));
      if (newDistance < dist3)
        pos2 = pos3;
      else if (newDistance > dist3)
        pos1 = pos3 + 1;
      else
        pos1 = pos2 = pos3;
    }
    if (pos1 < entities.size()) {
      for (int i = pos1; i >= 0
          && getDistKM((MapEntity) entities.get(i)) == newDistance; i--)
        if (entities.get(i) == entity)
          return -1;
      for (int i = pos1 + 1; i < entities.size()
          && getDistKM((MapEntity) entities.get(i)) == newDistance; i++)
        if (entities.get(i) == entity)
          return -1;
    }
    return pos1;
  }

  /**
   * Returns the node from <code>nodes</code> which is nearest to this
   * position. If a filter is given, only those nodes are inspected, which are
   * part of a way accepted by the filter.
   *
   * @param nodes
   * @param filter
   *            possibly null
   * @return A node or null
   */
  public MapNode selectNearest(Collection<MapNode> nodes, MapWayFilter filter) {
    MapNode result = null;
    double dist = Double.MAX_VALUE;
    double newDist;
    for (MapNode node : nodes) {
      newDist = getDistKM(node);
      boolean found = (newDist < dist);
      if (found && filter != null) {
        found = false;
        for (WayRef ref : node.getWayRefs()) {
          if (filter.isAccepted(ref.getWay()))
            found = true;
        }
      }
      if (found) {
        result = node;
        dist = newDist;
      }
    }
    return result;
  }

  /**
   * Computes a simple approximation of the compass course from this position
   * to the specified node.
   *
   * @param node
   * @return Number between 1 and 360
   */
  public int getCourseTo(MapNode node) {
    double lonCorr = Math.cos(Math.PI / 360.0 * (lat + node.getLat()));
    double latDist = node.getLat() - lat;
    double lonDist = lonCorr * (node.getLon() - lon);
    int course = (int) (180.0 / Math.PI * Math.atan2(lonDist, latDist));
    if (course <= 0)
      course += 360;
    return course;
  }

  /** Computes the total length of a track in kilometers. */
  public static double getTrackLengthKM(List<MapNode> nodes) {
    double result = 0.0;
    for (int i = 1; i < nodes.size(); i++) {
      MapNode n1 = nodes.get(i - 1);
      MapNode n2 = nodes.get(i);
      result += getDistKM(n1.getLat(), n1.getLon(), n2.getLat(), n2
          .getLon());
    }
    return result;
  }

  /**
   * Computes the distance between two positions on the earth surface using
   * the haversine formula.
   */
  public static double getDistKM(float lat1, float lon1, float lat2,
      float lon2) {
    double dLat = Math.toRadians(lat2 - lat1);
    double dLon = Math.toRadians(lon2 - lon1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
        + Math.cos(Math.toRadians(lat1))
        * Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
        * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return EARTH_RADIUS * c;
  }
}
 
TOP

Related Classes of aimax.osm.data.Position

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.