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

org.crazyyak.dev.net.google.maps.GoogleMapsUtils Maven / Gradle / Ivy

/*
 * Copyright 2012 Jacob D Parr
 *
 * 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
 *
 * http://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 org.crazyyak.dev.net.google.maps;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.crazyyak.dev.common.IoUtils;
import org.crazyyak.dev.common.exceptions.ApiException;
import org.crazyyak.dev.common.exceptions.ExceptionUtils;
import org.crazyyak.dev.domain.locality.*;
import org.crazyyak.dev.net.google.maps.directions.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.net.URLConnection;
import org.crazyyak.dev.domain.translation.jackson.YakJacksonMapper;

import static org.crazyyak.dev.common.StringUtils.encodeUrl;
import static org.crazyyak.dev.common.StringUtils.getTagContents;

public class GoogleMapsUtils {

  private static final BigDecimal kmToMilesRatio = new BigDecimal("0.621371");
  private static final BigDecimal metersToMilesRatio = new BigDecimal("0.000621371");
  private static final ObjectMapper objectMapper = new YakJacksonMapper();

  public static BigDecimal getMilesByGoogle(LatLng locationA, LatLng locationB) throws IOException {
    DrivingDirections directions = getDrivingDirections(locationA, locationB);

    Leg leg = directions.getRoutes()[0].getLegs()[0];
    long meters = leg.getDistance().getMeters();

    BigDecimal miles = metersToMilesRatio.multiply(new BigDecimal(meters));
    return miles.setScale(1, RoundingMode.HALF_EVEN);
  }

  public static BigDecimal getMilesByLatLng(LatLng locationA, LatLng locationB) {
    LatLng locationC = new LatLng(locationA.getLatitude(), locationB.getLongitude());

    BigDecimal firstLeg = calculateHaversineDistance(
      locationA.getLatitudeDouble(), locationA.getLongitudeDouble(),
      locationC.getLatitudeDouble(), locationC.getLongitudeDouble());

    BigDecimal secondLeg = calculateHaversineDistance(
      locationC.getLatitudeDouble(), locationC.getLongitudeDouble(),
      locationB.getLatitudeDouble(), locationB.getLongitudeDouble());

    BigDecimal miles = firstLeg.add(secondLeg);
    return miles.setScale(1, RoundingMode.HALF_EVEN);
  }

  public static DrivingDirections getDrivingDirections(LatLng locationA, LatLng locationB) throws IOException {
    // https://developers.google.com/maps/documentation/directions/

    ExceptionUtils.assertNotNull(locationA, "locationA");
    ExceptionUtils.assertNotNull(locationB, "locationB");

    String url = "http://maps.googleapis.com/maps/api/directions/json";
    url += String.format("?origin=%s,%s", locationA.getLatitude(), locationA.getLongitude());
    url += String.format("&destination=%s,%s", locationB.getLatitude(), locationB.getLongitude());
    url += "&sensor=false";

    URLConnection connection = new URL(url).openConnection();
    String json = IoUtils.toString(connection.getInputStream());

    DrivingDirections directions = objectMapper.readValue(json, DrivingDirections.class);

    if (directions.getStatus().isNotOK()) {
      String msg = String.format("Unable to compute driving directions: %s (%s)", directions.getStatus(), directions.getStatus().getDescription());
      throw ApiException.internalServerError(msg);
    }

    return directions;
  }

  public static BigDecimal calculateHaversineDistance(double userLat, double userLng, double venueLat, double venueLng) {

      double latDistance = Math.toRadians(userLat - venueLat);
      double lngDistance = Math.toRadians(userLng - venueLng);

      double a = (Math.sin(latDistance / 2) * Math.sin(latDistance / 2)) +
                      (Math.cos(Math.toRadians(userLat))) *
                      (Math.cos(Math.toRadians(venueLat))) *
                      (Math.sin(lngDistance / 2)) *
                      (Math.sin(lngDistance / 2));

      double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    BigDecimal kiloMeters = new BigDecimal(6372.797 * c);
    BigDecimal miles = kiloMeters.multiply(kmToMilesRatio);
    return miles.setScale(1, RoundingMode.HALF_EVEN);
  }

  public static LatLng getLatLng(String address, String city, State state, String zip) throws IOException {
    String st = (state == null) ? null : state.getAbbreviation();
    return getLatLng(address, city, st, zip);
  }

  public static LatLng getLatLng(String address, String city, String state, String zip) throws IOException {
    String url = "https://maps.googleapis.com/maps/api/geocode/xml?sensor=false&address=";
    url += encodeUrl(String.format("%s, %s, %s %s", address, city, state, zip));
    URLConnection connection = new URL(url).openConnection();
    String data = IoUtils.toString(connection.getInputStream());
    data = getTagContents(data, "location", 0);

    return new LatLng(
        getTagContents(data, "lat", 0),
        getTagContents(data, "lng", 0)
    );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy