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

com.google.appengine.api.datastore.GeoPt Maven / Gradle / Ivy

/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.appengine.api.datastore;

import java.io.Serializable;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A geographical point, specified by float latitude and longitude coordinates. Often used to
 * integrate with mapping sites like Google Maps.
 */
// TODO: Make the file GWT-compatible (Float.floatToIntBits(float)
// and String.format(String, float, float) is not implemented in GWT).
// Once done add this file to the gwt-datastore BUILD target.
public final class GeoPt implements Serializable, Comparable {

  public static final long serialVersionUID = 349808987517153697L;

  // This attribute needs to be non-final to support GWT serialization
  private float latitude;
  // This attribute needs to be non-final to support GWT serialization
  private float longitude;

  /**
   * Constructs a {@code GeoPt}.
   *
   * @param latitude The latitude. Must be between -90 and 90 (inclusive).
   * @param longitude The longitude. Must be between -180 and 180 (inclusive).
   * @throws IllegalArgumentException If {@code latitude} or {@code longitude} is outside the legal
   *     range.
   */
  public GeoPt(float latitude, float longitude) {
    if (Math.abs(latitude) > 90) {
      throw new IllegalArgumentException("Latitude must be between -90 and 90 (inclusive).");
    }

    if (Math.abs(longitude) > 180) {
      throw new IllegalArgumentException("Longitude must be between -180 and 180.");
    }

    this.latitude = latitude;
    this.longitude = longitude;
  }

  /**
   * This constructor exists for frameworks (e.g. Google Web Toolkit) that require it for
   * serialization purposes. It should not be called explicitly.
   */
  @SuppressWarnings("unused")
  private GeoPt() {
    this(0, 0);
  }

  public float getLatitude() {
    return latitude;
  }

  public float getLongitude() {
    return longitude;
  }

  /** Sort first by latitude, then by longitude */
  @Override
  public int compareTo(GeoPt o) {
    int latResult = ((Float) latitude).compareTo(o.latitude);
    if (latResult != 0) {
      return latResult;
    }
    return ((Float) longitude).compareTo(o.longitude);
  }

  @Override
  public boolean equals(@Nullable Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    GeoPt geoPt = (GeoPt) o;

    if (Float.compare(geoPt.latitude, latitude) != 0) {
      return false;
    }
    if (Float.compare(geoPt.longitude, longitude) != 0) {
      return false;
    }

    return true;
  }

  @Override
  public int hashCode() {
    int result;
    result = (latitude != +0.0f ? Float.floatToIntBits(latitude) : 0);
    result = 31 * result + (longitude != +0.0f ? Float.floatToIntBits(longitude) : 0);
    return result;
  }

  @Override
  public String toString() {
    return String.format("%f,%f", latitude, longitude);
  }

  /**
   * Computes the "distance" between two points on a sphere the size of the Earth.
   *
   * 

http://en.wikipedia.org/wiki/Haversine_formula */ // TODO: shall we make this an instance method (it feels similar in structure to // an equals() method)? static double distance(GeoPt p1, GeoPt p2) { double latitude = Math.toRadians(p1.getLatitude()); double longitude = Math.toRadians(p1.getLongitude()); double otherLatitude = Math.toRadians(p2.getLatitude()); double otherLongitude = Math.toRadians(p2.getLongitude()); double deltaLat = latitude - otherLatitude; double deltaLong = longitude - otherLongitude; double a1 = haversin(deltaLat); double a2 = Math.cos(latitude) * Math.cos(otherLatitude) * haversin(deltaLong); return 2 * EARTH_RADIUS_METERS * Math.asin(Math.sqrt(a1 + a2)); } static double haversin(double delta) { double x = Math.sin(delta / 2); return x * x; } public static final double EARTH_RADIUS_METERS = 6371010d; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy