Skip to content

Commit 46b9ef7

Browse files
committed
Initial commit.
1 parent 34bf0d3 commit 46b9ef7

File tree

130 files changed

+9741
-1
lines changed

Some content is hidden

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

130 files changed

+9741
-1
lines changed

.gitignore

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.DS_Store
2+
13
# built application files
24
*.apk
35
*.ap_
@@ -11,10 +13,13 @@
1113
# generated files
1214
bin/
1315
gen/
16+
build/
1417

1518
# Local configuration file (sdk path, etc)
1619
local.properties
1720

18-
# Eclipse project files
21+
# IDE project files
1922
.classpath
2023
.project
24+
*.iml
25+
.idea
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#Fri Aug 30 19:01:30 BST 2013
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

261 KB
Binary file not shown.
1.62 MB
Binary file not shown.
25.9 KB
Binary file not shown.
88 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#Fri Aug 30 18:47:07 BST 2013
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

255 KB
Binary file not shown.
1.77 MB
Binary file not shown.
21.7 KB
Binary file not shown.
77.2 KB
Binary file not shown.

CartoCache/build.gradle

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apply plugin: 'android-library'
2+
3+
repositories {
4+
mavenCentral()
5+
mavenLocal()
6+
}
7+
8+
dependencies {
9+
compile 'com.google.android.gms:play-services:3.1.36'
10+
compile 'com.android.support:support-v4:18.0.+'
11+
compile 'com.android.support:appcompat-v7:18.0.+'
12+
}
13+
14+
android {
15+
compileSdkVersion 18
16+
buildToolsVersion "18.0.1"
17+
18+
defaultConfig {
19+
minSdkVersion 8
20+
targetSdkVersion 18
21+
}
22+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.codeandmagic.cartocache"
4+
android:versionCode="1"
5+
android:versionName="1.0">
6+
7+
<uses-sd
8+
android:minSdkVersion="8"
9+
android:targetSdkVersion="18" />
10+
11+
<application></application>
12+
13+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package com.codeandmagic.cartocache;
2+
3+
import com.google.android.gms.maps.GoogleMap;
4+
import com.google.android.gms.maps.model.CameraPosition;
5+
import com.google.android.gms.maps.model.LatLng;
6+
import com.google.android.gms.maps.model.Marker;
7+
import com.google.android.gms.maps.model.Polygon;
8+
import com.google.android.gms.maps.model.PolygonOptions;
9+
10+
import java.util.ArrayList;
11+
import java.util.Collection;
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.logging.Logger;
16+
17+
import static com.codeandmagic.cartocache.QTile.EMPTY_ARRAY;
18+
import static com.codeandmagic.cartocache.QTile.getTile;
19+
import static com.codeandmagic.cartocache.Utils.diff;
20+
21+
/**
22+
* Created by evelyne24.
23+
*/
24+
public class CartoCache<P extends Place> implements GoogleMap.OnCameraChangeListener, DataFetcher.Callback<P> {
25+
26+
private static final L log = L.getLog(CartoCache.class);
27+
28+
private final GoogleMap map;
29+
private final CartoCacheConfig<P> config;
30+
31+
private Map<QTile, Polygon> drawnTiles = new HashMap<QTile, Polygon>();
32+
private Map<QTile, List<Marker>> markers = new HashMap<QTile, List<Marker>>();
33+
private QTile[] visibleTiles = EMPTY_ARRAY;
34+
35+
public CartoCache(CartoCacheConfig<P> config, GoogleMap map) {
36+
this.config = config;
37+
this.map = map;
38+
this.map.setOnCameraChangeListener(this);
39+
}
40+
41+
@Override
42+
public void onCameraChange(CameraPosition cameraPosition) {
43+
final LatLng latLng = cameraPosition.target;
44+
final ZoomLevel zoom = getDataFetchZoom(cameraPosition.zoom);
45+
final QTile centerTile = getTile(latLng, zoom);
46+
centerTile.initNeighbourTiles();
47+
48+
QTile[] newTiles = new QTile[4];
49+
newTiles[0] = centerTile;
50+
51+
QTile[] neighbours = centerTile.getClosestNeighbourTiles(latLng);
52+
System.arraycopy(neighbours, 0, newTiles, 1, neighbours.length);
53+
54+
QTile[] removedTiles = diff(visibleTiles, newTiles, EMPTY_ARRAY);
55+
QTile[] addedTiles = diff(newTiles, visibleTiles, EMPTY_ARRAY);
56+
57+
// Delete markers for all remove drawnTiles
58+
for (QTile tile : removedTiles) {
59+
removePlacesForTile(tile);
60+
}
61+
62+
// Delete all tile debug squares
63+
for (Map.Entry<QTile, Polygon> entry : drawnTiles.entrySet()) {
64+
entry.getValue().remove();
65+
}
66+
67+
if (config.debug) {
68+
drawnTiles.clear();
69+
70+
// Add all new tile debug squares
71+
for (QTile tile : newTiles) {
72+
drawnTiles.put(tile, drawTile(tile, tile.equals(centerTile) ? config.currentTileConfig : config.tileConfig));
73+
}
74+
}
75+
76+
// Add markers for new added drawnTiles:
77+
// First verify if the drawnTiles are in cache.
78+
// If not, request places for the new drawnTiles.
79+
for (QTile qTile : addedTiles) {
80+
Collection<P> places = config.placesCache.get(qTile);
81+
if (places != null) {
82+
if(config.debug) {
83+
log.i("Cache HIT for QTile " + qTile.quadKey);
84+
}
85+
addPlacesForTile(qTile, places);
86+
} else {
87+
if(config.debug) {
88+
log.w("Cache MISS for QTile " + qTile.quadKey);
89+
}
90+
config.dataFetcher.requestPlaces(qTile, this);
91+
}
92+
}
93+
94+
visibleTiles = newTiles;
95+
}
96+
97+
private ZoomLevel getDataFetchZoom(float cameraZoom) {
98+
final int seeAllScreenZoom = (int) (cameraZoom - 1);
99+
if (seeAllScreenZoom < 1) {
100+
return ZoomLevel.Z1;
101+
}
102+
if (seeAllScreenZoom > config.maxDataFetchZoom.zoom) {
103+
return config.maxDataFetchZoom;
104+
}
105+
return ZoomLevel.get(seeAllScreenZoom);
106+
}
107+
108+
private void removePlacesForTile(QTile qTile) {
109+
final List<Marker> list = markers.get(qTile);
110+
if (list != null) {
111+
for (Marker marker : list) {
112+
marker.remove();
113+
}
114+
}
115+
markers.remove(qTile);
116+
}
117+
118+
private void addPlacesForTile(QTile qTile, Collection<P> places) {
119+
final List<Marker> list = new ArrayList<Marker>();
120+
for (P place : places) {
121+
list.add(map.addMarker(config.markerConfig.getMarker(place)));
122+
}
123+
markers.put(qTile, list);
124+
}
125+
126+
private Polygon drawTile(QTile tile, QTileDrawConfig config) {
127+
return map.addPolygon(new PolygonOptions()
128+
.add(tile.topLeft, tile.topRight, tile.bottomRight, tile.bottomLeft)
129+
.fillColor(config.fillColor)
130+
.strokeColor(config.strokeColor)
131+
.strokeWidth(config.strokeWidth));
132+
}
133+
134+
135+
@Override
136+
public void onSuccess(QTile qTile, Collection<P> places) {
137+
config.placesCache.add(qTile, places);
138+
addPlacesForTile(qTile, config.placesCache.get(qTile));
139+
}
140+
141+
@Override
142+
public void onError(QTile qTile, Throwable e) {
143+
144+
}
145+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.codeandmagic.cartocache;
2+
3+
import android.graphics.Color;
4+
5+
/**
6+
* Created by evelyne24.
7+
*/
8+
public class CartoCacheConfig<P extends Place> {
9+
10+
public static class Builder<P extends Place> {
11+
private boolean debug = true;
12+
public QTileDrawConfig currentTileConfig = new QTileDrawConfig(Color.parseColor("#77ff8282"), Color.RED, 2);
13+
public QTileDrawConfig tileConfig = new QTileDrawConfig(Color.parseColor("#77b0b1ff"), Color.BLUE, 1);
14+
15+
private ZoomLevel maxDataFetchZoom = ZoomLevel.Z17;
16+
private ZoomLevel minDataFetchZoom = ZoomLevel.Z11;
17+
private ZoomLevel clusteringZoom = ZoomLevel.Z13;
18+
private MarkerConfig<P> markerConfig = new DefaultMarkerConfig<P>();
19+
private PlacesCache<P> placesCache = new DefaultPlaceCache<P>(false);
20+
private DataFetcher<P> dataFetcher;
21+
22+
23+
public Builder<P> setDebug(boolean debug) {
24+
this.debug = debug;
25+
return this;
26+
}
27+
28+
public Builder<P> setCurrentTileConfig(QTileDrawConfig currentTileConfig) {
29+
this.currentTileConfig = currentTileConfig;
30+
return this;
31+
}
32+
33+
public Builder<P> setTileConfig(QTileDrawConfig tileConfig) {
34+
this.tileConfig = tileConfig;
35+
return this;
36+
}
37+
38+
public Builder<P> setMinDataFetchZoom(ZoomLevel minDataFetchZoom) {
39+
this.minDataFetchZoom = minDataFetchZoom;
40+
return this;
41+
}
42+
43+
public Builder<P> setMaxDataFetchZoom(ZoomLevel maxDataFetchZoom) {
44+
this.maxDataFetchZoom = maxDataFetchZoom;
45+
return this;
46+
}
47+
48+
public Builder<P> setClusteringZoom(ZoomLevel clusteringZoom) {
49+
this.clusteringZoom = clusteringZoom;
50+
return this;
51+
}
52+
53+
public Builder<P> setMarkerConfig(MarkerConfig<P> markerConfig) {
54+
this.markerConfig = markerConfig;
55+
return this;
56+
}
57+
58+
public Builder<P> setPlacesCache(PlacesCache<P> placesCache) {
59+
this.placesCache = placesCache;
60+
return this;
61+
}
62+
63+
public Builder<P> setDataFetcher(DataFetcher<P> dataFetcher) {
64+
this.dataFetcher = dataFetcher;
65+
return this;
66+
}
67+
68+
69+
public CartoCacheConfig<P> build() {
70+
if(dataFetcher == null) {
71+
throw new IllegalArgumentException("Missing required DataFetcher configuration.");
72+
}
73+
return new CartoCacheConfig<P>(this);
74+
}
75+
}
76+
77+
public final boolean debug;
78+
public final QTileDrawConfig currentTileConfig;
79+
public final QTileDrawConfig tileConfig;
80+
81+
public final ZoomLevel maxDataFetchZoom;
82+
public final ZoomLevel minDataFetchZoom;
83+
public final ZoomLevel clusteringZoom;
84+
public final MarkerConfig<P> markerConfig;
85+
public final PlacesCache<P> placesCache;
86+
public final DataFetcher<P> dataFetcher;
87+
88+
89+
private CartoCacheConfig(Builder<P> builder) {
90+
this.debug = builder.debug;
91+
this.currentTileConfig = builder.currentTileConfig;
92+
this.tileConfig = builder.tileConfig;
93+
94+
this.minDataFetchZoom = builder.minDataFetchZoom;
95+
this.maxDataFetchZoom = builder.maxDataFetchZoom;
96+
this.clusteringZoom = builder.clusteringZoom;
97+
this.markerConfig = builder.markerConfig;
98+
this.placesCache = builder.placesCache;
99+
this.dataFetcher = builder.dataFetcher;
100+
}
101+
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.codeandmagic.cartocache;
2+
3+
import java.util.Collection;
4+
5+
/**
6+
* Created by evelyne24.
7+
*/
8+
public interface DataFetcher<P extends Place> {
9+
10+
public static interface Callback<P extends Place> {
11+
void onSuccess(final QTile qTile, final Collection<P> places);
12+
void onError(final QTile qTile, final Throwable e);
13+
}
14+
15+
public void requestPlaces(final QTile qTile, final Callback<P> callback);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.codeandmagic.cartocache;
2+
3+
import com.google.android.gms.maps.model.MarkerOptions;
4+
5+
/**
6+
* Created by evelyne24.
7+
*/
8+
public class DefaultMarkerConfig<P extends Place> implements MarkerConfig<P> {
9+
10+
@Override
11+
public MarkerOptions getMarker(P place) {
12+
return new MarkerOptions().position(place.getPosition()).title("Place " + place.getId());
13+
}
14+
}

0 commit comments

Comments
 (0)