Skip to content

Commit 8dc50fa

Browse files
authored
Merge pull request #60 from ngageoint/develop
v2.1.5
2 parents 83aa827 + e81f02f commit 8dc50fa

File tree

74 files changed

+4991
-2331
lines changed

Some content is hidden

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

74 files changed

+4991
-2331
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
with:
1616
java-version: 11
1717
- name: mobsfscan
18-
uses: MobSF/mobsfscan@0.0.8
18+
uses: MobSF/mobsfscan@0.1.2
1919
with:
2020
args: '. --sarif --output results.sarif || true'
2121
- name: Upload mobsfscan report

MapCacheAndroid.sketch

15.9 KB
Binary file not shown.

docs/exampleTileUrls.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"osm.mil":"https://osm.gs.mil/tiles/default/{z}/{x}/{y}.png"
3+
}

docs/hostedGeopackages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"Hurricane Ian":"https://github.com/ngageoint/geopackage-mapcache-android/raw/master/docs/ianFlooding.gpkg",
3+
"Florida Imagery":"https://github.com/ngageoint/geopackage-mapcache-android/raw/master/docs/ianFlooding.gpkg"
4+
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
android.enableJetifier=true
22
android.useAndroidX=true
3-
android.databinding.incremental=true
3+
android.databinding.incremental=true

mapcache/build.gradle

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ android {
1313
defaultConfig {
1414
applicationId "mil.nga.mapcache"
1515
resValue "string", "applicationId", applicationId
16-
minSdkVersion 21
16+
minSdkVersion 28
1717
targetSdkVersion 31
18-
versionCode 42
19-
versionName '2.1.4'
18+
versionCode 44
19+
versionName '2.1.5'
2020
multiDexEnabled true
2121
}
2222
buildTypes {
@@ -53,11 +53,12 @@ dependencies {
5353
api 'com.google.android.material:material:1.0.0'
5454
api 'androidx.preference:preference:1.1.1'
5555
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
56-
api 'mil.nga.geopackage.map:geopackage-android-map:6.4.0' // comment out to build locally
56+
api 'mil.nga.geopackage.map:geopackage-android-map:6.7.0' // comment out to build locally
5757
//api project(':geopackage-map') // uncomment me to build locally
58-
api 'mil.nga.mgrs:mgrs-android:2.1.0'
59-
api 'mil.nga.gars:gars-android:1.1.0'
58+
api 'mil.nga.mgrs:mgrs-android:2.2.0'
59+
api 'mil.nga.gars:gars-android:1.2.0'
6060
api 'androidx.multidex:multidex:2.0.1'
61+
implementation 'com.google.code.gson:gson:2.8.7'
6162
implementation 'androidx.exifinterface:exifinterface:1.3.3'
6263
implementation 'com.google.android.gms:play-services-location:19.0.1'
6364
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package mil.nga.mapcache;
2+
3+
import android.content.Context;
4+
import android.os.Handler;
5+
import android.os.Looper;
6+
import android.widget.Toast;
7+
8+
import java.util.concurrent.atomic.AtomicInteger;
9+
import java.util.concurrent.locks.Lock;
10+
import java.util.concurrent.locks.ReentrantLock;
11+
12+
import mil.nga.geopackage.BoundingBox;
13+
import mil.nga.geopackage.features.user.FeatureDao;
14+
import mil.nga.geopackage.features.user.FeatureRow;
15+
import mil.nga.geopackage.geom.GeoPackageGeometryData;
16+
import mil.nga.geopackage.map.features.StyleCache;
17+
import mil.nga.geopackage.map.geom.GoogleMapShape;
18+
import mil.nga.geopackage.map.geom.GoogleMapShapeConverter;
19+
import mil.nga.geopackage.tiles.TileBoundingBoxUtils;
20+
import mil.nga.sf.Geometry;
21+
import mil.nga.sf.GeometryEnvelope;
22+
import mil.nga.sf.GeometryType;
23+
import mil.nga.sf.util.GeometryEnvelopeBuilder;
24+
25+
/**
26+
* Single feature row processor
27+
*
28+
* @author osbornb
29+
*/
30+
public class FeatureRowProcessor implements Runnable {
31+
32+
/**
33+
* Map update task
34+
*/
35+
private final MapFeaturesUpdateTask task;
36+
37+
/**
38+
* Database
39+
*/
40+
private final String database;
41+
42+
/**
43+
* Feature DAO
44+
*/
45+
private final FeatureDao featureDao;
46+
47+
/**
48+
* Feature row
49+
*/
50+
private final FeatureRow row;
51+
52+
/**
53+
* Total feature count
54+
*/
55+
private final AtomicInteger count;
56+
57+
/**
58+
* Total max features
59+
*/
60+
private final int maxFeatures;
61+
62+
/**
63+
* Editable shape flag
64+
*/
65+
private final boolean editable;
66+
67+
/**
68+
* Shape converter
69+
*/
70+
private final GoogleMapShapeConverter converter;
71+
72+
/**
73+
* Style Cache
74+
*/
75+
private final StyleCache styleCache;
76+
77+
/**
78+
* Filter bounding box
79+
*/
80+
private final BoundingBox filterBoundingBox;
81+
82+
/**
83+
* Max projection longitude
84+
*/
85+
private final double maxLongitude;
86+
87+
/**
88+
* Filter flag
89+
*/
90+
private final boolean filter;
91+
92+
/**
93+
* Contains various states for the map.
94+
*/
95+
private final MapModel model;
96+
97+
/**
98+
* Lock for concurrently updating the features bounding box
99+
*/
100+
private final Lock featuresBoundingBoxLock = new ReentrantLock();
101+
102+
/**
103+
* The application context.
104+
*/
105+
private final Context context;
106+
107+
/**
108+
* Constructor
109+
*
110+
* @param task The update task.
111+
* @param database The name of the geopackage the features belong too.
112+
* @param featureDao The feature data access object.
113+
* @param row The row to process.
114+
* @param count The current total count of features.
115+
* @param maxFeatures The maximum features to display on the map.
116+
* @param editable True if the feature should look editable on the map.
117+
* @param converter Converts the feature's shape to one to use on the map.
118+
* @param styleCache The style cache.
119+
* @param filterBoundingBox The bounding box to use for filtering.
120+
* @param maxLongitude The maximum longitude.
121+
* @param filter True if we should filter using the passed in bounding box.
122+
* @param model Contains various states for the map.
123+
* @param context The application context.
124+
*/
125+
public FeatureRowProcessor(MapFeaturesUpdateTask task, String database, FeatureDao featureDao,
126+
FeatureRow row, AtomicInteger count, int maxFeatures,
127+
boolean editable, GoogleMapShapeConverter converter, StyleCache styleCache,
128+
BoundingBox filterBoundingBox, double maxLongitude, boolean filter,
129+
MapModel model, Context context) {
130+
this.task = task;
131+
this.database = database;
132+
this.featureDao = featureDao;
133+
this.row = row;
134+
this.count = count;
135+
this.maxFeatures = maxFeatures;
136+
this.editable = editable;
137+
this.converter = converter;
138+
this.styleCache = styleCache;
139+
this.filterBoundingBox = filterBoundingBox;
140+
this.maxLongitude = maxLongitude;
141+
this.filter = filter;
142+
this.model = model;
143+
this.context = context;
144+
}
145+
146+
/**
147+
* {@inheritDoc}
148+
*/
149+
@Override
150+
public void run() {
151+
processFeatureRow(task, database, featureDao, converter, styleCache, row, count, maxFeatures,
152+
editable, filterBoundingBox, maxLongitude, filter);
153+
}
154+
155+
/**
156+
* Process the feature row
157+
*
158+
* @param task The map update task.
159+
* @param database The geopackage name the feature row belongs too.
160+
* @param featureDao The feature data access object.
161+
* @param converter Converts the feature shape to one that can be used on a google map.
162+
* @param styleCache The style cache.
163+
* @param row The row to process.
164+
* @param count The current feature count displayed on map.
165+
* @param maxFeatures The maximum features to display on the map.
166+
* @param editable True if the feature should look editable on the map.
167+
* @param boundingBox The bounding box to use to filter features.
168+
* @param maxLongitude The maximum longitude.
169+
* @param filter True if we should filer using the bounding box.
170+
*/
171+
private void processFeatureRow(MapFeaturesUpdateTask task, String database, FeatureDao featureDao,
172+
GoogleMapShapeConverter converter, StyleCache styleCache, FeatureRow row, AtomicInteger count,
173+
int maxFeatures, boolean editable, BoundingBox boundingBox, double maxLongitude,
174+
boolean filter) {
175+
176+
boolean exists;
177+
synchronized (model.getFeatureShapes()) {
178+
exists = model.getFeatureShapes().exists(row.getId(), database, featureDao.getTableName());
179+
}
180+
181+
if (!exists && task.NotCancelled()) {
182+
183+
try {
184+
GeoPackageGeometryData geometryData = row.getGeometry();
185+
if (geometryData != null && !geometryData.isEmpty()) {
186+
187+
final Geometry geometry = geometryData.getGeometry();
188+
189+
if (geometry != null) {
190+
191+
boolean passesFilter = true;
192+
193+
if (filter && boundingBox != null) {
194+
GeometryEnvelope envelope = geometryData.getEnvelope();
195+
if (envelope == null) {
196+
envelope = GeometryEnvelopeBuilder.buildEnvelope(geometry);
197+
}
198+
if (envelope != null) {
199+
if (geometry.getGeometryType() == GeometryType.POINT) {
200+
mil.nga.sf.Point point = (mil.nga.sf.Point) geometry;
201+
passesFilter = TileBoundingBoxUtils.isPointInBoundingBox(point, boundingBox, maxLongitude);
202+
} else {
203+
BoundingBox geometryBoundingBox = new BoundingBox(envelope);
204+
passesFilter = TileBoundingBoxUtils.overlap(boundingBox, geometryBoundingBox, maxLongitude) != null;
205+
}
206+
}
207+
}
208+
209+
if (passesFilter && count.getAndIncrement() < maxFeatures) {
210+
final long featureId = row.getId();
211+
final GoogleMapShape shape = converter.toShape(geometry);
212+
updateFeaturesBoundingBox(shape);
213+
ShapeHelper.getInstance().prepareShapeOptions(shape, styleCache, row, editable, true, context);
214+
task.addToMap(featureId, database, featureDao.getTableName(), shape);
215+
}
216+
}
217+
}
218+
} catch (Exception e) {
219+
new Handler(Looper.getMainLooper()).post(() -> {
220+
Toast toast = Toast.makeText(context, "Error loading geometry", Toast.LENGTH_SHORT);
221+
toast.show();
222+
});
223+
}
224+
}
225+
}
226+
227+
/**
228+
* Update the features bounding box with the shape
229+
*
230+
* @param shape The shape to use to expand the features bounding box.
231+
*/
232+
private void updateFeaturesBoundingBox(GoogleMapShape shape) {
233+
try {
234+
featuresBoundingBoxLock.lock();
235+
if (model.getFeaturesBoundingBox() != null) {
236+
shape.expandBoundingBox(model.getFeaturesBoundingBox());
237+
} else {
238+
model.setFeaturesBoundingBox(shape.boundingBox());
239+
}
240+
} finally {
241+
featuresBoundingBoxLock.unlock();
242+
}
243+
}
244+
}

0 commit comments

Comments
 (0)