Skip to content

Commit c419402

Browse files
authored
Added functionality to export ___location of nearby missing pictures to GPX file and KML file (commons-app#5645)
* Fixed Grey empty screen at Upload wizard caption step after denying files permission * Empty commit * Fixed loop issue * Created docs for earlier commits * Fixed javadoc * Fixed spaces * Added added basic features to OSM Maps * Added search ___location feature * Added filter to Open Street Maps * Fixed chipGroup in Open Street Maps * Removed mapBox code * Removed mapBox's code * Reformat code * Reformatted code * Removed rotation feature to map * Removed rotation files and Fixed Marker click problem * Ignored failing tests * Added voice input feature * Fixed test cases * Changed caption and description text * Replaced mapbox to osmdroid in upload activity * Fixed Unit Tests * Made selected marker to be fixed on map * Changed color of map marker * Fixes commons-app#5439 by capitalizing first letter of voice input * Removed mapbox code1 * Removed mapbox code2 * Fixed failing tests * Fixed failing due to merging * Added feature to save nearby places as GPX and KML * Fixed error caused by null
1 parent dae1f25 commit c419402

File tree

7 files changed

+443
-0
lines changed

7 files changed

+443
-0
lines changed

app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import fr.free.nrw.commons.explore.depictions.DepictsClient;
1212
import fr.free.nrw.commons.___location.LatLng;
1313
import fr.free.nrw.commons.nearby.Place;
14+
import fr.free.nrw.commons.nearby.model.PlaceBindings;
15+
import fr.free.nrw.commons.nearby.model.ItemsClass;
1416
import fr.free.nrw.commons.nearby.model.NearbyResponse;
1517
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
1618
import fr.free.nrw.commons.profile.achievements.FeaturedImages;
@@ -27,6 +29,8 @@
2729
import java.util.ArrayList;
2830
import java.util.List;
2931
import java.util.Locale;
32+
import java.util.regex.Matcher;
33+
import java.util.regex.Pattern;
3034
import javax.inject.Inject;
3135
import javax.inject.Singleton;
3236
import okhttp3.HttpUrl;
@@ -393,6 +397,196 @@ public List<Place> getNearbyPlaces(
393397
throw new Exception(response.message());
394398
}
395399

400+
/**
401+
* Make API Call to get Places
402+
*
403+
* @param leftLatLng Left lat long
404+
* @param rightLatLng Right lat long
405+
* @return
406+
* @throws Exception
407+
*/
408+
@Nullable
409+
public String getPlacesAsKML(final LatLng leftLatLng, final LatLng rightLatLng)
410+
throws Exception {
411+
String kmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
412+
"<!--Created by wikidata-missing-pictures-offline -->\n" +
413+
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
414+
" <Document>";
415+
416+
int increment = 1;
417+
double longitude = leftLatLng.getLongitude();
418+
419+
while (longitude <= rightLatLng.getLongitude()) {
420+
double NEXT_LONGITUDE =
421+
(increment + longitude) >= 0.0 && (increment + longitude) <= 1.0 ? 0.0
422+
: increment + longitude;
423+
424+
double latitude = leftLatLng.getLatitude();
425+
426+
while (latitude <= rightLatLng.getLatitude()) {
427+
double NEXT_LATITUDE =
428+
(increment + latitude) >= 0.0 && (increment + latitude) <= 1.0 ? 0.0
429+
: increment + latitude;
430+
List<PlaceBindings> placeBindings = runQuery(new LatLng(latitude, longitude, 0),
431+
new LatLng(NEXT_LATITUDE, NEXT_LONGITUDE, 0));
432+
if (placeBindings != null) {
433+
for (PlaceBindings item : placeBindings) {
434+
if (item.getItem() != null && item.getLabel() != null && item.getClas() != null) {
435+
String input = item.getLocation().getValue();
436+
Pattern pattern = Pattern.compile(
437+
"Point\\(([-+]?[0-9]*\\.?[0-9]+) ([-+]?[0-9]*\\.?[0-9]+)\\)");
438+
Matcher matcher = pattern.matcher(input);
439+
440+
if (matcher.find()) {
441+
String longStr = matcher.group(1);
442+
String latStr = matcher.group(2);
443+
String itemUrl = item.getItem().getValue();
444+
String itemName = item.getLabel().getValue().replace("&", "&amp;");
445+
String itemLatitude = latStr;
446+
String itemLongitude = longStr;
447+
String itemClass = item.getClas().getValue();
448+
449+
String formattedItemName =
450+
!itemClass.isEmpty() ? itemName + " (" + itemClass + ")"
451+
: itemName;
452+
453+
String kmlEntry = "\n <Placemark>\n" +
454+
" <name>" + formattedItemName + "</name>\n" +
455+
" <description>" + itemUrl + "</description>\n" +
456+
" <Point>\n" +
457+
" <coordinates>" + itemLongitude + ","
458+
+ itemLatitude
459+
+ "</coordinates>\n" +
460+
" </Point>\n" +
461+
" </Placemark>";
462+
kmlString = kmlString + kmlEntry;
463+
} else {
464+
Timber.e("No match found");
465+
}
466+
}
467+
}
468+
}
469+
latitude += increment;
470+
}
471+
longitude += increment;
472+
}
473+
kmlString = kmlString + "\n </Document>\n" +
474+
"</kml>\n";
475+
return kmlString;
476+
}
477+
478+
/**
479+
* Make API Call to get Places
480+
*
481+
* @param leftLatLng Left lat long
482+
* @param rightLatLng Right lat long
483+
* @return
484+
* @throws Exception
485+
*/
486+
@Nullable
487+
public String getPlacesAsGPX(final LatLng leftLatLng, final LatLng rightLatLng)
488+
throws Exception {
489+
String gpxString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
490+
"<gpx\n" +
491+
" version=\"1.0\"\n" +
492+
" creator=\"ExpertGPS 1.1 - https://www.topografix.com\"\n" +
493+
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
494+
" xmlns=\"http://www.topografix.com/GPX/1/0\"\n" +
495+
" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">"
496+
+ "\n<bounds minlat=\"$MIN_LATITUDE\" minlon=\"$MIN_LONGITUDE\" maxlat=\"$MAX_LATITUDE\" maxlon=\"$MAX_LONGITUDE\"/>";
497+
498+
int increment = 1;
499+
double longitude = leftLatLng.getLongitude();
500+
501+
while (longitude <= rightLatLng.getLongitude()) {
502+
double NEXT_LONGITUDE =
503+
(increment + longitude) >= 0.0 && (increment + longitude) <= 1.0 ? 0.0
504+
: increment + longitude;
505+
506+
double latitude = leftLatLng.getLatitude();
507+
508+
while (latitude <= rightLatLng.getLatitude()) {
509+
double NEXT_LATITUDE =
510+
(increment + latitude) >= 0.0 && (increment + latitude) <= 1.0 ? 0.0
511+
: increment + latitude;
512+
List<PlaceBindings> placeBindings = runQuery(new LatLng(latitude, longitude, 0),
513+
new LatLng(NEXT_LATITUDE, NEXT_LONGITUDE, 0));
514+
if (placeBindings != null) {
515+
for (PlaceBindings item : placeBindings) {
516+
if (item.getItem() != null && item.getLabel() != null && item.getClas() != null) {
517+
String input = item.getLocation().getValue();
518+
Pattern pattern = Pattern.compile(
519+
"Point\\(([-+]?[0-9]*\\.?[0-9]+) ([-+]?[0-9]*\\.?[0-9]+)\\)");
520+
Matcher matcher = pattern.matcher(input);
521+
522+
if (matcher.find()) {
523+
String longStr = matcher.group(1);
524+
String latStr = matcher.group(2);
525+
String itemUrl = item.getItem().getValue();
526+
String itemName = item.getLabel().getValue().replace("&", "&amp;");
527+
String itemLatitude = latStr;
528+
String itemLongitude = longStr;
529+
String itemClass = item.getClas().getValue();
530+
531+
String formattedItemName =
532+
!itemClass.isEmpty() ? itemName + " (" + itemClass + ")"
533+
: itemName;
534+
535+
String gpxEntry =
536+
"\n <wpt lat=\"" + itemLatitude + "\" lon=\"" + itemLongitude
537+
+ "\">\n" +
538+
" <name>" + itemName + "</name>\n" +
539+
" <url>" + itemUrl + "</url>\n" +
540+
" </wpt>";
541+
gpxString = gpxString + gpxEntry;
542+
543+
} else {
544+
Timber.e("No match found");
545+
}
546+
}
547+
}
548+
}
549+
latitude += increment;
550+
}
551+
longitude += increment;
552+
}
553+
gpxString = gpxString + "\n</gpx>";
554+
return gpxString;
555+
}
556+
557+
private List<PlaceBindings> runQuery(final LatLng currentLatLng, final LatLng nextLatLng)
558+
throws IOException {
559+
560+
final String wikidataQuery = FileUtils.readFromResource("/queries/places_query.rq");
561+
final String query = wikidataQuery
562+
.replace("${LONGITUDE}",
563+
String.format(Locale.ROOT, "%.2f", currentLatLng.getLongitude()))
564+
.replace("${LATITUDE}", String.format(Locale.ROOT, "%.4f", currentLatLng.getLatitude()))
565+
.replace("${NEXT_LONGITUDE}",
566+
String.format(Locale.ROOT, "%.4f", nextLatLng.getLongitude()))
567+
.replace("${NEXT_LATITUDE}",
568+
String.format(Locale.ROOT, "%.4f", nextLatLng.getLatitude()));
569+
570+
final HttpUrl.Builder urlBuilder = HttpUrl
571+
.parse(sparqlQueryUrl)
572+
.newBuilder()
573+
.addQueryParameter("query", query)
574+
.addQueryParameter("format", "json");
575+
576+
final Request request = new Request.Builder()
577+
.url(urlBuilder.build())
578+
.build();
579+
580+
final Response response = okHttpClient.newCall(request).execute();
581+
if (response.body() != null && response.isSuccessful()) {
582+
final String json = response.body().string();
583+
final ItemsClass item = gson.fromJson(json, ItemsClass.class);
584+
return item.getResults().getBindings();
585+
} else {
586+
return null;
587+
}
588+
}
589+
396590
/**
397591
* Make API Call to get Nearby Places Implementation does not expects a custom query
398592
*

app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng currentLatLng,
118118
return nearbyPlacesInfo;
119119
}
120120

121+
public String getPlacesAsKML(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
122+
return nearbyPlaces.getPlacesAsKML(leftLatLng, rightLatLng);
123+
}
124+
125+
public String getPlacesAsGPX(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
126+
return nearbyPlaces.getPlacesAsGPX(leftLatLng, rightLatLng);
127+
}
128+
121129
/**
122130
* Prepares Place list to make their distance information update later.
123131
*

app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,27 @@ public List<Place> getFromWikidataQuery(
119119
.getNearbyPlaces(screenTopRight, screenBottomLeft, lang, shouldQueryForMonuments,
120120
customQuery);
121121
}
122+
123+
/**
124+
* Runs the Wikidata query to retrieve the KML String
125+
*
126+
* @param leftLatLng coordinates of Left Most position
127+
* @param rightLatLng coordinates of Right Most position
128+
* @throws IOException if query fails
129+
*/
130+
public String getPlacesAsKML(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
131+
return okHttpJsonApiClient.getPlacesAsKML(leftLatLng, rightLatLng);
132+
}
133+
134+
/**
135+
* Runs the Wikidata query to retrieve the GPX String
136+
*
137+
* @param leftLatLng coordinates of Left Most position
138+
* @param rightLatLng coordinates of Right Most position
139+
* @throws IOException if query fails
140+
*/
141+
public String getPlacesAsGPX(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
142+
return okHttpJsonApiClient.getPlacesAsGPX(leftLatLng, rightLatLng);
143+
}
144+
122145
}

0 commit comments

Comments
 (0)