All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.model.WgsCoordinate Maven / Gradle / Ivy

package org.opentripplanner.model;

import org.locationtech.jts.geom.Coordinate;
import org.opentripplanner.model.base.ValueObjectToStringBuilder;

import java.io.Serializable;

/**
 * This class represent a OTP coordinate.
 * 

* This is a ValueObject (design pattern). */ public final class WgsCoordinate implements Serializable { private static final String WHY_COORDINATE_DO_NOT_HAVE_HASH_EQUALS = "Use the 'sameLocation(..)' method to compare coordinates. See JavaDoc on 'equals(..)'"; /** * A epsilon of 1E-7 gives a precision for coordinates at equator at 1.1 cm, * which is good enough for compering most coordinates in OTP. */ private static final double EPSILON = 1E-7; private final double latitude; private final double longitude; public WgsCoordinate(double latitude, double longitude) { this.latitude = latitude; this.longitude = longitude; } /** * Unlike the constructor this factory method retuns {@code null} if both {@code lat} and * {@code lon} is {@code null}. */ public static WgsCoordinate creatOptionalCoordinate(Double latitude, Double longitude) { if(latitude == null && longitude == null) { return null; } // Set coordinate is both lat and lon exist if(latitude != null && longitude != null) { return new WgsCoordinate(latitude, longitude); } throw new IllegalArgumentException( "Both 'latitude' and 'longitude' must have a value or both must be 'null'." ); } public double latitude() { return latitude; } public double longitude() { return longitude; } /** Return OTP domain coordinate as JTS GeoTools Library coordinate. */ public Coordinate asJtsCoordinate() { return new Coordinate(longitude, latitude); } /** * Compare to coordinates and return {@code true} if they are close together - have the * same location. The comparison uses an EPSILON of 1E-7 for each axis, for both latitude and * longitude. */ public boolean sameLocation(WgsCoordinate other) { if (this == other) { return true; } return isCloseTo(latitude, other.latitude) && isCloseTo(longitude, other.longitude); } /** * Not supported, throws UnsupportedOperationException. When we compare to coordinates we want * see if they are within a given distance, roughly within a square centimeter. This is not * transitive, hence violating the equals/hasCode guideline. Consider 3 point along * one of the axis: *

     *  | 8mm | 8mm |
     *  x --- y --- z
     * 
* Then {@code x.sameLocation(y)} is {@code true} and {@code y.sameLocation(z)} is * {@code true}, but {@code x.sameLocation(z)} is {@code false}. *

* Use the {@link #sameLocation(WgsCoordinate)} method instead of equals, and never put this * class in a Set or use it as a key in a Map. * @throws UnsupportedOperationException if called. */ @Override public boolean equals(Object obj) { throw new UnsupportedOperationException(WHY_COORDINATE_DO_NOT_HAVE_HASH_EQUALS); } /** * @throws UnsupportedOperationException if called. See {@link #equals(Object)} */ @Override public int hashCode() { throw new UnsupportedOperationException(WHY_COORDINATE_DO_NOT_HAVE_HASH_EQUALS); } /** * Return a string on the form: {@code "(60.12345, 11.12345)"}. Up to 5 digits are used * after the period(.), even if the coordinate is specified with a higher precision. */ @Override public String toString() { return ValueObjectToStringBuilder.of().addCoordinate(latitude(), longitude()).toString(); } private static boolean isCloseTo(double a, double b) { double delta = Math.abs(a - b); return delta < EPSILON; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy