prepare integration of anymaps in the project to maintain it and keep it
working with new version of osmdroid
This commit is contained in:
parent
96d0d81ade
commit
34f7e505b8
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
ext {
|
||||
name = 'AnyMaps - Open Street Maps'
|
||||
artifactId = 'anymaps.osm'
|
||||
description = 'Open Street Maps version of AnyMaps'
|
||||
}
|
||||
|
||||
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 project(':anymaps-base')
|
||||
|
||||
implementation 'org.slf4j:slf4j-simple:1.6.1'
|
||||
implementation 'org.osmdroid:osmdroid-android:6.0.3'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:1.9.5'
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<!--
|
||||
~ Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
~
|
||||
~ All rights reserved
|
||||
-->
|
||||
|
||||
<manifest package="com.car2go.maps.osm"/>
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import com.car2go.maps.model.BitmapDescriptor;
|
||||
|
||||
/**
|
||||
* Creates instances of {@link BitmapDescriptor}
|
||||
*/
|
||||
public class BitmapDescriptorFactory implements com.car2go.maps.BitmapDescriptorFactory {
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static Context context;
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static final BitmapDescriptorFactory instance = new BitmapDescriptorFactory();
|
||||
|
||||
private BitmapDescriptorFactory() {
|
||||
}
|
||||
|
||||
public static BitmapDescriptorFactory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void initialize(Context context) {
|
||||
BitmapDescriptorFactory.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitmapDescriptor fromBitmap(Bitmap bitmap) {
|
||||
ensureInitialized();
|
||||
|
||||
return new OsmBitmapDescriptor(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitmapDescriptor fromResource(int resourceId) {
|
||||
ensureInitialized();
|
||||
|
||||
return new OsmBitmapDescriptor(
|
||||
BitmapFactory.decodeResource(context.getResources(), resourceId)
|
||||
);
|
||||
}
|
||||
|
||||
private static void ensureInitialized() {
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Not initialized. Did you forgot to initialize MapsConfiguration?");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import com.car2go.maps.CameraUpdate;
|
||||
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 class CameraUpdateFactory implements com.car2go.maps.CameraUpdateFactory {
|
||||
|
||||
private static final CameraUpdateFactory instance = new CameraUpdateFactory();
|
||||
|
||||
private CameraUpdateFactory() {
|
||||
}
|
||||
|
||||
public static CameraUpdateFactory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CameraUpdate newLatLngZoom(LatLng center, float zoomLevel) {
|
||||
return new OsmCameraUpdate.Builder()
|
||||
.center(center)
|
||||
.zoom(zoomLevel)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CameraUpdate newLatLngBounds(LatLngBounds bounds, int padding) {
|
||||
return new OsmCameraUpdate.Builder()
|
||||
.bounds(bounds)
|
||||
.padding(padding)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CameraUpdate zoomTo(float zoomLevel) {
|
||||
return new OsmCameraUpdate.Builder()
|
||||
.zoom(zoomLevel)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import com.car2go.maps.AnyMap;
|
||||
import com.car2go.maps.CameraUpdate;
|
||||
import com.car2go.maps.model.LatLng;
|
||||
|
||||
import org.osmdroid.api.IMapController;
|
||||
import org.osmdroid.views.MapView;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.toGeoPoint;
|
||||
|
||||
/**
|
||||
* Handles incoming {@link CameraUpdate} events
|
||||
*/
|
||||
class CameraUpdateHandler {
|
||||
|
||||
private final org.osmdroid.views.MapView map;
|
||||
|
||||
public CameraUpdateHandler(MapView map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnyMap#moveCamera(CameraUpdate)
|
||||
*/
|
||||
public void moveCamera(CameraUpdate cameraUpdate) {
|
||||
final OsmCameraUpdate osmCameraUpdate = (OsmCameraUpdate) cameraUpdate;
|
||||
|
||||
final IMapController controller = map.getController();
|
||||
|
||||
if (osmCameraUpdate.bounds != null) {
|
||||
final LatLng center = osmCameraUpdate.bounds.getCenter();
|
||||
|
||||
controller.setZoom(map.getMaxZoomLevel());
|
||||
|
||||
controller.zoomToSpan(
|
||||
(int) ((osmCameraUpdate.bounds.northeast.latitude - osmCameraUpdate.bounds.southwest.latitude) * 1e6),
|
||||
(int) ((osmCameraUpdate.bounds.northeast.longitude - osmCameraUpdate.bounds.southwest.longitude) * 1e6)
|
||||
);
|
||||
|
||||
controller.setCenter(
|
||||
toGeoPoint(center)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (osmCameraUpdate.zoom != null) {
|
||||
controller.setZoom(osmCameraUpdate.zoom.intValue());
|
||||
}
|
||||
|
||||
if (osmCameraUpdate.center != null) {
|
||||
controller.setCenter(
|
||||
toGeoPoint(osmCameraUpdate.center)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnyMap#animateCamera(CameraUpdate)
|
||||
*/
|
||||
public void animateCamera(CameraUpdate cameraUpdate) {
|
||||
moveCamera(cameraUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnyMap#animateCamera(CameraUpdate, AnyMap.CancelableCallback)
|
||||
*/
|
||||
public void animateCamera(CameraUpdate cameraUpdate, AnyMap.CancelableCallback callback) {
|
||||
moveCamera(cameraUpdate);
|
||||
|
||||
callback.onFinish();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnyMap#animateCamera(CameraUpdate, int, AnyMap.CancelableCallback)
|
||||
*/
|
||||
public void animateCamera(CameraUpdate cameraUpdate, int duration, AnyMap.CancelableCallback callback) {
|
||||
moveCamera(cameraUpdate);
|
||||
|
||||
callback.onFinish();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.car2go.maps.MapContainerView;
|
||||
import com.car2go.maps.OnMapReadyCallback;
|
||||
|
||||
import org.osmdroid.config.Configuration;
|
||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
||||
import org.osmdroid.views.CustomZoomButtonsController;
|
||||
|
||||
/**
|
||||
* @see MapContainerView
|
||||
*/
|
||||
public class MapView extends MapContainerView {
|
||||
|
||||
private OsmMap anyMap;
|
||||
|
||||
public MapView(Context context) {
|
||||
super(context);
|
||||
|
||||
initView(context, null);
|
||||
}
|
||||
|
||||
public MapView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
initView(context, attrs);
|
||||
}
|
||||
|
||||
private void initView(Context context, AttributeSet attrs) {
|
||||
org.osmdroid.views.MapView mapView = new org.osmdroid.views.MapView(context);
|
||||
|
||||
addView(mapView);
|
||||
|
||||
mapView.setTileSource(TileSourceFactory.MAPNIK);
|
||||
mapView.setMultiTouchControls(true);
|
||||
mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
|
||||
|
||||
anyMap = new OsmMap(mapView);
|
||||
|
||||
setClipToPadding(false);
|
||||
setLayerType(LAYER_TYPE_SOFTWARE, null);
|
||||
|
||||
applyAttributes(context, attrs);
|
||||
}
|
||||
|
||||
private void applyAttributes(Context context, AttributeSet attrs) {
|
||||
if (attrs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapView);
|
||||
try {
|
||||
boolean liteMode = typedArray.getBoolean(R.styleable.MapView_anyMapLiteMode, false);
|
||||
|
||||
anyMap.getUiSettings().setAllGesturesEnabled(!liteMode);
|
||||
} finally {
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getMapAsync(final OnMapReadyCallback callback) {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onMapReady(anyMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public void setUserAgent(String UA) {
|
||||
Configuration.getInstance().setUserAgentValue(UA);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.car2go.maps.AnyMap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Initializer for OSM maps.
|
||||
*/
|
||||
public final class MapsConfiguration implements com.car2go.maps.MapsConfiguration {
|
||||
|
||||
private static final MapsConfiguration instance = new MapsConfiguration();
|
||||
|
||||
private MapsConfiguration() {
|
||||
}
|
||||
|
||||
public static MapsConfiguration getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Context context) {
|
||||
BitmapDescriptorFactory.initialize(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AnyMap.Feature> getSupportedFeatures() {
|
||||
return Collections.singleton(AnyMap.Feature.REVEALABLE);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import com.car2go.maps.AnyMap;
|
||||
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
|
||||
|
||||
/**
|
||||
* Handles MyLocation feature
|
||||
*/
|
||||
class MyLocationHandler {
|
||||
|
||||
private final MyLocationNewOverlay myLocationOverlay;
|
||||
|
||||
public MyLocationHandler(MapView map) {
|
||||
myLocationOverlay = new MyLocationNewOverlay(map);
|
||||
map.getOverlays().add(myLocationOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AnyMap#setMyLocationEnabled(boolean)
|
||||
*/
|
||||
public void setMyLocationEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
myLocationOverlay.enableMyLocation();
|
||||
} else {
|
||||
myLocationOverlay.disableMyLocation();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.car2go.maps.model.BitmapDescriptor;
|
||||
|
||||
/**
|
||||
* Holds {@link android.graphics.Bitmap} for {@link com.car2go.maps.osm.drawable.OsmMarker}
|
||||
*/
|
||||
public class OsmBitmapDescriptor implements BitmapDescriptor {
|
||||
|
||||
public final Bitmap bitmap;
|
||||
|
||||
public OsmBitmapDescriptor(Bitmap bitmap) {
|
||||
this.bitmap = bitmap;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import com.car2go.maps.CameraUpdate;
|
||||
import com.car2go.maps.model.LatLng;
|
||||
import com.car2go.maps.model.LatLngBounds;
|
||||
|
||||
/**
|
||||
* Contains information about pending map camera update
|
||||
*/
|
||||
public class OsmCameraUpdate implements CameraUpdate {
|
||||
|
||||
public final LatLng center;
|
||||
public final Float zoom;
|
||||
public final LatLngBounds bounds;
|
||||
public final Integer padding;
|
||||
|
||||
private OsmCameraUpdate(Builder builder) {
|
||||
center = builder.center;
|
||||
zoom = builder.zoom;
|
||||
bounds = builder.bounds;
|
||||
padding = builder.padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link OsmCameraUpdate}
|
||||
*/
|
||||
public static final class Builder {
|
||||
private LatLng center;
|
||||
private Float zoom;
|
||||
private LatLngBounds bounds;
|
||||
private Integer padding;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(OsmCameraUpdate copy) {
|
||||
this.center = copy.center;
|
||||
this.zoom = copy.zoom;
|
||||
this.bounds = copy.bounds;
|
||||
this.padding = copy.padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns new center of the camera. Can't be used together with {@link #bounds}
|
||||
*
|
||||
* @param center new center of the camera
|
||||
* @return same {@link OsmCameraUpdate.Builder}
|
||||
*/
|
||||
public Builder center(LatLng center) {
|
||||
this.center = center;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns new zoom level of the camera. Can't be used together with {@link #bounds}
|
||||
*
|
||||
* @param zoom new zoom level of the camera
|
||||
* @return same {@link OsmCameraUpdate.Builder}
|
||||
*/
|
||||
public Builder zoom(Float zoom) {
|
||||
this.zoom = zoom;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns new displayed bounds of the camera. Can't be used together with
|
||||
* {@link #center(LatLng)} or {@link #zoom(Float)}
|
||||
*
|
||||
* @param bounds new bounds displayed by the camera
|
||||
* @return same {@link OsmCameraUpdate.Builder}
|
||||
*/
|
||||
public Builder bounds(LatLngBounds bounds) {
|
||||
this.bounds = bounds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in conjunction with {@link #bounds(LatLngBounds)}
|
||||
*
|
||||
* @param padding padding in pixels from the sides of the displayed bounds.
|
||||
* @return same {@link OsmCameraUpdate.Builder}
|
||||
*/
|
||||
public Builder padding(Integer padding) {
|
||||
this.padding = padding;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return new {@link OsmCameraUpdate}
|
||||
*/
|
||||
public OsmCameraUpdate build() {
|
||||
if ((center != null || zoom != null) && bounds != null) {
|
||||
throw new IllegalStateException("Conflicting parameters: center/zoom and bounds");
|
||||
}
|
||||
|
||||
return new OsmCameraUpdate(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.car2go.maps.AnyMap;
|
||||
import com.car2go.maps.CameraUpdate;
|
||||
import com.car2go.maps.Projection;
|
||||
import com.car2go.maps.UiSettings;
|
||||
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.LatLngBounds;
|
||||
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;
|
||||
import com.car2go.maps.model.VisibleRegion;
|
||||
import com.car2go.maps.osm.drawable.DrawableComponentFactory;
|
||||
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.config.Configuration;
|
||||
import org.osmdroid.events.MapListener;
|
||||
import org.osmdroid.events.ScrollEvent;
|
||||
import org.osmdroid.events.ZoomEvent;
|
||||
import org.osmdroid.views.MapView;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.toLatLng;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AnyMap} which works with Open Street Maps
|
||||
*/
|
||||
class OsmMap implements AnyMap {
|
||||
|
||||
private final org.osmdroid.views.MapView map;
|
||||
|
||||
private final CameraUpdateHandler cameraUpdateHandler;
|
||||
private final MyLocationHandler myLocationHandler;
|
||||
private final DrawableComponentFactory drawableComponentFactory;
|
||||
private final UiSettings uiSettings;
|
||||
|
||||
private OnMapClickListener onMapClickListener = OnMapClickListener.NULL;
|
||||
private OnMapLongClickListener onMapLongClickListener = OnMapLongClickListener.NULL;
|
||||
|
||||
private boolean mapEnabled = true;
|
||||
|
||||
OsmMap(MapView map) {
|
||||
this.map = map;
|
||||
|
||||
cameraUpdateHandler = new CameraUpdateHandler(map);
|
||||
myLocationHandler = new MyLocationHandler(map);
|
||||
drawableComponentFactory = new DrawableComponentFactory(map);
|
||||
uiSettings = new OsmUiSettings();
|
||||
|
||||
map.setOnTouchListener(new MapTouchListener(map.getContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCamera(CameraUpdate cameraUpdate) {
|
||||
cameraUpdateHandler.moveCamera(cameraUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateCamera(CameraUpdate cameraUpdate) {
|
||||
cameraUpdateHandler.animateCamera(cameraUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateCamera(CameraUpdate cameraUpdate, CancelableCallback callback) {
|
||||
cameraUpdateHandler.animateCamera(cameraUpdate, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateCamera(CameraUpdate cameraUpdate, int duration, CancelableCallback callback) {
|
||||
cameraUpdateHandler.animateCamera(cameraUpdate, duration, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CameraPosition getCameraPosition() {
|
||||
return currentCameraPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Projection getProjection() {
|
||||
org.osmdroid.views.Projection projection = map.getProjection();
|
||||
|
||||
return new OsmProjection(
|
||||
new VisibleRegion(
|
||||
new LatLngBounds(
|
||||
new LatLng(
|
||||
projection.getSouthWest().getLatitude(),
|
||||
projection.getSouthWest().getLongitude()
|
||||
),
|
||||
new LatLng(
|
||||
projection.getNorthEast().getLatitude(),
|
||||
projection.getNorthEast().getLongitude()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marker addMarker(MarkerOptions options) {
|
||||
return drawableComponentFactory.addMarker(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Circle addCircle(CircleOptions options) {
|
||||
return drawableComponentFactory.addCircle(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Polygon addPolygon(PolygonOptions options) {
|
||||
return drawableComponentFactory.addPolygon(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Polyline addPolyline(PolylineOptions options) {
|
||||
return drawableComponentFactory.addPolyline(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UiSettings getUiSettings() {
|
||||
return uiSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnMapClickListener(OnMapClickListener listener) {
|
||||
onMapClickListener = (listener == null)
|
||||
? OnMapClickListener.NULL
|
||||
: listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnMapLongClickListener(OnMapLongClickListener listener) {
|
||||
onMapLongClickListener = (listener == null)
|
||||
? OnMapLongClickListener.NULL
|
||||
: listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnCameraChangeListener(OnCameraChangeListener listener) {
|
||||
map.setMapListener(new OsmMapListener(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnMarkerClickListener(OnMarkerClickListener listener) {
|
||||
drawableComponentFactory.setOnMarkerClickListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInfoWindowAdapter(InfoWindowAdapter adapter) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrafficEnabled(boolean enabled) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMyLocationEnabled(boolean enabled) {
|
||||
myLocationHandler.setMyLocationEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMapType(Type type) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
map.setTranslationY((top - bottom) / 2f);
|
||||
map.setTranslationX((left - right) / 2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLocationChanged(LatLng location, float accuracy) {
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
private CameraPosition currentCameraPosition() {
|
||||
final IGeoPoint center = map.getMapCenter();
|
||||
final int zoomLevel = map.getZoomLevel();
|
||||
|
||||
return new CameraPosition(
|
||||
new LatLng(center.getLatitude(), center.getLongitude()),
|
||||
zoomLevel
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects clicks and long-clicks on map
|
||||
*/
|
||||
private class MapTouchListener implements View.OnTouchListener, GestureDetector.OnGestureListener {
|
||||
|
||||
private GestureDetector gestureDetector;
|
||||
|
||||
public MapTouchListener(Context context) {
|
||||
gestureDetector = new GestureDetector(context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (!mapEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
gestureDetector.onTouchEvent(event);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPress(MotionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
onMapClickListener.onMapClick(touchPoint(e));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
onMapLongClickListener.onMapLongClick(touchPoint(e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private LatLng touchPoint(MotionEvent e) {
|
||||
IGeoPoint geoPoint = map.getProjection().fromPixels(
|
||||
(int) e.getX(),
|
||||
(int) e.getY()
|
||||
);
|
||||
return toLatLng(geoPoint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for map position changes and delegates them
|
||||
* to {@link com.car2go.maps.AnyMap.OnCameraChangeListener}
|
||||
*/
|
||||
private class OsmMapListener implements MapListener {
|
||||
|
||||
private final OnCameraChangeListener listener;
|
||||
|
||||
private OsmMapListener(OnCameraChangeListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(ScrollEvent event) {
|
||||
notifyListener();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onZoom(ZoomEvent event) {
|
||||
notifyListener();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void notifyListener() {
|
||||
listener.onCameraChange(
|
||||
currentCameraPosition()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* UI settings for OpenStreetMap
|
||||
*/
|
||||
private class OsmUiSettings implements UiSettings {
|
||||
|
||||
@Override
|
||||
public void setAllGesturesEnabled(final boolean enabled) {
|
||||
mapEnabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMyLocationButtonEnabled(boolean enabled) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMapToolbarEnabled(boolean enabled) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import com.car2go.maps.Projection;
|
||||
import com.car2go.maps.model.VisibleRegion;
|
||||
|
||||
/**
|
||||
* Adapts OpenStreetMap projection to AnyMap projection
|
||||
*/
|
||||
public class OsmProjection implements Projection {
|
||||
|
||||
private final VisibleRegion visibleRegion;
|
||||
|
||||
public OsmProjection(VisibleRegion visibleRegion) {
|
||||
this.visibleRegion = visibleRegion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibleRegion getVisibleRegion() {
|
||||
return visibleRegion;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.drawable;
|
||||
|
||||
import com.car2go.maps.AnyMap;
|
||||
import com.car2go.maps.model.Circle;
|
||||
import com.car2go.maps.model.CircleOptions;
|
||||
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;
|
||||
import com.car2go.maps.osm.drawable.overlay.MarkerOverlayItem;
|
||||
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.overlay.ItemizedIconOverlay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Creates {@link com.car2go.maps.model.DrawableComponent} and attaches them to maps
|
||||
*/
|
||||
public class DrawableComponentFactory {
|
||||
|
||||
private final MapView map;
|
||||
|
||||
private final ItemizedIconOverlay<MarkerOverlayItem> markersOverlay;
|
||||
|
||||
private AnyMap.OnMarkerClickListener onMarkerClickListener = AnyMap.OnMarkerClickListener.NULL;
|
||||
|
||||
public DrawableComponentFactory(MapView map) {
|
||||
this.map = map;
|
||||
|
||||
markersOverlay = new ItemizedIconOverlay<>(
|
||||
map.getContext(),
|
||||
new ArrayList<MarkerOverlayItem>(),
|
||||
new ItemizedIconOverlay.OnItemGestureListener<MarkerOverlayItem>() {
|
||||
@Override
|
||||
public boolean onItemSingleTapUp(int index, MarkerOverlayItem item) {
|
||||
return onMarkerClickListener.onMarkerClick(item.marker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongPress(int index, MarkerOverlayItem item) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
map.getOverlays().add(markersOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds marker to the map
|
||||
*
|
||||
* @return added {@link Marker} which is bound to the map.
|
||||
*/
|
||||
public Marker addMarker(MarkerOptions options) {
|
||||
return new OsmMarker(map, options, markersOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds circle to the map
|
||||
*
|
||||
* @return added {@link Circle} which is bound to the map.
|
||||
*/
|
||||
public Circle addCircle(CircleOptions options) {
|
||||
return new OsmCircle(map, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds polygon to the map.
|
||||
*
|
||||
* @return added {@link Polygon} which is bound to the map
|
||||
*/
|
||||
public Polygon addPolygon(PolygonOptions options) {
|
||||
return new OsmPolygon(map, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds polyline to the map.
|
||||
*
|
||||
* @return added {@link Polyline} which is bound to the map
|
||||
*/
|
||||
public Polyline addPolyline(PolylineOptions options) {
|
||||
return new OsmPolyline(map, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param listener listener which will be invoked on marker clicks
|
||||
*/
|
||||
public void setOnMarkerClickListener(AnyMap.OnMarkerClickListener listener) {
|
||||
onMarkerClickListener = listener == null
|
||||
? AnyMap.OnMarkerClickListener.NULL
|
||||
: listener;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.drawable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
|
||||
import com.car2go.maps.model.Circle;
|
||||
import com.car2go.maps.model.CircleOptions;
|
||||
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.Projection;
|
||||
import org.osmdroid.views.overlay.Overlay;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.toGeoPoint;
|
||||
|
||||
/**
|
||||
* Draws circle on OpenStreetMaps.
|
||||
* Associated with given {@link com.car2go.maps.AnyMap} object, so it should not be cached.
|
||||
*/
|
||||
public class OsmCircle implements Circle {
|
||||
|
||||
private final MapView map;
|
||||
private final CircleOverlay overlay;
|
||||
|
||||
OsmCircle(MapView map, CircleOptions options) {
|
||||
this.map = map;
|
||||
|
||||
overlay = new CircleOverlay(map.getContext(), options);
|
||||
map.getOverlays().add(overlay);
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
overlay.setEnabled(visible);
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
map.getOverlays().remove(overlay);
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay which draws a single circle on OpenStreetMap
|
||||
*/
|
||||
private static class CircleOverlay extends Overlay {
|
||||
|
||||
private final IGeoPoint position;
|
||||
private final float radius;
|
||||
|
||||
private final Paint fillPaint;
|
||||
private final Paint strokePaint;
|
||||
|
||||
private final Point auxPoint = new Point();
|
||||
|
||||
public CircleOverlay(Context context, CircleOptions options) {
|
||||
super(context);
|
||||
|
||||
position = toGeoPoint(options.getCenter());
|
||||
radius = (float) options.getRadius();
|
||||
|
||||
fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
fillPaint.setStyle(Paint.Style.FILL);
|
||||
fillPaint.setColor(options.getFillColor());
|
||||
|
||||
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
strokePaint.setStyle(Paint.Style.STROKE);
|
||||
strokePaint.setColor(options.getStrokeColor());
|
||||
strokePaint.setStrokeWidth(options.getStrokeWidth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas c, MapView osmv, boolean shadow) {
|
||||
Projection projection = osmv.getProjection();
|
||||
|
||||
Point centerPoint = projection.toPixels(position, auxPoint);
|
||||
float radiusPixels = projection.metersToPixels(radius);
|
||||
|
||||
c.drawCircle(
|
||||
centerPoint.x,
|
||||
centerPoint.y,
|
||||
radiusPixels,
|
||||
fillPaint
|
||||
);
|
||||
|
||||
c.drawCircle(
|
||||
centerPoint.x,
|
||||
centerPoint.y,
|
||||
radiusPixels,
|
||||
strokePaint
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.drawable;
|
||||
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
|
||||
import com.car2go.maps.model.BitmapDescriptor;
|
||||
import com.car2go.maps.model.LatLng;
|
||||
import com.car2go.maps.model.Marker;
|
||||
import com.car2go.maps.model.MarkerOptions;
|
||||
import com.car2go.maps.osm.OsmBitmapDescriptor;
|
||||
import com.car2go.maps.osm.drawable.overlay.MarkerOverlayItem;
|
||||
import com.car2go.maps.osm.util.OsmUtils;
|
||||
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.overlay.ItemizedIconOverlay;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.anchorToHotspot;
|
||||
|
||||
/**
|
||||
* Draws marker on OpenStreetMaps.
|
||||
* Associated with given {@link com.car2go.maps.AnyMap} object, so it should not be cached.
|
||||
*/
|
||||
public class OsmMarker implements Marker {
|
||||
|
||||
private final MapView map;
|
||||
|
||||
private final LatLng position;
|
||||
private final ItemizedIconOverlay<MarkerOverlayItem> overlay;
|
||||
private final MarkerOverlayItem overlayItem;
|
||||
|
||||
private boolean removed = false;
|
||||
private boolean visible = true;
|
||||
|
||||
OsmMarker(MapView map, MarkerOptions options, ItemizedIconOverlay<MarkerOverlayItem> markersOverlay) {
|
||||
this.map = map;
|
||||
|
||||
overlayItem = new MarkerOverlayItem(
|
||||
OsmUtils.toGeoPoint(options.getPosition()),
|
||||
this
|
||||
);
|
||||
|
||||
OsmBitmapDescriptor descriptor = (OsmBitmapDescriptor) options.getIcon();
|
||||
overlayItem.setMarker(
|
||||
new BitmapDrawable(map.getResources(), descriptor.bitmap)
|
||||
);
|
||||
overlayItem.setMarkerHotspot(
|
||||
anchorToHotspot(options.getAnchorU(), options.getAnchorV())
|
||||
);
|
||||
|
||||
markersOverlay.addItem(overlayItem);
|
||||
|
||||
overlay = markersOverlay;
|
||||
position = options.getPosition();
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(BitmapDescriptor icon) {
|
||||
OsmBitmapDescriptor descriptor = (OsmBitmapDescriptor) icon;
|
||||
|
||||
overlayItem.setMarker(new BitmapDrawable(map.getResources(), descriptor.bitmap));
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LatLng getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showInfoWindow() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRotation(float rotation) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
if (removed || this.visible == visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
overlay.addItem(overlayItem);
|
||||
} else {
|
||||
overlay.removeItem(overlayItem);
|
||||
}
|
||||
|
||||
this.visible = visible;
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (!visible) {
|
||||
removed = true;
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
return;
|
||||
}
|
||||
|
||||
overlay.removeItem(overlayItem);
|
||||
removed = true;
|
||||
visible = false;
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setZ(int z) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.drawable;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Region;
|
||||
|
||||
import com.car2go.maps.model.LatLng;
|
||||
import com.car2go.maps.model.Polygon;
|
||||
import com.car2go.maps.model.PolygonOptions;
|
||||
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.Projection;
|
||||
import org.osmdroid.views.overlay.Overlay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.toGeoPoints;
|
||||
|
||||
/**
|
||||
* Draws polygon on OpenStreetMaps.
|
||||
* Associated with given {@link com.car2go.maps.AnyMap} object, so it should not be cached.
|
||||
*/
|
||||
public class OsmPolygon implements Polygon {
|
||||
|
||||
private final MapView map;
|
||||
private final PolygonOverlay overlay;
|
||||
private final PolygonOptions options;
|
||||
|
||||
OsmPolygon(MapView map, PolygonOptions options) {
|
||||
this.map = map;
|
||||
this.options = options;
|
||||
|
||||
overlay = new PolygonOverlay(map, options);
|
||||
|
||||
map.getOverlays().add(0, overlay);
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHoles(List<List<LatLng>> holes) {
|
||||
overlay.setHoles(holes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LatLng> getPoints() {
|
||||
return options.getPoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
overlay.setEnabled(visible);
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
map.getOverlays().remove(overlay);
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay which draws a single polygon (with holes) on OpenStreetMap
|
||||
*/
|
||||
private static class PolygonOverlay extends Overlay {
|
||||
|
||||
private final MapView map;
|
||||
|
||||
private final boolean outsider;
|
||||
|
||||
private final List<IGeoPoint> points;
|
||||
private final List<List<IGeoPoint>> holes = new ArrayList<>();
|
||||
|
||||
private final Path polygonPath = new Path();
|
||||
private final Paint fillPaint;
|
||||
private final Paint strokePaint;
|
||||
|
||||
private final Point auxPoint = new Point();
|
||||
|
||||
public PolygonOverlay(MapView map, PolygonOptions options) {
|
||||
super(map.getContext());
|
||||
|
||||
this.map = map;
|
||||
|
||||
outsider = options.isOutsider();
|
||||
points = toGeoPoints(options.getPoints());
|
||||
|
||||
fillPaint = new Paint();
|
||||
fillPaint.setStyle(Paint.Style.FILL);
|
||||
fillPaint.setColor(options.getFillColor());
|
||||
|
||||
fillPaint.setAlpha(
|
||||
Color.alpha(options.getFillColor()) / 2
|
||||
);
|
||||
|
||||
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
strokePaint.setStyle(Paint.Style.STROKE);
|
||||
strokePaint.setColor(options.getStrokeColor());
|
||||
strokePaint.setStrokeWidth(options.getStrokeWidth());
|
||||
}
|
||||
|
||||
void setHoles(List<List<LatLng>> holes) {
|
||||
this.holes.clear();
|
||||
|
||||
for (List<LatLng> hole : holes) {
|
||||
this.holes.add(
|
||||
toGeoPoints(hole)
|
||||
);
|
||||
}
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas c, MapView osmv, boolean shadow) {
|
||||
Projection projection = osmv.getProjection();
|
||||
|
||||
c.save();
|
||||
|
||||
if (!holes.isEmpty()) {
|
||||
polygonPath.rewind();
|
||||
populateHoles(projection);
|
||||
|
||||
// Draw outline of the holes
|
||||
c.drawPath(polygonPath, strokePaint);
|
||||
|
||||
// Clip holes so that when we'll draw polygon on top of them the area under the
|
||||
// holes will be "cropped"
|
||||
c.clipPath(polygonPath, Region.Op.DIFFERENCE);
|
||||
}
|
||||
|
||||
if (!points.isEmpty()) {
|
||||
if (!outsider) {
|
||||
polygonPath.rewind();
|
||||
populateOutline(projection);
|
||||
|
||||
// Draw and fill polygon itself
|
||||
c.drawPath(polygonPath, fillPaint);
|
||||
c.drawPath(polygonPath, strokePaint);
|
||||
} else {
|
||||
// Optimization for outsider-polygons. Just fill the whole screen with the color.
|
||||
// We cropped holes before, so it will appear as "transparent" polygons are
|
||||
// drawn.
|
||||
c.drawPaint(fillPaint);
|
||||
}
|
||||
}
|
||||
|
||||
c.restore();
|
||||
}
|
||||
|
||||
private void populateOutline(Projection projection) {
|
||||
populatePath(projection, points, polygonPath);
|
||||
}
|
||||
|
||||
private void populateHoles(Projection projection) {
|
||||
for (List<IGeoPoint> hole : holes) {
|
||||
populatePath(projection, hole, polygonPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void populatePath(Projection projection, List<IGeoPoint> points, Path path) {
|
||||
Point startPoint = projection.toPixels(points.get(0), auxPoint);
|
||||
path.moveTo(startPoint.x, startPoint.y);
|
||||
|
||||
for (int i = 1; i < points.size(); i++) {
|
||||
Point point = projection.toPixels(points.get(i), auxPoint);
|
||||
|
||||
path.lineTo(point.x, point.y);
|
||||
}
|
||||
|
||||
path.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.drawable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
|
||||
import com.car2go.maps.model.Polyline;
|
||||
import com.car2go.maps.model.PolylineOptions;
|
||||
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.views.MapView;
|
||||
import org.osmdroid.views.Projection;
|
||||
import org.osmdroid.views.overlay.Overlay;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.toGeoPoints;
|
||||
|
||||
/**
|
||||
* Draws polyline on OpenStreetMaps.
|
||||
* Associated with given {@link com.car2go.maps.AnyMap} object, so it should not be cached.
|
||||
*/
|
||||
public class OsmPolyline implements Polyline {
|
||||
|
||||
private final MapView map;
|
||||
private final PolylineOverlay overlay;
|
||||
|
||||
public OsmPolyline(MapView map, PolylineOptions options) {
|
||||
this.map = map;
|
||||
|
||||
overlay = new PolylineOverlay(map.getContext(), options);
|
||||
map.getOverlays().add(overlay);
|
||||
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
overlay.setEnabled(visible);
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
map.getOverlays().remove(overlay);
|
||||
map.invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlay which draws a single polyline on OpenStreetMap
|
||||
*/
|
||||
private static class PolylineOverlay extends Overlay {
|
||||
|
||||
private static final int ITEMS_PER_LINE = 4;
|
||||
|
||||
private final List<IGeoPoint> geoPoints;
|
||||
private final float[] linePoints;
|
||||
|
||||
private final Paint linePaint;
|
||||
|
||||
private final Point auxPoint = new Point();
|
||||
|
||||
public PolylineOverlay(Context ctx, PolylineOptions options) {
|
||||
super(ctx);
|
||||
|
||||
geoPoints = toGeoPoints(options.getPoints());
|
||||
linePoints = new float[(geoPoints.size() - 1) * ITEMS_PER_LINE];
|
||||
|
||||
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
linePaint.setStyle(Paint.Style.STROKE);
|
||||
linePaint.setStrokeWidth(options.getWidth());
|
||||
linePaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
linePaint.setColor(options.getColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas c, MapView osmv, boolean shadow) {
|
||||
Projection projection = osmv.getProjection();
|
||||
|
||||
prepareLines(projection);
|
||||
|
||||
c.drawLines(linePoints, linePaint);
|
||||
}
|
||||
|
||||
private void prepareLines(Projection projection) {
|
||||
for (int i = 0; i < geoPoints.size() - 1; i++) {
|
||||
projection.toPixels(geoPoints.get(i), auxPoint);
|
||||
|
||||
linePoints[ITEMS_PER_LINE * i] = auxPoint.x;
|
||||
linePoints[ITEMS_PER_LINE * i + 1] = auxPoint.y;
|
||||
|
||||
projection.toPixels(geoPoints.get(i + 1), auxPoint);
|
||||
|
||||
linePoints[ITEMS_PER_LINE * i + 2] = auxPoint.x;
|
||||
linePoints[ITEMS_PER_LINE * i + 3] = auxPoint.y;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.drawable.overlay;
|
||||
|
||||
import com.car2go.maps.model.Marker;
|
||||
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.views.overlay.OverlayItem;
|
||||
|
||||
/**
|
||||
* Overlay item for {@link org.osmdroid.views.overlay.ItemizedIconOverlay} which is associated
|
||||
* with {@link Marker}
|
||||
*/
|
||||
public class MarkerOverlayItem extends OverlayItem {
|
||||
|
||||
public final Marker marker;
|
||||
|
||||
/**
|
||||
* @param geoPoint position of the item
|
||||
* @param marker associated {@link Marker}
|
||||
*/
|
||||
public MarkerOverlayItem(IGeoPoint geoPoint, Marker marker) {
|
||||
super(null, null, geoPoint);
|
||||
|
||||
this.marker = marker;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.util;
|
||||
|
||||
import com.car2go.maps.model.LatLng;
|
||||
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
import org.osmdroid.views.overlay.OverlayItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* OpenStreetMaps related utilities
|
||||
*/
|
||||
public class OsmUtils {
|
||||
|
||||
private static final float ANCHOR_LOW_THRESHOLD = 0.2f;
|
||||
private static final float ANCHOR_HIGH_THRESHOLD = 0.7f;
|
||||
|
||||
/**
|
||||
* @return {@link IGeoPoint} with same coordinates as {@link LatLng}
|
||||
*/
|
||||
public static IGeoPoint toGeoPoint(LatLng latLng) {
|
||||
return new GeoPoint(
|
||||
latLng.latitude,
|
||||
latLng.longitude
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience for {@link #toGeoPoint(LatLng)} which works on {@link List}
|
||||
*/
|
||||
public static List<IGeoPoint> toGeoPoints(List<LatLng> points) {
|
||||
List<IGeoPoint> result = new ArrayList<>();
|
||||
|
||||
for (LatLng point : points) {
|
||||
result.add(
|
||||
toGeoPoint(point)
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link LatLng} with same coordinates as {@link IGeoPoint}
|
||||
*/
|
||||
public static LatLng toLatLng(IGeoPoint geoPoint) {
|
||||
return new LatLng(
|
||||
geoPoint.getLatitude(),
|
||||
geoPoint.getLongitude()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since OpenStreetMaps does not support UV coordinates for anchors there is a need for
|
||||
* explicit conversion. This method searches for
|
||||
* {@link org.osmdroid.views.overlay.OverlayItem.HotspotPlace} which is closest to given UV
|
||||
* coordinates.
|
||||
*
|
||||
* @return {@link org.osmdroid.views.overlay.OverlayItem.HotspotPlace} which is closest to
|
||||
* given UV coordinates.
|
||||
*/
|
||||
public static OverlayItem.HotspotPlace anchorToHotspot(float u, float v) {
|
||||
if (v > ANCHOR_HIGH_THRESHOLD) {
|
||||
if (u < ANCHOR_LOW_THRESHOLD) {
|
||||
return OverlayItem.HotspotPlace.LOWER_LEFT_CORNER;
|
||||
} else if (u > ANCHOR_HIGH_THRESHOLD) {
|
||||
return OverlayItem.HotspotPlace.LOWER_RIGHT_CORNER;
|
||||
} else {
|
||||
return OverlayItem.HotspotPlace.BOTTOM_CENTER;
|
||||
}
|
||||
} else if (v < ANCHOR_LOW_THRESHOLD) {
|
||||
if (u < ANCHOR_LOW_THRESHOLD) {
|
||||
return OverlayItem.HotspotPlace.UPPER_LEFT_CORNER;
|
||||
} else if (u > ANCHOR_HIGH_THRESHOLD) {
|
||||
return OverlayItem.HotspotPlace.UPPER_RIGHT_CORNER;
|
||||
} else {
|
||||
return OverlayItem.HotspotPlace.TOP_CENTER;
|
||||
}
|
||||
} else {
|
||||
if (u < ANCHOR_LOW_THRESHOLD) {
|
||||
return OverlayItem.HotspotPlace.LEFT_CENTER;
|
||||
} else if (u > ANCHOR_HIGH_THRESHOLD) {
|
||||
return OverlayItem.HotspotPlace.RIGHT_CENTER;
|
||||
} else {
|
||||
return OverlayItem.HotspotPlace.CENTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm;
|
||||
|
||||
import com.car2go.maps.AnyMap;
|
||||
import com.car2go.maps.model.LatLng;
|
||||
import com.car2go.maps.model.LatLngBounds;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.osmdroid.api.IMapController;
|
||||
|
||||
import static com.car2go.maps.osm.util.OsmUtils.toGeoPoint;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.refEq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
public class CameraUpdateHandlerTest {
|
||||
|
||||
@Mock
|
||||
org.osmdroid.views.MapView map;
|
||||
@Mock
|
||||
IMapController mapController;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
doReturn(mapController)
|
||||
.when(map)
|
||||
.getController();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveCameraToPosition() throws Exception {
|
||||
// Given
|
||||
CameraUpdateHandler handler = new CameraUpdateHandler(map);
|
||||
|
||||
final LatLng center = new LatLng(10, 10);
|
||||
|
||||
OsmCameraUpdate cameraUpdate = new OsmCameraUpdate.Builder()
|
||||
.center(center)
|
||||
.build();
|
||||
|
||||
// When
|
||||
handler.moveCamera(cameraUpdate);
|
||||
|
||||
// Then
|
||||
verify(mapController).setCenter(eq(toGeoPoint(center)));
|
||||
verifyNoMoreInteractions(mapController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveCameraToPositionWithZoom() throws Exception {
|
||||
// Given
|
||||
CameraUpdateHandler handler = new CameraUpdateHandler(map);
|
||||
|
||||
final LatLng center = new LatLng(10, 10);
|
||||
final int zoomLevel = 10;
|
||||
|
||||
OsmCameraUpdate cameraUpdate = new OsmCameraUpdate.Builder()
|
||||
.center(center)
|
||||
.zoom((float) zoomLevel)
|
||||
.build();
|
||||
|
||||
// When
|
||||
handler.moveCamera(cameraUpdate);
|
||||
|
||||
// Then
|
||||
verify(mapController).setCenter(eq(toGeoPoint(center)));
|
||||
verify(mapController).setZoom(zoomLevel);
|
||||
verifyNoMoreInteractions(mapController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveCameraToBounds() throws Exception {
|
||||
// Given
|
||||
CameraUpdateHandler handler = new CameraUpdateHandler(map);
|
||||
|
||||
final LatLngBounds bounds = new LatLngBounds(
|
||||
new LatLng(10, 10),
|
||||
new LatLng(20, 20)
|
||||
);
|
||||
|
||||
OsmCameraUpdate cameraUpdate = new OsmCameraUpdate.Builder()
|
||||
.bounds(bounds)
|
||||
.build();
|
||||
|
||||
// When
|
||||
handler.moveCamera(cameraUpdate);
|
||||
|
||||
// Then
|
||||
verify(mapController).setCenter(eq(
|
||||
toGeoPoint(bounds.getCenter())
|
||||
));
|
||||
verify(mapController).zoomToSpan(
|
||||
eq((int) (10 * 1e6)),
|
||||
eq((int) (10 * 1e6))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnimateCamera() throws Exception {
|
||||
// Given
|
||||
CameraUpdateHandler handler = spy(new CameraUpdateHandler(map));
|
||||
|
||||
final LatLng center = new LatLng(10, 10);
|
||||
|
||||
OsmCameraUpdate cameraUpdate = new OsmCameraUpdate.Builder()
|
||||
.center(center)
|
||||
.build();
|
||||
|
||||
// When
|
||||
handler.animateCamera(cameraUpdate);
|
||||
|
||||
// Then
|
||||
verify(handler).moveCamera(refEq(cameraUpdate));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnimateCameraWithCallback() throws Exception {
|
||||
// Given
|
||||
CameraUpdateHandler handler = spy(new CameraUpdateHandler(map));
|
||||
|
||||
final LatLng center = new LatLng(10, 10);
|
||||
|
||||
OsmCameraUpdate cameraUpdate = new OsmCameraUpdate.Builder()
|
||||
.center(center)
|
||||
.build();
|
||||
|
||||
AnyMap.CancelableCallback callback = mock(AnyMap.CancelableCallback.class);
|
||||
|
||||
// When
|
||||
handler.animateCamera(cameraUpdate, callback);
|
||||
|
||||
// Then
|
||||
verify(handler).moveCamera(refEq(cameraUpdate));
|
||||
|
||||
verify(callback).onFinish();
|
||||
verifyNoMoreInteractions(callback);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Daimler AG / Moovel GmbH
|
||||
*
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
package com.car2go.maps.osm.util;
|
||||
|
||||
import com.car2go.maps.model.LatLng;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.osmdroid.api.IGeoPoint;
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
import org.osmdroid.views.overlay.OverlayItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class OsmUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testToGeoPoint() throws Exception {
|
||||
// Given
|
||||
final LatLng input = new LatLng(10d, 20d);
|
||||
|
||||
final GeoPoint expected = new GeoPoint(10d, 20d);
|
||||
|
||||
// When
|
||||
IGeoPoint output = OsmUtils.toGeoPoint(input);
|
||||
|
||||
// Then
|
||||
assertEquals(expected, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToGeoPoints() throws Exception {
|
||||
// Given
|
||||
final List<LatLng> input = asList(
|
||||
new LatLng(10d, 20d),
|
||||
new LatLng(30d, 40d)
|
||||
);
|
||||
|
||||
final List<GeoPoint> expected = asList(
|
||||
new GeoPoint(10d, 20d),
|
||||
new GeoPoint(30d, 40d)
|
||||
);
|
||||
|
||||
// When
|
||||
List<IGeoPoint> output = OsmUtils.toGeoPoints(input);
|
||||
|
||||
// Then
|
||||
assertEquals(expected, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToLatLng() throws Exception {
|
||||
// Given
|
||||
final GeoPoint input = new GeoPoint(10d, 20d);
|
||||
|
||||
final LatLng expected = new LatLng(10d, 20d);
|
||||
|
||||
// When
|
||||
LatLng output = OsmUtils.toLatLng(input);
|
||||
|
||||
// Then
|
||||
assertEquals(expected, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnchorToHotspot() throws Exception {
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.UPPER_LEFT_CORNER,
|
||||
OsmUtils.anchorToHotspot(0f, 0f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.TOP_CENTER,
|
||||
OsmUtils.anchorToHotspot(0.5f, 0f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.UPPER_RIGHT_CORNER,
|
||||
OsmUtils.anchorToHotspot(1f, 0f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.LEFT_CENTER,
|
||||
OsmUtils.anchorToHotspot(0f, 0.5f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.CENTER,
|
||||
OsmUtils.anchorToHotspot(0.5f, 0.5f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.RIGHT_CENTER,
|
||||
OsmUtils.anchorToHotspot(1f, 0.5f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.LOWER_LEFT_CORNER,
|
||||
OsmUtils.anchorToHotspot(0f, 1f)
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.BOTTOM_CENTER,
|
||||
OsmUtils.anchorToHotspot(0.5f, 1f)
|
||||
);
|
||||
assertEquals(
|
||||
OverlayItem.HotspotPlace.LOWER_RIGHT_CORNER,
|
||||
OsmUtils.anchorToHotspot(1f, 1f)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +1 @@
|
|||
include ':app'
|
||||
include ':app', ':anymaps-base', ':anymaps-osm'
|
||||
|
|
Loading…
Reference in New Issue