Skip to content

Commit 87fd9df

Browse files
author
Nicholas Hallahan
committed
Merge POI Functionality into Master
Merge commit 'e17054a7b8ef71c80375ef34d163afc6ff91392b'
2 parents a7d413b + e17054a commit 87fd9df

138 files changed

Lines changed: 2888 additions & 625 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,5 @@ local.properties
6161

6262
# TeXlipse plugin
6363
.texlipse
64+
65+
app/app.iml

MapboxAndroidSDK/build.gradle

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
buildscript {
2-
repositories {
3-
mavenCentral()
4-
}
5-
dependencies {
6-
classpath 'com.android.tools.build:gradle:1.0.0'
7-
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.10.1'
8-
}
9-
}
10-
111
apply plugin: 'android-sdk-manager'
122
apply plugin: 'com.android.library'
133
apply plugin: 'checkstyle'
@@ -33,9 +23,9 @@ repositories {
3323

3424
dependencies {
3525
compile 'com.vividsolutions:jts:1.13'
36-
compile 'com.android.support:support-v4:21.0.3'
37-
compile 'com.squareup.okhttp:okhttp:2.2.0'
38-
compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'
26+
compile 'com.android.support:support-v4:22.2.0'
27+
compile 'com.squareup.okhttp:okhttp:2.4.0'
28+
compile 'com.squareup.okhttp:okhttp-urlconnection:2.4.0'
3929
compile 'com.nineoldandroids:library:2.4.0'
4030
compile 'com.jakewharton:disklrucache:2.0.2'
4131
}
@@ -49,6 +39,17 @@ android {
4939
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
5040
}
5141

42+
buildTypes {
43+
all {
44+
resValue "string", "mapboxAndroidSDKVersion", project.VERSION_NAME
45+
}
46+
}
47+
48+
compileOptions {
49+
sourceCompatibility JavaVersion.VERSION_1_7
50+
targetCompatibility JavaVersion.VERSION_1_7
51+
}
52+
5253
sourceSets {
5354

5455
main {

MapboxAndroidSDK/gradle.properties

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
GROUP=com.mapbox.mapboxsdk
2-
VERSION_NAME=0.6.0-SNAPSHOT
2+
VERSION_NAME=0.7.5-SNAPSHOT
33

44
POM_DESCRIPTION=Mapbox SDK
55
POM_URL=https://github.com/mapbox/mapbox-android-sdk
@@ -13,9 +13,9 @@ POM_DEVELOPER_ID=mapbox
1313
POM_DEVELOPER_NAME=Mapbox
1414

1515
ANDROID_MIN_SDK=9
16-
ANDROID_BUILD_TARGET_SDK_VERSION=21
17-
ANDROID_BUILD_TOOLS_VERSION=21.1.2
18-
ANDROID_BUILD_SDK_VERSION=21
16+
ANDROID_BUILD_TARGET_SDK_VERSION=22
17+
ANDROID_BUILD_TOOLS_VERSION=22.0.1
18+
ANDROID_BUILD_SDK_VERSION=22
1919

2020
POM_NAME=Mapbox SDK
2121
POM_ARTIFACT_ID=mapbox-android-sdk
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.mapbox.mapboxsdk.clustering;
2+
3+
4+
import com.mapbox.mapboxsdk.geometry.LatLng;
5+
6+
import java.util.Collection;
7+
8+
/**
9+
* A collection of ClusterItems that are nearby each other.
10+
*/
11+
public interface Cluster<T extends ClusterItem> {
12+
public LatLng getPosition();
13+
14+
Collection<T> getItems();
15+
16+
int getSize();
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.mapbox.mapboxsdk.clustering;
2+
3+
import com.mapbox.mapboxsdk.geometry.LatLng;
4+
5+
/**
6+
* ClusterItem represents a marker on the map.
7+
*/
8+
public interface ClusterItem {
9+
10+
/**
11+
* The position of this marker. This must always return the same value.
12+
*/
13+
LatLng getPosition();
14+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.mapbox.mapboxsdk.clustering.algo;
2+
3+
import com.mapbox.mapboxsdk.clustering.Cluster;
4+
import com.mapbox.mapboxsdk.clustering.ClusterItem;
5+
6+
import java.util.Collection;
7+
import java.util.Set;
8+
9+
/**
10+
* Logic for computing clusters
11+
*/
12+
public interface Algorithm<T extends ClusterItem> {
13+
void addItem(T item);
14+
15+
void addItems(Collection<T> items);
16+
17+
void clearItems();
18+
19+
void removeItem(T item);
20+
21+
Set<? extends Cluster<T>> getClusters(double zoom);
22+
23+
Collection<T> getItems();
24+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package com.mapbox.mapboxsdk.clustering.algo;
2+
3+
4+
import com.mapbox.mapboxsdk.clustering.Cluster;
5+
import com.mapbox.mapboxsdk.clustering.ClusterItem;
6+
import com.mapbox.mapboxsdk.clustering.geometry.Bounds;
7+
import com.mapbox.mapboxsdk.clustering.geometry.Point;
8+
import com.mapbox.mapboxsdk.clustering.projection.SphericalMercatorProjection;
9+
import com.mapbox.mapboxsdk.clustering.quadtree.PointQuadTree;
10+
import com.mapbox.mapboxsdk.geometry.LatLng;
11+
12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.HashMap;
16+
import java.util.HashSet;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.Set;
20+
21+
/**
22+
* A simple clustering algorithm with O(nlog n) performance. Resulting clusters are not
23+
* hierarchical.
24+
* <p/>
25+
* High level algorithm:<br>
26+
* 1. Iterate over items in the order they were added (candidate clusters).<br>
27+
* 2. Create a cluster with the center of the item. <br>
28+
* 3. Add all items that are within a certain distance to the cluster. <br>
29+
* 4. Move any items out of an existing cluster if they are closer to another cluster. <br>
30+
* 5. Remove those items from the list of candidate clusters.
31+
* <p/>
32+
* Clusters have the center of the first element (not the centroid of the items within it).
33+
*/
34+
public class NonHierarchicalDistanceBasedAlgorithm<T extends ClusterItem> implements Algorithm<T> {
35+
public static final int MAX_DISTANCE_AT_ZOOM = 100; // essentially 100 dp.
36+
37+
/**
38+
* Any modifications should be synchronized on mQuadTree.
39+
*/
40+
private final Collection<QuadItem<T>> mItems = new ArrayList<QuadItem<T>>();
41+
42+
/**
43+
* Any modifications should be synchronized on mQuadTree.
44+
*/
45+
private final PointQuadTree<QuadItem<T>> mQuadTree = new PointQuadTree<QuadItem<T>>(0, 1, 0, 1);
46+
47+
private static final SphericalMercatorProjection PROJECTION = new SphericalMercatorProjection(1);
48+
49+
@Override
50+
public void addItem(T item) {
51+
final QuadItem<T> quadItem = new QuadItem<T>(item);
52+
synchronized (mQuadTree) {
53+
mItems.add(quadItem);
54+
mQuadTree.add(quadItem);
55+
}
56+
}
57+
58+
@Override
59+
public void addItems(Collection<T> items) {
60+
for (T item : items) {
61+
addItem(item);
62+
}
63+
}
64+
65+
@Override
66+
public void clearItems() {
67+
synchronized (mQuadTree) {
68+
mItems.clear();
69+
mQuadTree.clear();
70+
}
71+
}
72+
73+
@Override
74+
public void removeItem(T item) {
75+
// TODO: delegate QuadItem#hashCode and QuadItem#equals to its item.
76+
throw new UnsupportedOperationException("NonHierarchicalDistanceBasedAlgorithm.remove not implemented");
77+
}
78+
79+
@Override
80+
public Set<? extends Cluster<T>> getClusters(double zoom) {
81+
final int discreteZoom = (int) zoom;
82+
83+
final double zoomSpecificSpan = MAX_DISTANCE_AT_ZOOM / Math.pow(2, discreteZoom) / 256;
84+
85+
final Set<QuadItem<T>> visitedCandidates = new HashSet<QuadItem<T>>();
86+
final Set<Cluster<T>> results = new HashSet<Cluster<T>>();
87+
final Map<QuadItem<T>, Double> distanceToCluster = new HashMap<QuadItem<T>, Double>();
88+
final Map<QuadItem<T>, StaticCluster<T>> itemToCluster = new HashMap<QuadItem<T>, StaticCluster<T>>();
89+
90+
synchronized (mQuadTree) {
91+
for (QuadItem<T> candidate : mItems) {
92+
if (visitedCandidates.contains(candidate)) {
93+
// Candidate is already part of another cluster.
94+
continue;
95+
}
96+
97+
Bounds searchBounds = createBoundsFromSpan(candidate.getPoint(), zoomSpecificSpan);
98+
Collection<QuadItem<T>> clusterItems;
99+
clusterItems = mQuadTree.search(searchBounds);
100+
if (clusterItems.size() == 1) {
101+
// Only the current marker is in range. Just add the single item to the results.
102+
results.add(candidate);
103+
visitedCandidates.add(candidate);
104+
distanceToCluster.put(candidate, 0d);
105+
continue;
106+
}
107+
StaticCluster<T> cluster = new StaticCluster<>(candidate.mClusterItem.getPosition());
108+
results.add(cluster);
109+
110+
for (QuadItem<T> clusterItem : clusterItems) {
111+
Double existingDistance = distanceToCluster.get(clusterItem);
112+
double distance = distanceSquared(clusterItem.getPoint(), candidate.getPoint());
113+
if (existingDistance != null) {
114+
// Item already belongs to another cluster. Check if it's closer to this cluster.
115+
if (existingDistance < distance) {
116+
continue;
117+
}
118+
// Move item to the closer cluster.
119+
itemToCluster.get(clusterItem).remove(clusterItem.mClusterItem);
120+
}
121+
distanceToCluster.put(clusterItem, distance);
122+
cluster.add(clusterItem.mClusterItem);
123+
itemToCluster.put(clusterItem, cluster);
124+
}
125+
visitedCandidates.addAll(clusterItems);
126+
}
127+
}
128+
return results;
129+
}
130+
131+
@Override
132+
public Collection<T> getItems() {
133+
final List<T> items = new ArrayList<T>();
134+
synchronized (mQuadTree) {
135+
for (QuadItem<T> quadItem : mItems) {
136+
items.add(quadItem.mClusterItem);
137+
}
138+
}
139+
return items;
140+
}
141+
142+
private double distanceSquared(Point a, Point b) {
143+
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
144+
}
145+
146+
private Bounds createBoundsFromSpan(Point p, double span) {
147+
// TODO: Use a span that takes into account the visual size of the marker, not just its
148+
// LatLng.
149+
double halfSpan = span / 2;
150+
return new Bounds(
151+
p.x - halfSpan, p.x + halfSpan,
152+
p.y - halfSpan, p.y + halfSpan);
153+
}
154+
155+
private static class QuadItem<T extends ClusterItem> implements PointQuadTree.Item, Cluster<T> {
156+
private final T mClusterItem;
157+
private final Point mPoint;
158+
private final LatLng mPosition;
159+
private Set<T> singletonSet;
160+
161+
private QuadItem(T item) {
162+
mClusterItem = item;
163+
mPosition = item.getPosition();
164+
mPoint = PROJECTION.toPoint(mPosition);
165+
singletonSet = Collections.singleton(mClusterItem);
166+
}
167+
168+
@Override
169+
public Point getPoint() {
170+
return mPoint;
171+
}
172+
173+
@Override
174+
public LatLng getPosition() {
175+
return mPosition;
176+
}
177+
178+
@Override
179+
public Set<T> getItems() {
180+
return singletonSet;
181+
}
182+
183+
@Override
184+
public int getSize() {
185+
return 1;
186+
}
187+
}
188+
}

0 commit comments

Comments
 (0)