working with new version of osmdroidtags/release-v3.5
@@ -0,0 +1 @@ | |||
/build |
@@ -0,0 +1,36 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
ext { | |||
name = 'AnyMaps - Base Library' | |||
artifactId = 'anymaps.base' | |||
description = 'Base library for AnyMaps libraries. Contains common interface' | |||
} | |||
apply plugin: 'com.android.library' | |||
apply plugin: 'maven' | |||
android { | |||
compileSdkVersion 28 | |||
buildToolsVersion "28.0.3" | |||
defaultConfig { | |||
minSdkVersion 15 | |||
targetSdkVersion 28 | |||
versionCode 1 | |||
versionName "1.0" | |||
} | |||
buildTypes { | |||
release { | |||
minifyEnabled false | |||
} | |||
} | |||
} | |||
dependencies { | |||
implementation 'com.android.support:support-annotations:28.0.0' | |||
testImplementation 'junit:junit:4.12' | |||
} |
@@ -0,0 +1,7 @@ | |||
<!-- | |||
~ Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
~ | |||
~ All rights reserved | |||
--> | |||
<manifest package="com.car2go.maps"/> |
@@ -0,0 +1,165 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
import android.view.View; | |||
import com.car2go.maps.model.CameraPosition; | |||
import com.car2go.maps.model.Circle; | |||
import com.car2go.maps.model.CircleOptions; | |||
import com.car2go.maps.model.LatLng; | |||
import com.car2go.maps.model.Marker; | |||
import com.car2go.maps.model.MarkerOptions; | |||
import com.car2go.maps.model.Polygon; | |||
import com.car2go.maps.model.PolygonOptions; | |||
import com.car2go.maps.model.Polyline; | |||
import com.car2go.maps.model.PolylineOptions; | |||
/** | |||
* Provider-independent map controller. Originally was designed to mimic Google Map API and being | |||
* adapted to other providers. For detailed documentation on each method please refer Google Maps | |||
* documentation. | |||
*/ | |||
public interface AnyMap { | |||
void moveCamera(CameraUpdate cameraUpdate); | |||
void animateCamera(CameraUpdate cameraUpdate); | |||
void animateCamera(CameraUpdate cameraUpdate, CancelableCallback callback); | |||
void animateCamera(CameraUpdate cameraUpdate, int duration, CancelableCallback callback); | |||
CameraPosition getCameraPosition(); | |||
Projection getProjection(); | |||
Marker addMarker(MarkerOptions options); | |||
Circle addCircle(CircleOptions options); | |||
Polygon addPolygon(PolygonOptions options); | |||
Polyline addPolyline(PolylineOptions options); | |||
UiSettings getUiSettings(); | |||
void setOnMapClickListener(OnMapClickListener listener); | |||
void setOnMapLongClickListener(OnMapLongClickListener listener); | |||
void setOnCameraChangeListener(OnCameraChangeListener listener); | |||
void setOnMarkerClickListener(OnMarkerClickListener listener); | |||
void setInfoWindowAdapter(InfoWindowAdapter adapter); | |||
void setTrafficEnabled(boolean enabled); | |||
void setMyLocationEnabled(boolean enabled); | |||
void setMapType(Type type); | |||
void setPadding(int left, int top, int right, int bottom); | |||
void onUserLocationChanged(LatLng location, float accuracy); | |||
enum Type { | |||
NORMAL, | |||
SATELLITE | |||
} | |||
/** | |||
* Features of {@link AnyMap} which might be supported or not supported | |||
* by each particular implementation. | |||
*/ | |||
enum Feature { | |||
/** | |||
* Displaying layer with traffic jams on the map | |||
*/ | |||
TRAFFIC_LAYER, | |||
/** | |||
* Supporting several {@link com.car2go.maps.AnyMap.Type}. If this capability is not present, | |||
* only one of types is implemented (which one - is not specified). | |||
*/ | |||
MAP_TYPES, | |||
/** | |||
* Supports being invisible at first and being revealed (or simply made visible) later on. | |||
*/ | |||
REVEALABLE | |||
} | |||
interface OnMapClickListener { | |||
OnMapClickListener NULL = new OnMapClickListener() { | |||
@Override | |||
public void onMapClick(LatLng latLng) { | |||
// Do nothing | |||
} | |||
}; | |||
void onMapClick(LatLng latLng); | |||
} | |||
interface OnMapLongClickListener { | |||
OnMapLongClickListener NULL = new OnMapLongClickListener() { | |||
@Override | |||
public void onMapLongClick(LatLng latLng) { | |||
// Do nothing | |||
} | |||
}; | |||
void onMapLongClick(LatLng latLng); | |||
} | |||
interface OnCameraChangeListener { | |||
void onCameraChange(CameraPosition cameraPosition); | |||
} | |||
interface OnMarkerClickListener { | |||
OnMarkerClickListener NULL = new OnMarkerClickListener() { | |||
@Override | |||
public boolean onMarkerClick(Marker marker) { | |||
// Do nothing | |||
return false; | |||
} | |||
}; | |||
boolean onMarkerClick(Marker marker); | |||
} | |||
interface CancelableCallback { | |||
void onFinish(); | |||
void onCancel(); | |||
} | |||
interface InfoWindowAdapter { | |||
View getInfoWindow(Marker marker); | |||
View getInfoContents(Marker marker); | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
import android.graphics.Bitmap; | |||
import android.support.annotation.DrawableRes; | |||
import com.car2go.maps.model.BitmapDescriptor; | |||
/** | |||
* Factory for creating BitmapDescriptors. | |||
*/ | |||
public interface BitmapDescriptorFactory { | |||
/** | |||
* @return new {@link BitmapDescriptor} from given {@link Bitmap} | |||
*/ | |||
BitmapDescriptor fromBitmap(Bitmap bitmap); | |||
/** | |||
* @return new {@link BitmapDescriptor} from given resource | |||
*/ | |||
BitmapDescriptor fromResource(@DrawableRes int resourceId); | |||
} |
@@ -0,0 +1,13 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
/** | |||
* Mimics Google CameraUpdate | |||
*/ | |||
public interface CameraUpdate { | |||
} |
@@ -0,0 +1,31 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
import com.car2go.maps.model.LatLng; | |||
import com.car2go.maps.model.LatLngBounds; | |||
/** | |||
* Creates {@link CameraUpdate} objects which can be used to update map camera | |||
*/ | |||
public interface CameraUpdateFactory { | |||
/** | |||
* @return {@link CameraUpdate} which moves camera to given position with given zoom level. | |||
*/ | |||
CameraUpdate newLatLngZoom(LatLng latLng, float zoomLevel); | |||
/** | |||
* @return {@link CameraUpdate} which moves camera so it displays given bounds with given padding. | |||
*/ | |||
CameraUpdate newLatLngBounds(LatLngBounds bounds, int padding); | |||
/** | |||
* @return {@link CameraUpdate} which zooms camera to given zoom level. | |||
*/ | |||
CameraUpdate zoomTo(float zoomLevel); | |||
} |
@@ -0,0 +1,68 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
import android.content.Context; | |||
import android.os.Bundle; | |||
import android.util.AttributeSet; | |||
import android.widget.FrameLayout; | |||
/** | |||
* View container for an {@link AnyMap}. | |||
*/ | |||
public abstract class MapContainerView extends FrameLayout { | |||
protected MapContainerView(Context context) { | |||
super(context); | |||
} | |||
protected MapContainerView(Context context, AttributeSet attrs) { | |||
super(context, attrs); | |||
} | |||
/** | |||
* Gets the wrapped {@link AnyMap} asynchronously. | |||
* | |||
* @param callback the callback to use when the map has been got | |||
*/ | |||
public abstract void getMapAsync(OnMapReadyCallback callback); | |||
/** | |||
* Propagate the onCreate lifecycle call to the AnyMap. | |||
* | |||
* @param savedInstanceState the savedInstanceState | |||
*/ | |||
public abstract void onCreate(Bundle savedInstanceState); | |||
/** | |||
* Propagate the onResume lifecycle call to the AnyMap. | |||
*/ | |||
public abstract void onResume(); | |||
/** | |||
* Propagate the onPause lifecycle call to the AnyMap. | |||
*/ | |||
public abstract void onPause(); | |||
/** | |||
* Propagate the onDestroy lifecycle call to the AnyMap. | |||
*/ | |||
public abstract void onDestroy(); | |||
/** | |||
* Propagate the onLowMemory lifecycle call to the AnyMap. | |||
*/ | |||
public abstract void onLowMemory(); | |||
/** | |||
* Propagate the onSaveInstanceState lifecycle call to the AnyMap. | |||
* | |||
* @param outState the outState | |||
*/ | |||
public abstract void onSaveInstanceState(Bundle outState); | |||
} |
@@ -0,0 +1,32 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
import android.content.Context; | |||
import java.util.Set; | |||
/** | |||
* A util class for initializing the map and retrieving its capabilities. | |||
*/ | |||
public interface MapsConfiguration { | |||
/** | |||
* Initializes the maps. | |||
* | |||
* @param context the context | |||
*/ | |||
void initialize(Context context); | |||
/** | |||
* Gets the supported features of the {@link AnyMap} implementation. If some features are not supported | |||
* and you will try to call them - nothing will happen. | |||
* | |||
* @return capabilities of the {@link AnyMap} implementation. | |||
*/ | |||
Set<AnyMap.Feature> getSupportedFeatures(); | |||
} |
@@ -0,0 +1,16 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
/** | |||
* Mimics Google OnMapReadyCallback | |||
*/ | |||
public interface OnMapReadyCallback { | |||
void onMapReady(AnyMap anyMap); | |||
} |
@@ -0,0 +1,18 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
import com.car2go.maps.model.VisibleRegion; | |||
/** | |||
* Mimics Google Projection | |||
*/ | |||
public interface Projection { | |||
VisibleRegion getVisibleRegion(); | |||
} |
@@ -0,0 +1,20 @@ | |||
/* | |||
* Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps; | |||
/** | |||
* Mimics Google UiSettings | |||
*/ | |||
public interface UiSettings { | |||
void setAllGesturesEnabled(boolean enabled); | |||
void setMyLocationButtonEnabled(boolean enabled); | |||
void setMapToolbarEnabled(boolean enabled); | |||
} |
@@ -0,0 +1,13 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
/** | |||
* Mimics Google BitmapDescriptor | |||
*/ | |||
public interface BitmapDescriptor { | |||
} |
@@ -0,0 +1,88 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.os.Parcel; | |||
import android.os.Parcelable; | |||
/** | |||
* Contains information about camera position on the map. | |||
* Immutable. | |||
*/ | |||
public class CameraPosition implements Parcelable { | |||
/** | |||
* Center of the camera viewport | |||
*/ | |||
public final LatLng target; | |||
/** | |||
* Zoom level of the camera | |||
*/ | |||
public final float zoom; | |||
public CameraPosition(LatLng target, float zoom) { | |||
this.target = target; | |||
this.zoom = zoom; | |||
} | |||
protected CameraPosition(Parcel in) { | |||
this.target = in.readParcelable(LatLng.class.getClassLoader()); | |||
this.zoom = in.readFloat(); | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (!(o instanceof CameraPosition)) { | |||
return false; | |||
} | |||
CameraPosition that = (CameraPosition) o; | |||
return Float.compare(that.zoom, zoom) == 0 && target.equals(that.target); | |||
} | |||
@Override | |||
public int hashCode() { | |||
int result = target.hashCode(); | |||
result = 31 * result + (zoom != +0.0f ? Float.floatToIntBits(zoom) : 0); | |||
return result; | |||
} | |||
@Override | |||
public String toString() { | |||
return "CameraPosition{" + | |||
"target=" + target + | |||
", zoom=" + zoom + | |||
'}'; | |||
} | |||
@Override | |||
public int describeContents() { | |||
return 0; | |||
} | |||
@Override | |||
public void writeToParcel(Parcel dest, int flags) { | |||
dest.writeParcelable(this.target, flags); | |||
dest.writeFloat(this.zoom); | |||
} | |||
public static final Creator<CameraPosition> CREATOR = new Creator<CameraPosition>() { | |||
public CameraPosition createFromParcel(Parcel source) { | |||
return new CameraPosition(source); | |||
} | |||
public CameraPosition[] newArray(int size) { | |||
return new CameraPosition[size]; | |||
} | |||
}; | |||
} |
@@ -0,0 +1,13 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
/** | |||
* Draws circle on the map | |||
*/ | |||
public interface Circle extends DrawableComponent { | |||
} |
@@ -0,0 +1,102 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.support.annotation.ColorInt; | |||
/** | |||
* Accumulates parameters which are required to create {@link Circle} component. | |||
* Mutable. | |||
*/ | |||
public class CircleOptions { | |||
private LatLng center; | |||
private double radius; | |||
private int fillColor; | |||
private int strokeColor; | |||
private float strokeWidth; | |||
/** | |||
* @param point center of the circle | |||
* @return same {@link CircleOptions} | |||
*/ | |||
public CircleOptions center(LatLng point) { | |||
center = point; | |||
return this; | |||
} | |||
/** | |||
* @param radius radius of the circle in meters | |||
* @return same {@link CircleOptions} | |||
*/ | |||
public CircleOptions radius(double radius) { | |||
this.radius = radius; | |||
return this; | |||
} | |||
/** | |||
* @param color color used to fill the circle | |||
* @return same {@link CircleOptions} | |||
*/ | |||
public CircleOptions fillColor(@ColorInt int color) { | |||
fillColor = color; | |||
return this; | |||
} | |||
/** | |||
* @param color color of the circle outline (stroke) | |||
* @return same {@link CircleOptions} | |||
*/ | |||
public CircleOptions strokeColor(@ColorInt int color) { | |||
strokeColor = color; | |||
return this; | |||
} | |||
/** | |||
* @param width width of the stroke in pixels | |||
* @return same {@link CircleOptions} | |||
*/ | |||
public CircleOptions strokeWidth(float width) { | |||
strokeWidth = width; | |||
return this; | |||
} | |||
/** | |||
* @see #center(LatLng) | |||
*/ | |||
public LatLng getCenter() { | |||
return center; | |||
} | |||
/** | |||
* @see #radius(double) | |||
*/ | |||
public double getRadius() { | |||
return radius; | |||
} | |||
/** | |||
* @see #fillColor(int) | |||
*/ | |||
public int getFillColor() { | |||
return fillColor; | |||
} | |||
/** | |||
* @see #strokeColor(int) | |||
*/ | |||
public int getStrokeColor() { | |||
return strokeColor; | |||
} | |||
/** | |||
* @see #strokeWidth(float) | |||
*/ | |||
public float getStrokeWidth() { | |||
return strokeWidth; | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
/** | |||
* Entity which can be drawn on map | |||
*/ | |||
public interface DrawableComponent { | |||
/** | |||
* Changes visibility of the component | |||
* | |||
* @param visible {@code true} to make component visible. | |||
* {@code false} to make component invisible. | |||
*/ | |||
void setVisible(boolean visible); | |||
/** | |||
* Removes component from the map. If it's already removed, does nothing. | |||
*/ | |||
void remove(); | |||
} |
@@ -0,0 +1,14 @@ | |||
package com.car2go.maps.model; | |||
/** | |||
* Defines handling of geofences | |||
*/ | |||
public interface Geofence { | |||
/** | |||
* Checks if a location is inside the geofence or not | |||
* @param latLng location to change | |||
* @return {@code true} if location is inside the geofence | |||
*/ | |||
public boolean contains(LatLng latLng); | |||
} |
@@ -0,0 +1,96 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.location.Location; | |||
import android.os.Parcel; | |||
import android.os.Parcelable; | |||
/** | |||
* Latitude/Longitude pair. | |||
* Immutable. | |||
*/ | |||
public class LatLng implements Parcelable { | |||
/** | |||
* Latitude on the map | |||
*/ | |||
public final double latitude; | |||
/** | |||
* Longitude on the map | |||
*/ | |||
public final double longitude; | |||
public static LatLng fromLocation(Location location) { | |||
return new LatLng(location.getLatitude(), location.getLongitude()); | |||
} | |||
public LatLng(double latitude, double longitude) { | |||
this.latitude = latitude; | |||
this.longitude = longitude; | |||
} | |||
protected LatLng(Parcel in) { | |||
this.latitude = in.readDouble(); | |||
this.longitude = in.readDouble(); | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (!(o instanceof LatLng)) { | |||
return false; | |||
} | |||
LatLng latLng = (LatLng) o; | |||
return Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0; | |||
} | |||
@Override | |||
public int hashCode() { | |||
int result; | |||
long temp; | |||
temp = Double.doubleToLongBits(latitude); | |||
result = (int) (temp ^ (temp >>> 32)); | |||
temp = Double.doubleToLongBits(longitude); | |||
result = 31 * result + (int) (temp ^ (temp >>> 32)); | |||
return result; | |||
} | |||
@Override | |||
public String toString() { | |||
return "LatLng{" + | |||
"latitude=" + latitude + | |||
", longitude=" + longitude + | |||
'}'; | |||
} | |||
@Override | |||
public int describeContents() { | |||
return 0; | |||
} | |||
@Override | |||
public void writeToParcel(Parcel dest, int flags) { | |||
dest.writeDouble(this.latitude); | |||
dest.writeDouble(this.longitude); | |||
} | |||
public static final Creator<LatLng> CREATOR = new Creator<LatLng>() { | |||
public LatLng createFromParcel(Parcel source) { | |||
return new LatLng(source); | |||
} | |||
public LatLng[] newArray(int size) { | |||
return new LatLng[size]; | |||
} | |||
}; | |||
} |
@@ -0,0 +1,171 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.os.Parcel; | |||
import android.os.Parcelable; | |||
/** | |||
* (Pseudo)Rectangular region on the map. | |||
* Immutable. | |||
*/ | |||
public class LatLngBounds implements Parcelable { | |||
/** | |||
* South-West point of the region. | |||
*/ | |||
public final LatLng southwest; | |||
/** | |||
* North-East point of the region. | |||
*/ | |||
public final LatLng northeast; | |||
public LatLngBounds(LatLng southwest, LatLng northeast) { | |||
this.southwest = southwest; | |||
this.northeast = northeast; | |||
} | |||
protected LatLngBounds(Parcel in) { | |||
this.southwest = in.readParcelable(LatLng.class.getClassLoader()); | |||
this.northeast = in.readParcelable(LatLng.class.getClassLoader()); | |||
} | |||
/** | |||
* @return {@link com.car2go.maps.model.LatLngBounds.Builder} for {@link LatLngBounds} | |||
*/ | |||
public static Builder builder() { | |||
return new Builder(); | |||
} | |||
/** | |||
* @return center of the region | |||
*/ | |||
public LatLng getCenter() { | |||
// Implementation copied from original obfuscated version of LatLngBounds | |||
double var1 = (this.southwest.latitude + this.northeast.latitude) / 2.0D; | |||
double var3 = this.northeast.longitude; | |||
double var5 = this.southwest.longitude; | |||
double var7; | |||
if (var5 <= var3) { | |||
var7 = (var3 + var5) / 2.0D; | |||
} else { | |||
var7 = (var3 + 360.0D + var5) / 2.0D; | |||
} | |||
return new LatLng(var1, var7); | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) return true; | |||
if (!(o instanceof LatLngBounds)) return false; | |||
LatLngBounds that = (LatLngBounds) o; | |||
return southwest.equals(that.southwest) && northeast.equals(that.northeast); | |||
} | |||
@Override | |||
public int hashCode() { | |||
int result = southwest.hashCode(); | |||
result = 31 * result + northeast.hashCode(); | |||
return result; | |||
} | |||
@Override | |||
public String toString() { | |||
return "LatLngBounds{" + | |||
"southwest=" + southwest + | |||
", northeast=" + northeast + | |||
'}'; | |||
} | |||
@Override | |||
public int describeContents() { | |||
return 0; | |||
} | |||
@Override | |||
public void writeToParcel(Parcel dest, int flags) { | |||
dest.writeParcelable(this.southwest, 0); | |||
dest.writeParcelable(this.northeast, 0); | |||
} | |||
public static final Parcelable.Creator<LatLngBounds> CREATOR = new Parcelable.Creator<LatLngBounds>() { | |||
public LatLngBounds createFromParcel(Parcel source) { | |||
return new LatLngBounds(source); | |||
} | |||
public LatLngBounds[] newArray(int size) { | |||
return new LatLngBounds[size]; | |||
} | |||
}; | |||
/** | |||
* Builds new instances of {@link LatLngBounds} | |||
*/ | |||
public static class Builder { | |||
private double southWestLattitude = 1.0D / 0.0; | |||
private double northEastLattitude = -1.0D / 0.0; | |||
private double southWestLongitude = 0.0D / 0.0; | |||
private double northEastLongitude = 0.0D / 0.0; | |||
/** | |||
* Ensures that given point will be within output bounds. Output bounds guaranteed to be | |||
* as small as possible and enclose all given points. | |||
* | |||
* @return same {@link com.car2go.maps.model.LatLngBounds.Builder} | |||
*/ | |||
public Builder include(LatLng point) { | |||
southWestLattitude = Math.min(southWestLattitude, point.latitude); | |||
northEastLattitude = Math.max(northEastLattitude, point.latitude); | |||
if (Double.isNaN(southWestLongitude)) { | |||
southWestLongitude = point.longitude; | |||
northEastLongitude = point.longitude; | |||
} else if (!withinBounds(point.longitude)) { | |||
if (degreeDifference(southWestLongitude, point.longitude) < degreeDifference(point.longitude, northEastLongitude)) { | |||
southWestLongitude = point.longitude; | |||
} else { | |||
northEastLongitude = point.longitude; | |||
} | |||
} | |||
return this; | |||
} | |||
private double degreeDifference(double first, double second) { | |||
return (first - second + 360.0D) % 360.0D; | |||
} | |||
private boolean withinBounds(double longitude) { | |||
return this.southWestLongitude <= this.northEastLongitude | |||
? this.southWestLongitude <= longitude && longitude <= this.northEastLongitude | |||
: this.southWestLongitude <= longitude || longitude <= this.northEastLongitude; | |||
} | |||
/** | |||
* @return new instance of {@link LatLngBounds} | |||
* @throws IllegalStateException if less than 2 unique points were specified | |||
*/ | |||
public LatLngBounds build() { | |||
if (Double.isNaN(southWestLongitude)) { | |||
throw new IllegalStateException("No included points"); | |||
} | |||
return new LatLngBounds( | |||
new LatLng(southWestLattitude, southWestLongitude), | |||
new LatLng(northEastLattitude, northEastLongitude) | |||
); | |||
} | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* Copyright (c) 2016 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.graphics.Bitmap; | |||
/** | |||
* Draws marker (with icon) on the map | |||
*/ | |||
public interface Marker extends DrawableComponent { | |||
/** | |||
* Changes icon of the marker to given {@link Bitmap} | |||
*/ | |||
void setIcon(BitmapDescriptor icon); | |||
/** | |||
* @return current position of the marker | |||
*/ | |||
LatLng getPosition(); | |||
/** | |||
* Shows information window associated with this marker, if any. | |||
*/ | |||
void showInfoWindow(); | |||
/** | |||
* Sets the rotation of the marker. | |||
* | |||
* @param rotation the rotation value | |||
*/ | |||
void setRotation(float rotation); | |||
/** | |||
* Sets the Z index of the marker | |||
* | |||
* @param z z index of the marker | |||
*/ | |||
void setZ(int z); | |||
} |
@@ -0,0 +1,128 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
/** | |||
* Accumulates parameters which are required to create {@link Marker} component. | |||
* Mutable. | |||
*/ | |||
public class MarkerOptions { | |||
private float alpha = 1f; | |||
private LatLng position; | |||
private boolean visible = true; | |||
private float anchorU = 0f; | |||
private float anchorV = 0f; | |||
private BitmapDescriptor icon; | |||
private int z = 0; | |||
/** | |||
* @param alpha alpha-level of the marker. In range [0..1]. Default value is 1. | |||
* @return same {@link MarkerOptions} | |||
*/ | |||
public MarkerOptions alpha(float alpha) { | |||
this.alpha = alpha; | |||
return this; | |||
} | |||
/** | |||
* @param position position of the marker's anchor on the map | |||
* @return same {@link MarkerOptions} | |||
*/ | |||
public MarkerOptions position(LatLng position) { | |||
this.position = position; | |||
return this; | |||
} | |||
/** | |||
* @param visible {@code true} to make marker visible by default. {@code false} to make marker | |||
* invisible by default. Default value is {@code true}. | |||
* @return same {@link MarkerOptions} | |||
*/ | |||
public MarkerOptions visible(boolean visible) { | |||
this.visible = visible; | |||
return this; | |||
} | |||
/** | |||
* Specifies anchor of the marker (which part of marker's icon is considered position of the | |||
* marker on the map). (0, 0) denotes top left corner. (1, 1) denotes bottom right corner. | |||
* | |||
* @param u U coordinate of the anchor relatively to the icon. Default value is 0. | |||
* @param v V coordinate of the anchor relatively to the icon. Default value is 0. | |||
* @return same {@link MarkerOptions} | |||
*/ | |||
public MarkerOptions anchor(float u, float v) { | |||
anchorU = u; | |||
anchorV = v; | |||
return this; | |||
} | |||
/** | |||
* @param icon icon of the marker | |||
* @return same {@link MarkerOptions} | |||
*/ | |||
public MarkerOptions icon(BitmapDescriptor icon) { | |||
this.icon = icon; | |||
return this; | |||
} | |||
public MarkerOptions z(int z) { | |||
this.z = z; | |||
return this; | |||
} | |||
/** | |||
* @see #alpha(float) | |||
*/ | |||
public float getAlpha() { | |||
return alpha; | |||
} | |||
/** | |||
* @see #position(LatLng) | |||
*/ | |||
public LatLng getPosition() { | |||
return position; | |||
} | |||
/** | |||
* @see #visible(boolean) | |||
*/ | |||
public boolean isVisible() { | |||
return visible; | |||
} | |||
/** | |||
* @see #anchor(float, float) | |||
*/ | |||
public float getAnchorU() { | |||
return anchorU; | |||
} | |||
/** | |||
* @see #anchor(float, float) | |||
*/ | |||
public float getAnchorV() { | |||
return anchorV; | |||
} | |||
/** | |||
* @see #icon(BitmapDescriptor) | |||
*/ | |||
public BitmapDescriptor getIcon() { | |||
return icon; | |||
} | |||
/** | |||
* @see #z(int) | |||
*/ | |||
public int getZ() { | |||
return z; | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import java.util.List; | |||
/** | |||
* Draws polygon on the map. Might contain holes within the polygon. | |||
*/ | |||
public interface Polygon extends DrawableComponent { | |||
/** | |||
* @param holes holes within the polygon area. If holes are outside of the polygon, behavior | |||
* is undefined. | |||
*/ | |||
void setHoles(List<List<LatLng>> holes); | |||
/** | |||
* @return a snapshot of the vertices of this polygon at this time. | |||
* The list returned is a copy of the list of vertices and so changes to the polygon's vertices | |||
* will not be reflected by this list, nor will changes to this list be reflected by the polygon. | |||
*/ | |||
List<LatLng> getPoints(); | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.support.annotation.ColorInt; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* Accumulates parameters which are required to create {@link Polygon} component. | |||
* Mutable. | |||
*/ | |||
public class PolygonOptions { | |||
private final List<LatLng> points = new ArrayList<>(); | |||
private int fillColor; | |||
private float strokeWidth; | |||
private int strokeColor; | |||
private boolean outsider = false; | |||
/** | |||
* @param color color used to fill the polygon | |||
* @return same {@link PolygonOptions} | |||
*/ | |||
public PolygonOptions fillColor(@ColorInt int color) { | |||
fillColor = color; | |||
return this; | |||
} | |||
/** | |||
* @param width width of the polygon outline in pixels. | |||
* @return same {@link PolygonOptions} | |||
*/ | |||
public PolygonOptions strokeWidth(float width) { | |||
strokeWidth = width; | |||
return this; | |||
} | |||
/** | |||
* @param color color of the polygon outline | |||
* @return same {@link PolygonOptions} | |||
*/ | |||
public PolygonOptions strokeColor(@ColorInt int color) { | |||
strokeColor = color; | |||
return this; | |||
} | |||
/** | |||
* @param outsider {@code true} to invert filling of this polygon. That is, filling everything | |||
* with color except for the holes. {@code false} for normal drawing routine. | |||
* @return same {@link PolygonOptions} | |||
*/ | |||
public PolygonOptions outsider(boolean outsider) { | |||
this.outsider = outsider; | |||
return this; | |||
} | |||
/** | |||
* Adds given point to the polygon | |||
* | |||
* @return same {@link PolygonOptions} | |||
*/ | |||
public PolygonOptions add(LatLng point) { | |||
points.add(point); | |||
return this; | |||
} | |||
/** | |||
* Adds all points from list to the polygon | |||
* | |||
* @return same {@link PolygonOptions} | |||
*/ | |||
public PolygonOptions addAll(List<LatLng> points) { | |||
this.points.addAll(points); | |||
return this; | |||
} | |||
/** | |||
* @see #fillColor(int) | |||
*/ | |||
public int getFillColor() { | |||
return fillColor; | |||
} | |||
/** | |||
* @see #strokeWidth(float) | |||
*/ | |||
public float getStrokeWidth() { | |||
return strokeWidth; | |||
} | |||
/** | |||
* @see #strokeColor(int) | |||
*/ | |||
public int getStrokeColor() { | |||
return strokeColor; | |||
} | |||
/** | |||
* @see #outsider(boolean) | |||
*/ | |||
public boolean isOutsider() { | |||
return outsider; | |||
} | |||
/** | |||
* @see #add(LatLng) | |||
* @see #addAll(List) | |||
*/ | |||
public List<LatLng> getPoints() { | |||
return points; | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
/** | |||
* Draws polyline on the map | |||
*/ | |||
public interface Polyline extends DrawableComponent { | |||
} |
@@ -0,0 +1,83 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.support.annotation.ColorInt; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* Accumulates parameters which are required to create {@link Polyline} component. | |||
* Mutable. | |||
*/ | |||
public class PolylineOptions { | |||
private int color; | |||
private float width; | |||
private final List<LatLng> points = new ArrayList<>(); | |||
/** | |||
* @param color color of the line | |||
* @return same {@link PolylineOptions} | |||
*/ | |||
public PolylineOptions color(@ColorInt int color) { | |||
this.color = color; | |||
return this; | |||
} | |||
/** | |||
* @param width width of the line in pixels | |||
* @return same {@link PolylineOptions} | |||
*/ | |||
public PolylineOptions width(float width) { | |||
this.width = width; | |||
return this; | |||
} | |||
/** | |||
* Adds point to polyline | |||
* | |||
* @return same {@link PolylineOptions} | |||
*/ | |||
public PolylineOptions add(LatLng point) { | |||
points.add(point); | |||
return this; | |||
} | |||
/** | |||
* Adds all points from list to polyline | |||
* | |||
* @return same {@link PolylineOptions} | |||
*/ | |||
public PolylineOptions addAll(List<LatLng> points) { | |||
this.points.addAll(points); | |||
return this; | |||
} | |||
/** | |||
* @see #color(int) | |||
*/ | |||
public int getColor() { | |||
return color; | |||
} | |||
/** | |||
* @see #width(float) | |||
*/ | |||
public float getWidth() { | |||
return width; | |||
} | |||
/** | |||
* @see #add(LatLng) | |||
* @see #addAll(List) | |||
*/ | |||
public List<LatLng> getPoints() { | |||
return points; | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package com.car2go.maps.model; | |||
/** | |||
* A rectangular geofence composed of two locations. | |||
* | |||
* The locations should be the North-West corner and the South-East corner of the rect. | |||
*/ | |||
public class RectGeofence implements Geofence { | |||
private final LatLng northWest; | |||
private final LatLng southEast; | |||
public RectGeofence(LatLng northWest, LatLng southEast) { | |||
this.northWest = northWest; | |||
this.southEast = southEast; | |||
if ((northWest.latitude <= southEast.latitude) || (northWest.longitude >= southEast.longitude)) { | |||
throw new IllegalArgumentException("North West point should be in the Top Left corner of the rect"); | |||
} | |||
} | |||
@Override | |||
public boolean contains(LatLng latLng) { | |||
double longitude = latLng.longitude; | |||
double latitude = latLng.latitude; | |||
double leftBorder = northWest.longitude; | |||
double rightBorder = southEast.longitude; | |||
double bottomBorder = southEast.latitude; | |||
double topBorder = northWest.latitude; | |||
return latitude >= bottomBorder && latitude <= topBorder && longitude >= leftBorder && longitude <= rightBorder; | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
/* | |||
* Copyright (c) 2015 Daimler AG / Moovel GmbH | |||
* | |||
* All rights reserved | |||
*/ | |||
package com.car2go.maps.model; | |||
import android.os.Parcel; | |||
import android.os.Parcelable; | |||
/** | |||
* Visible region on the map. | |||
* Immutable. | |||
*/ | |||
public class VisibleRegion implements Parcelable { | |||
/** | |||
* Currently visible bounds. | |||
*/ | |||
public final LatLngBounds latLngBounds; | |||
public VisibleRegion(LatLngBounds latLngBounds) { | |||
this.latLngBounds = latLngBounds; | |||
} | |||
protected VisibleRegion(Parcel in) { | |||
this.latLngBounds = in.readParcelable(LatLngBounds.class.getClassLoader()); | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (!(o instanceof VisibleRegion)) { | |||
return false; | |||
} | |||
VisibleRegion that = (VisibleRegion) o; | |||
return latLngBounds.equals(that.latLngBounds); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return latLngBounds.hashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return "VisibleRegion{" + | |||
"latLngBounds=" + latLngBounds + | |||
'}'; | |||
} | |||
@Override | |||
public int describeContents() { | |||
return 0; | |||
} | |||
@Override | |||
public void writeToParcel(Parcel dest, int flags) { | |||
dest.writeParcelable(this.latLngBounds, flags); | |||
} | |||
public static final Parcelable.Creator<VisibleRegion> CREATOR = new Parcelable.Creator<VisibleRegion>() { | |||
public VisibleRegion createFromParcel(Parcel source) { | |||
return new VisibleRegion(source); | |||
} | |||
public VisibleRegion[] newArray(int size) { | |||
return new VisibleRegion[size]; | |||
} | |||
}; | |||
} |
@@ -0,0 +1,124 @@ | |||
/* | |||
* Copyright 2013 Google Inc. | |||
* | |||
* 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 com.car2go.maps.util; | |||
/** | |||
* Utility functions that are used my both PolyUtil and SphericalUtil. | |||
*/ | |||
class MathUtil { | |||
/** | |||
* The earth's radius, in meters. | |||
* Mean radius as defined by IUGG. | |||
*/ | |||
static final double EARTH_RADIUS = 6371009.0D; | |||
MathUtil() { | |||
} | |||
/** | |||
* Restrict x to the range [low, high]. | |||
*/ | |||
static double clamp(double x, double low, double high) { | |||
return x < low ? low : (x > high ? high : x); | |||
} | |||
/** | |||
* Wraps the given value into the inclusive-exclusive interval between min and max. | |||
* | |||
* @param n The value to wrap. | |||
* @param min The minimum. | |||
* @param max The maximum. | |||
*/ | |||
static double wrap(double n, double min, double max) { | |||
return n >= min && n < max ? n : mod(n - min, max - min) + min; | |||
} | |||
/** | |||
* Returns the non-negative remainder of x / m. | |||
* | |||
* @param x The operand. | |||
* @param m The modulus. | |||
*/ | |||
static double mod(double x, double m) { | |||
return (x % m + m) % m; | |||
} | |||
/** | |||
* Returns mercator Y corresponding to latitude. | |||
* See http://en.wikipedia.org/wiki/Mercator_projection . | |||
*/ | |||
static double mercator(double lat) { | |||
return Math.log(Math.tan(lat * 0.5D + 0.7853981633974483D)); | |||
} | |||
/** | |||
* Returns latitude from mercator Y. | |||
*/ | |||
static double inverseMercator(double y) { | |||
return 2.0D * Math.atan(Math.exp(y)) - 1.5707963267948966D; | |||
} | |||
/** | |||
* Returns haversine(angle-in-radians). | |||
* hav(x) == (1 - cos(x)) / 2 == sin(x / 2)^2. | |||
*/ | |||
static double hav(double x) { | |||
double sinHalf = Math.sin(x * 0.5D); | |||
return sinHalf * sinHalf; | |||
} | |||
/** | |||
* Computes inverse haversine. Has good numerical stability around 0. | |||
* arcHav(x) == acos(1 - 2 * x) == 2 * asin(sqrt(x)). | |||
* The argument must be in [0, 1], and the result is positive. | |||
*/ | |||
static double arcHav(double x) { | |||
return 2.0D * Math.asin(Math.sqrt(x)); | |||
} | |||
/** | |||
* Given h==hav(x), returns sin(abs(x)). | |||
*/ | |||
static double sinFromHav(double h) { | |||
return 2.0D * Math.sqrt(h * (1.0D - h)); | |||
} | |||
/** | |||
* Returns hav(asin(x)). | |||
*/ | |||
static double havFromSin(double x) { | |||
double x2 = x * x; | |||
return x2 / (1.0D + Math.sqrt(1.0D - x2)) * 0.5D; | |||
} | |||
/** | |||
* Returns sin(arcHav(x) + arcHav(y)). | |||
*/ | |||
static double sinSumFromHav(double x, double y) { | |||
double a = Math.sqrt(x * (1.0D - x)); | |||
double b = Math.sqrt(y * (1.0D - y)); | |||
return 2.0D * (a + b - 2.0D * (a * y + b * x)); | |||
} | |||
/** | |||
* Returns hav() of distance from (lat1, lng1) to (lat2, lng2) on the unit sphere. | |||
*/ | |||
static double havDistance(double lat1, double lat2, double dLng) { | |||
return hav(lat1 - lat2) + hav(dLng) * Math.cos(lat1) * Math.cos(lat2); | |||
} | |||
} |
@@ -0,0 +1,146 @@ | |||
/* | |||
* Copyright 2013 Google Inc. | |||
* | |||
* 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 com.car2go.maps.util; | |||
import com.car2go.maps.model.LatLng; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
public class PolyUtil { | |||
/** | |||
* Decodes an encoded path string into a sequence of LatLngs. | |||
*/ | |||
public static List<LatLng> decode(String encodedPath) { | |||
int len = encodedPath.length(); | |||
ArrayList<LatLng> path = new ArrayList<>(); | |||
int index = 0; | |||
int lat = 0; | |||
int lng = 0; | |||
while (index < len) { | |||
int result = 1; | |||
int shift = 0; | |||
int b; | |||
do { | |||
b = encodedPath.charAt(index++) - 63 - 1; | |||
result += b << shift; | |||
shift += 5; | |||
} while (b >= 31); | |||
lat += (result & 1) != 0 ? ~(result >> 1) : result >> 1; | |||
result = 1; | |||
shift = 0; | |||
do { | |||
b = encodedPath.charAt(index++) - 63 - 1; | |||
result += b << shift; | |||
shift += 5; | |||
} while (b >= 31); | |||
lng += (result & 1) != 0 ? ~(result >> 1) : result >> 1; | |||
path.add(new LatLng((double) lat * 1.0E-5D, (double) lng * 1.0E-5D)); | |||
} | |||
return path; | |||
} | |||
/** | |||
* Returns tan(latitude-at-lng3) on the great circle (lat1, lng1) to (lat2, lng2). lng1==0. | |||
* See http://williams.best.vwh.net/avform.htm . | |||
*/ | |||
private static double tanLatGC(double lat1, double lat2, double lng2, double lng3) { | |||
return (Math.tan(lat1) * Math.sin(lng2 - lng3) + Math.tan(lat2) * Math.sin(lng3)) / Math.sin(lng2); | |||
} | |||
/** | |||
* Returns mercator(latitude-at-lng3) on the Rhumb line (lat1, lng1) to (lat2, lng2). lng1==0. | |||
*/ | |||
private static double mercatorLatRhumb(double lat1, double lat2, double lng2, double lng3) { | |||
return (MathUtil.mercator(lat1) * (lng2 - lng3) + MathUtil.mercator(lat2) * lng3) / lng2; | |||
} | |||
/** | |||
* Computes whether the vertical segment (lat3, lng3) to South Pole intersects the segment | |||
* (lat1, lng1) to (lat2, lng2). | |||
* Longitudes are offset by -lng1; the implicit lng1 becomes 0. | |||
*/ | |||
private static boolean intersects(double lat1, double lat2, double lng2, double lat3, double lng3, boolean geodesic) { | |||
if ((lng3 < 0.0D || lng3 < lng2) && (lng3 >= 0.0D || lng3 >= lng2)) { | |||
if (lat3 <= -1.5707963267948966D) { | |||
return false; | |||
} else if (lat1 > -1.5707963267948966D && lat2 > -1.5707963267948966D && lat1 < 1.5707963267948966D && lat2 < 1.5707963267948966D) { | |||
if (lng2 <= -3.141592653589793D) { | |||
return false; | |||
} else { | |||
double linearLat = (lat1 * (lng2 - lng3) + lat2 * lng3) / lng2; | |||
return lat1 >= 0.0D && lat2 >= 0.0D && lat3 < linearLat ? false : (lat1 <= 0.0D && lat2 <= 0.0D && lat3 >= linearLat ? true : (lat3 >= 1.5707963267948966D ? true : (geodesic ? Math.tan(lat3) >= tanLatGC(lat1, lat2, lng2, lng3) : MathUtil.mercator(lat3) >= mercatorLatRhumb(lat1, lat2, lng2, lng3)))); | |||
} | |||
} else { | |||
return false; | |||
} | |||
} else { | |||
return false; | |||
} | |||
} | |||
/** | |||
* Computes whether the given point lies inside the specified polygon. | |||
* The polygon is always cosidered closed, regardless of whether the last point equals | |||
* the first or not. | |||
* Inside is defined as not containing the South Pole -- the South Pole is always outside. | |||
* The polygon is formed of great circle segments if geodesic is true, and of rhumb | |||
* (loxodromic) segments otherwise. | |||
*/ | |||
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic) { | |||
int size = polygon.size(); | |||
if (size == 0) { | |||
return false; | |||
} else { | |||
double lat3 = Math.toRadians(point.latitude); | |||
double lng3 = Math.toRadians(point.longitude); | |||
LatLng prev = polygon.get(size - 1); | |||
double lat1 = Math.toRadians(prev.latitude); | |||
double lng1 = Math.toRadians(prev.longitude); | |||
int nIntersect = 0; | |||
double lng2; | |||
for (Iterator i$ = polygon.iterator(); i$.hasNext(); lng1 = lng2) { | |||
LatLng point2 = (LatLng) i$.next(); | |||
double dLng3 = MathUtil.wrap(lng3 - lng1, -3.141592653589793D, 3.141592653589793D); | |||
if (lat3 == lat1 && dLng3 == 0.0D) { | |||
return true; | |||
} | |||
double lat2 = Math.toRadians(point2.latitude); | |||
lng2 = Math.toRadians(point2.longitude); | |||
if (intersects(lat1, lat2, MathUtil.wrap(lng2 - lng1, -3.141592653589793D, 3.141592653589793D), lat3, dLng3, geodesic)) { | |||
++nIntersect; | |||
} | |||
lat1 = lat2; | |||
} | |||
return (nIntersect & 1) != 0; | |||
} | |||
} | |||
} |
@@ -0,0 +1,250 @@ | |||
/* | |||
* Copyright 2013 Google Inc. | |||
* | |||
* 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 com.car2go.maps.util; | |||
import com.car2go.maps.model.LatLng; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
public class SphericalUtil { | |||
private SphericalUtil() { | |||
} | |||
/** | |||
* Returns the heading from one LatLng to another LatLng. Headings are | |||
* expressed in degrees clockwise from North within the range [-180,180). | |||
* | |||
* @return The heading in degrees clockwise from north. | |||
*/ | |||
public static double computeHeading(LatLng from, LatLng to) { | |||
double fromLat = Math.toRadians(from.latitude); | |||
double fromLng = Math.toRadians(from.longitude); | |||
double toLat = Math.toRadians(to.latitude); | |||
double toLng = Math.toRadians(to.longitude); | |||
double dLng = toLng - fromLng; | |||
double heading = Math.atan2(Math.sin(dLng) * Math.cos(toLat), Math.cos(fromLat) * Math.sin(toLat) - Math.sin(fromLat) * Math.cos(toLat) * Math.cos(dLng)); | |||
return MathUtil.wrap(Math.toDegrees(heading), -180.0D, 180.0D); | |||
} | |||
/** | |||
* Returns the LatLng resulting from moving a distance from an origin | |||
* in the specified heading (expressed in degrees clockwise from north). | |||
* | |||
* @param from The LatLng from which to start. | |||
* @param distance The distance to travel. | |||
* @param heading The heading in degrees clockwise from north. | |||
*/ | |||
public static LatLng computeOffset(LatLng from, double distance, double heading) { | |||
distance /= 6371009.0D; | |||
heading = Math.toRadians(heading); | |||
double fromLat = Math.toRadians(from.latitude); | |||
double fromLng = Math.toRadians(from.longitude); | |||
double cosDistance = Math.cos(distance); | |||
double sinDistance = Math.sin(distance); | |||
double sinFromLat = Math.sin(fromLat); | |||
double cosFromLat = Math.cos(fromLat); | |||
double sinLat = cosDistance * sinFromLat + sinDistance * cosFromLat * Math.cos(heading); | |||
double dLng = Math.atan2(sinDistance * cosFromLat * Math.sin(heading), cosDistance - sinFromLat * sinLat); | |||
return new LatLng(Math.toDegrees(Math.asin(sinLat)), Math.toDegrees(fromLng + dLng)); | |||
} | |||
/** | |||
* Returns the location of origin when provided with a LatLng destination, | |||
* meters travelled and original heading. Headings are expressed in degrees | |||
* clockwise from North. This function returns null when no solution is | |||
* available. | |||
* | |||
* @param to The destination LatLng. | |||
* @param distance The distance travelled, in meters. | |||
* @param heading The heading in degrees clockwise from north. | |||
*/ | |||
public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) { | |||
heading = Math.toRadians(heading); | |||
distance /= 6371009.0D; | |||
double n1 = Math.cos(distance); | |||
double n2 = Math.sin(distance) * Math.cos(heading); | |||
double n3 = Math.sin(distance) * Math.sin(heading); | |||
double n4 = Math.sin(Math.toRadians(to.latitude)); | |||
double n12 = n1 * n1; | |||
double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4; | |||
if (discriminant < 0.0D) { | |||
return null; | |||
} else { | |||
double b = n2 * n4 + Math.sqrt(discriminant); | |||
b /= n1 * n1 + n2 * n2; | |||
double a = (n4 - n2 * b) / n1; | |||
double fromLatRadians = Math.atan2(a, b); | |||
if (fromLatRadians < -1.5707963267948966D || fromLatRadians > 1.5707963267948966D) { | |||
b = n2 * n4 - Math.sqrt(discriminant); | |||
b /= n1 * n1 + n2 * n2; | |||
fromLatRadians = Math.atan2(a, b); | |||
} | |||
if (fromLatRadians >= -1.5707963267948966D && fromLatRadians <= 1.5707963267948966D) { | |||
double fromLngRadians = Math.toRadians(to.longitude) - Math.atan2(n3, n1 * Math.cos(fromLatRadians) - n2 * Math.sin(fromLatRadians)); | |||
return new LatLng(Math.toDegrees(fromLatRadians), Math.toDegrees(fromLngRadians)); | |||
} else { | |||
return null; | |||
} | |||
} | |||
} | |||
/** | |||
* Returns the LatLng which lies the given fraction of the way between the | |||
* origin LatLng and the destination LatLng. | |||
* | |||
* @param from The LatLng from which to start. | |||
* @param to The LatLng toward which to travel. | |||
* @param fraction A fraction of the distance to travel. | |||
* @return The interpolated LatLng. | |||
*/ | |||
public static LatLng interpolate(LatLng from, LatLng to, double fraction) { | |||
double fromLat = Math.toRadians(from.latitude); | |||
double fromLng = Math.toRadians(from.longitude); | |||
double toLat = Math.toRadians(to.latitude); | |||
double toLng = Math.toRadians(to.longitude); | |||
double cosFromLat = Math.cos(fromLat); | |||
double cosToLat = Math.cos(toLat); | |||
double angle = computeAngleBetween(from, to); | |||
double sinAngle = Math.sin(angle); | |||
if (sinAngle < 1.0E-6D) { | |||
return from; | |||
} else { | |||
double a = Math.sin((1.0D - fraction) * angle) / sinAngle; | |||
double b = Math.sin(fraction * angle) / sinAngle; | |||
double x = a * cosFromLat * Math.cos(fromLng) + b * cosToLat * Math.cos(toLng); | |||
double y = a * cosFromLat * Math.sin(fromLng) + b * cosToLat * Math.sin(toLng); | |||
double z = a * Math.sin(fromLat) + b * Math.sin(toLat); | |||
double lat = Math.atan2(z, Math.sqrt(x * x + y * y)); | |||
double lng = Math.atan2(y, x); | |||
return new LatLng(Math.toDegrees(lat), Math.toDegrees(lng)); | |||
} | |||
} | |||
/** | |||
* Returns distance on the unit sphere; the arguments are in radians. | |||
*/ | |||
private static double distanceRadians(double lat1, double lng1, double lat2, double lng2) { | |||
return MathUtil.arcHav(MathUtil.havDistance(lat1, lat2, lng1 - lng2)); | |||
} | |||
/** | |||
* Returns the angle between two LatLngs, in radians. This is the same as the distance | |||
* on the unit sphere. | |||
*/ | |||
static double computeAngleBetween(LatLng from, LatLng to) { | |||
return distanceRadians(Math.toRadians(from.latitude), Math.toRadians(from.longitude), Math.toRadians(to.latitude), Math.toRadians(to.longitude)); | |||
} | |||
/** | |||
* Returns the distance between two LatLngs, in meters. | |||
*/ | |||
public static double computeDistanceBetween(LatLng from, LatLng to) { | |||
return computeAngleBetween(from, to) * 6371009.0D; | |||
} | |||
/** | |||
* Returns the length of the given path, in meters, on Earth. | |||
*/ | |||
public static double computeLength(List<LatLng> path) { | |||
if (path.size() < 2) { | |||
return 0.0D; | |||
} else { | |||
double length = 0.0D; | |||
LatLng prev = (LatLng) path.get(0); | |||
double prevLat = Math.toRadians(prev.latitude); | |||
double prevLng = Math.toRadians(prev.longitude); | |||
double lng; | |||
for (Iterator i$ = path.iterator(); i$.hasNext(); prevLng = lng) { | |||
LatLng point = (LatLng) i$.next(); | |||
double lat = Math.toRadians(point.latitude); | |||
lng = Math.toRadians(point.longitude); | |||
length += distanceRadians(prevLat, prevLng, lat, lng); | |||
prevLat = lat; | |||
} | |||
return length * 6371009.0D; | |||
} | |||
} | |||
/** | |||
* Returns the area of a closed path on Earth. | |||
* | |||
* @param path A closed path. | |||
* @return The path's area in square meters. | |||
*/ | |||
public static double computeArea(List<LatLng> path) { | |||
return Math.abs(computeSignedArea(path)); | |||
} | |||
/** | |||
* Returns the signed area of a closed path on Earth. The sign of the area may be used to | |||
* determine the orientation of the path. | |||
* "inside" is the surface that does not contain the South Pole. | |||
* | |||
* @param path A closed path. | |||
* @return The loop's area in square meters. | |||
*/ | |||
public static double computeSignedArea(List<LatLng> path) { | |||
return computeSignedArea(path, 6371009.0D); | |||
} | |||
/** | |||
* Returns the signed area of a closed path on a sphere of given radius. | |||
* The computed area uses the same units as the radius squared. | |||
* Used by SphericalUtilTest. | |||
*/ | |||
static double computeSignedArea(List<LatLng> path, double radius) { | |||
int size = path.size(); | |||
if (size < 3) { | |||
return 0.0D; | |||
} else { | |||
double total = 0.0D; | |||
LatLng prev = (LatLng) path.get(size - 1); | |||
double prevTanLat = Math.tan((1.5707963267948966D - Math.toRadians(prev.latitude)) / 2.0D); | |||
double prevLng = Math.toRadians(prev.longitude); | |||
double lng; | |||
for (Iterator i$ = path.iterator(); i$.hasNext(); prevLng = lng) { | |||
LatLng point = (LatLng) i$.next(); | |||
double tanLat = Math.tan((1.5707963267948966D - Math.toRadians(point.latitude)) / 2.0D); | |||
lng = Math.toRadians(point.longitude); | |||
total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng); | |||
prevTanLat = tanLat; | |||
} | |||
return total * radius * radius; | |||
} | |||
} | |||
/** | |||
* Returns the signed area of a triangle which has North Pole as a vertex. | |||
* Formula derived from "Area of a spherical triangle given two edges and the included angle" | |||
* as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2. | |||
* See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71 | |||
* The arguments named "tan" are tan((pi/2 - latitude)/2). | |||
*/ | |||
private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) { | |||
double deltaLng = lng1 - lng2; | |||
double t = tan1 * tan2; | |||
return 2.0D * Math.atan2(t * Math.sin(deltaLng), 1.0D + t * Math.cos(deltaLng)); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- | |||
~ Copyright (c) 2017 Daimler AG / Moovel GmbH | |||
~ | |||
~ All rights reserved | |||
--> | |||
<resources> | |||
<declare-styleable name="MapView"> | |||
<attr name="anyMapLiteMode" format="boolean"/> | |||
</declare-styleable> | |||
</resources> |
@@ -0,0 +1,46 @@ | |||
package com.car2go.maps.model; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.junit.runners.JUnit4; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
/** | |||
* Tests for the functionality of the RectGeofence | |||
*/ | |||
@RunWith(JUnit4.class) | |||
public class RectGeofenceTest { | |||
private RectGeofence createFence() { | |||
return new RectGeofence(new LatLng(1, -1), new LatLng(-1, 1)); | |||
} | |||
@Test | |||
public void testInside() throws Exception { | |||
assertTrue(createFence().contains(new LatLng(0, 0))); | |||
assertTrue(createFence().contains(new LatLng(0.999, 0.999))); | |||
assertTrue(createFence().contains(new LatLng(-0.999, 0.999))); | |||
assertTrue(createFence().contains(new LatLng(-0.999, -0.999))); | |||
assertTrue(createFence().contains(new LatLng(0.999, -0.999))); | |||
} | |||
@Test | |||
public void testOutside() throws Exception { | |||
assertFalse(createFence().contains(new LatLng(1.001, 0))); | |||
assertFalse(createFence().contains(new LatLng(-1.001, 0))); | |||
assertFalse(createFence().contains(new LatLng(0, 1.001))); | |||
assertFalse(createFence().contains(new LatLng(0, -1.001))); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void testWrongRectEastWest() throws Exception { | |||
new RectGeofence(new LatLng(1, 1), new LatLng(-1, -1)); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void testWrongRectNorthSouth() throws Exception { | |||
new RectGeofence(new LatLng(-1, -1), new LatLng(1, 1)); | |||