/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you 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 com.graphhopper;
import com.graphhopper.routing.util.HintsMap;
import com.graphhopper.util.Helper;
import com.graphhopper.util.shapes.GHPoint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* GraphHopper request wrapper to simplify requesting GraphHopper.
*
* @author Peter Karich
* @author ratrun
*/
public class GHRequest {
private final List<GHPoint> points;
private final HintsMap hints = new HintsMap();
// List of favored start (1st element) and arrival heading (all other).
// Headings are north based azimuth (clockwise) in (0, 360) or NaN for equal preference
private final List<Double> favoredHeadings;
private List<String> pointHints = new ArrayList<>();
private String algo = "";
private boolean possibleToAdd = false;
private Locale locale = Locale.US;
public GHRequest() {
this(5);
}
public GHRequest(int size) {
points = new ArrayList<GHPoint>(size);
favoredHeadings = new ArrayList<Double>(size);
possibleToAdd = true;
}
/**
* Set routing request from specified startPlace (fromLat, fromLon) to endPlace (toLat, toLon)
* with a preferred start and end heading. Headings are north based azimuth (clockwise) in (0,
* 360) or NaN for equal preference.
*/
public GHRequest(double fromLat, double fromLon, double toLat, double toLon,
double startHeading, double endHeading) {
this(new GHPoint(fromLat, fromLon), new GHPoint(toLat, toLon), startHeading, endHeading);
}
/**
* Set routing request from specified startPlace (fromLat, fromLon) to endPlace (toLat, toLon)
*/
public GHRequest(double fromLat, double fromLon, double toLat, double toLon) {
this(new GHPoint(fromLat, fromLon), new GHPoint(toLat, toLon));
}
/**
* Set routing request from specified startPlace to endPlace with a preferred start and end
* heading. Headings are north based azimuth (clockwise) in (0, 360) or NaN for equal preference
*/
public GHRequest(GHPoint startPlace, GHPoint endPlace, double startHeading, double endHeading) {
if (startPlace == null)
throw new IllegalStateException("'from' cannot be null");
if (endPlace == null)
throw new IllegalStateException("'to' cannot be null");
points = new ArrayList<GHPoint>(2);
points.add(startPlace);
points.add(endPlace);
favoredHeadings = new ArrayList<Double>(2);
validateAzimuthValue(startHeading);
favoredHeadings.add(startHeading);
validateAzimuthValue(endHeading);
favoredHeadings.add(endHeading);
}
public GHRequest(GHPoint startPlace, GHPoint endPlace) {
this(startPlace, endPlace, Double.NaN, Double.NaN);
}
/**
* Set routing request
* <p>
*
* @param points List of stopover points in order: start, 1st stop, 2nd stop, ..., end
* @param favoredHeadings List of favored headings for starting (start point) and arrival (via
* and end points) Headings are north based azimuth (clockwise) in (0, 360) or NaN for equal
*/
public GHRequest(List<GHPoint> points, List<Double> favoredHeadings) {
if (points.size() != favoredHeadings.size())
throw new IllegalArgumentException("Size of headings (" + favoredHeadings.size()
+ ") must match size of points (" + points.size() + ")");
for (Double heading : favoredHeadings) {
validateAzimuthValue(heading);
}
this.points = points;
this.favoredHeadings = favoredHeadings;
}
/**
* Set routing request
* <p>
*
* @param points List of stopover points in order: start, 1st stop, 2nd stop, ..., end
*/
public GHRequest(List<GHPoint> points) {
this(points, Collections.nCopies(points.size(), Double.NaN));
}
/**
* Add stopover point to routing request.
* <p>
*
* @param point geographical position (see GHPoint)
* @param favoredHeading north based azimuth (clockwise) in (0, 360) or NaN for equal preference
*/
public GHRequest addPoint(GHPoint point, double favoredHeading) {
if (point == null)
throw new IllegalArgumentException("point cannot be null");
if (!possibleToAdd)
throw new IllegalStateException("Please call empty constructor if you intent to use "
+ "more than two places via addPoint method.");
points.add(point);
validateAzimuthValue(favoredHeading);
favoredHeadings.add(favoredHeading);
return this;
}
/**
* Add stopover point to routing request.
* <p>
*
* @param point geographical position (see GHPoint)
*/
public GHRequest addPoint(GHPoint point) {
addPoint(point, Double.NaN);
return this;
}
/**
* @return north based azimuth (clockwise) in (0, 360) or NaN for equal preference
*/
public double getFavoredHeading(int i) {
return favoredHeadings.get(i);
}
/**
* @return if there exist a preferred heading for start/via/end point i
*/
public boolean hasFavoredHeading(int i) {
if (i >= favoredHeadings.size())
return false;
return !Double.isNaN(favoredHeadings.get(i));
}
private void validateAzimuthValue(double heading) {
// heading must be in (0, 360) oder NaN
if (!Double.isNaN(heading) && (Double.compare(heading, 360) > 0 || Double.compare(heading, 0) < 0))
throw new IllegalArgumentException("Heading " + heading + " must be in range (0,360) or NaN");
}
public List<GHPoint> getPoints() {
return points;
}
public String getAlgorithm() {
return algo;
}
/**
* For possible values see AlgorithmOptions.*
*/
public GHRequest setAlgorithm(String algo) {
if (algo != null)
this.algo = Helper.camelCaseToUnderScore(algo);
return this;
}
public Locale getLocale() {
return locale;
}
public GHRequest setLocale(Locale locale) {
if (locale != null)
this.locale = locale;
return this;
}
public GHRequest setLocale(String localeStr) {
return setLocale(Helper.getLocale(localeStr));
}
public String getWeighting() {
return hints.getWeighting();
}
/**
* By default it supports fastest and shortest. Or specify empty to use default.
*/
public GHRequest setWeighting(String w) {
hints.setWeighting(w);
return this;
}
public String getVehicle() {
return hints.getVehicle();
}
/**
* Specify car, bike or foot. Or specify empty to use default.
*/
public GHRequest setVehicle(String vehicle) {
hints.setVehicle(vehicle);
return this;
}
public HintsMap getHints() {
return hints;
}
public GHRequest setPointHints(List<String> pointHints) {
this.pointHints = pointHints;
return this;
}
public List<String> getPointHints() {
return pointHints;
}
public boolean hasPointHints() {
return pointHints.size() == points.size();
}
@Override
public String toString() {
String res = "";
for (GHPoint point : points) {
if (res.isEmpty()) {
res = point.toString();
} else {
res += "; " + point.toString();
}
}
return res + "(" + algo + ")";
}
}