content: /**
   * Container for an osm node
   *
   * @author ab
   */
  package btools.router;
  
  import btools.mapaccess.OsmNode;
  import btools.util.CheapRuler;
  
  public class OsmNodeNamed extends OsmNode {
    public String name;
    public double radius; // radius of nogopoint (in meters)
    public double nogoWeight;  // weight for nogopoint
    public boolean isNogo = false;
    public boolean direct = false; // mark direct routing
  
    public OsmNodeNamed() {
    }
  
    public OsmNodeNamed(OsmNode n) {
      super(n.ilon, n.ilat);
    }
  
    @Override
    public String toString() {
      if (Double.isNaN(nogoWeight)) {
        return ilon + "," + ilat + "," + name;
      } else {
        return ilon + "," + ilat + "," + name + "," + nogoWeight;
      }
    }
  
    public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
      double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lat1 + lat2) >> 1);
  
      boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius;
      boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
      // First point is within the circle
      if (isFirstPointWithinCircle) {
        // Last point is within the circle
        if (isLastPointWithinCircle) {
          return totalSegmentLength;
        }
        // Last point is not within the circle
        // Just swap points and go on with first first point not within the
        // circle now.
        // Swap longitudes
        int tmp = lon2;
        lon2 = lon1;
        lon1 = tmp;
        // Swap latitudes
        tmp = lat2;
        lat2 = lat1;
        lat1 = tmp;
        // Fix boolean values
        isLastPointWithinCircle = isFirstPointWithinCircle;
        isFirstPointWithinCircle = false;
      }
      // Distance between the initial point and projection of center of
      // the circle on the current segment.
      double initialToProject = (
        (lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
          + (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
      ) / totalSegmentLength;
      // Distance between the initial point and the center of the circle.
      double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
      // Half length of the segment within the circle
      double halfDistanceWithin = Math.sqrt(
        radius * radius - (
          initialToCenter * initialToCenter -
            initialToProject * initialToProject
        )
      );
      // Last point is within the circle
      if (isLastPointWithinCircle) {
        return halfDistanceWithin + (totalSegmentLength - initialToProject);
      }
      return 2 * halfDistanceWithin;
    }
  
    public static OsmNodeNamed decodeNogo(String s) {
      OsmNodeNamed n = new OsmNodeNamed();
      int idx1 = s.indexOf(',');
      n.ilon = Integer.parseInt(s.substring(0, idx1));
      int idx2 = s.indexOf(',', idx1 + 1);
      n.ilat = Integer.parseInt(s.substring(idx1 + 1, idx2));
      int idx3 = s.indexOf(',', idx2 + 1);
      if (idx3 == -1) {
        n.name = s.substring(idx2 + 1);
        n.nogoWeight = Double.NaN;
      } else {
        n.name = s.substring(idx2 + 1, idx3);
        n.nogoWeight = Double.parseDouble(s.substring(idx3 + 1));
      }
      n.isNogo = true;
      return n;
    }
  }
  