Added search tests

This commit is contained in:
crimean 2018-12-03 00:01:34 +03:00
parent d4d31d0877
commit 113c5fd8e9
19 changed files with 13175 additions and 119 deletions

View file

@ -40,9 +40,15 @@ task collectRegionsInfoResources(type: Copy) {
}
task collectTestResources(type: Copy) {
from "../../resources/test-resources"
into "src/test/resources/"
include "*"
from("../../resources/test-resources") {
include "*"
}
from("../../resources/poi") {
include "poi_types.xml"
include "/phrases/en/*"
//include "/phrases/ru/*"
}
}

View file

@ -1,37 +1,9 @@
package net.osmand.binary;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.set.hash.TIntHashSet;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.WireFormat;
import net.osmand.Collator;
import net.osmand.CollatorStringMatcher;
@ -72,9 +44,37 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.WireFormat;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.set.hash.TIntHashSet;
public class BinaryMapIndexReader {
@ -130,7 +130,7 @@ public class BinaryMapIndexReader {
init();
}
/*private */BinaryMapIndexReader(final RandomAccessFile raf, File file, boolean init) throws IOException {
public BinaryMapIndexReader(final RandomAccessFile raf, File file, boolean init) throws IOException {
this.raf = raf;
this.file = file;
codedIS = CodedInputStream.newInstance(raf);

View file

@ -1,16 +1,19 @@
package net.osmand.data;
import net.osmand.Location;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.edit.Node;
import net.osmand.util.Algorithms;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
@ -317,4 +320,49 @@ public class Amenity extends MapObject {
public boolean isClosed() {
return OSM_DELETE_VALUE.equals(getAdditionalInfo(OSM_DELETE_TAG));
}
public JSONObject toJSON() {
JSONObject json = super.toJSON();
json.put("subType", subType);
json.put("type", type.getKeyName());
json.put("openingHours", openingHours);
if (additionalInfo != null && additionalInfo.size() > 0) {
JSONObject additionalInfoObj = new JSONObject();
for (Entry<String, String> e : additionalInfo.entrySet()) {
additionalInfoObj.put(e.getKey(), e.getValue());
}
json.put("additionalInfo", additionalInfoObj);
}
return json;
}
public static Amenity parseJSON(JSONObject json) {
Amenity a = new Amenity();
MapObject.parseJSON(json, a);
if (json.has("subType")) {
a.subType = json.getString("subType");
}
if (json.has("type")) {
String categoryName = json.getString("type");
a.setType(MapPoiTypes.getDefault().getPoiCategoryByName(categoryName));
} else {
a.setType(MapPoiTypes.getDefault().getOtherPoiCategory());
}
if (json.has("openingHours")) {
a.openingHours = json.getString("openingHours");
}
if (json.has("additionalInfo")) {
JSONObject namesObj = json.getJSONObject("additionalInfo");
a.additionalInfo = new HashMap<>();
Iterator<String> iterator = namesObj.keys();
while (iterator.hasNext()) {
String key = iterator.next();
String value = namesObj.getString(key);
a.additionalInfo.put(key, value);
}
}
return a;
}
}

View file

@ -1,12 +1,15 @@
package net.osmand.data;
import net.osmand.util.Algorithms;
import org.json.JSONObject;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import net.osmand.util.Algorithms;
public class Building extends MapObject {
private String postcode;
@ -216,4 +219,43 @@ public class Building extends MapObject {
return "";
}
public JSONObject toJSON() {
JSONObject json = super.toJSON();
json.put("postcode", postcode);
if (latLon2 != null) {
json.put("lat2", String.format(Locale.US, "%.5f", latLon2.getLatitude()));
json.put("lon2", String.format(Locale.US, "%.5f", latLon2.getLongitude()));
}
if (interpolationType != null) {
json.put("interpolationType", interpolationType.name());
}
if (interpolationInterval != 0) {
json.put("interpolationInterval", interpolationInterval);
}
json.put("name2", name2);
return json;
}
public static Building parseJSON(JSONObject json) throws IllegalArgumentException {
Building b = new Building();
MapObject.parseJSON(json, b);
if (json.has("postcode")) {
b.postcode = json.getString("postcode");
}
if (json.has("lat2") && json.has("lon2")) {
b.latLon2 = new LatLon(json.getDouble("lat2"), json.getDouble("lon2"));
}
if (json.has("interpolationType")) {
b.interpolationType = BuildingInterpolation.valueOf(json.getString("interpolationType"));
}
if (json.has("interpolationInterval")) {
b.interpolationInterval = json.getInt("interpolationInterval");
}
if (json.has("name2")) {
b.name2 = json.getString("name2");
}
return b;
}
}

View file

@ -1,5 +1,8 @@
package net.osmand.data;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@ -55,7 +58,6 @@ public class City extends MapObject {
return new City(postcode, POSTCODE_INTERNAL_ID--);
}
public City(CityType type) {
if (type == null) {
throw new NullPointerException();
@ -156,4 +158,43 @@ public class City extends MapObject {
return m;
}
public JSONObject toJSON() {
JSONObject json = super.toJSON();
json.put("type", type.name());
json.put("postcode", postcode);
JSONArray listOfStreetsArr = new JSONArray();
for (Street s : listOfStreets) {
listOfStreetsArr.put(s.toJSON());
}
json.put("listOfStreets", listOfStreetsArr);
return json;
}
public static City parseJSON(JSONObject json) throws IllegalArgumentException {
CityType type;
if (json.has("type")) {
type = CityType.valueOf(json.getString("type"));
} else {
throw new IllegalArgumentException();
}
City c = new City(type);
MapObject.parseJSON(json, c);
if (json.has("postcode")) {
c.postcode = json.getString("postcode");
}
if (json.has("listOfStreets")) {
JSONArray streetsArr = json.getJSONArray("listOfStreets");
c.listOfStreets = new ArrayList<>();
for (int i = 0; i < streetsArr.length(); i++) {
JSONObject streetObj = streetsArr.getJSONObject(i);
Street street = Street.parseJSON(c, streetObj);
if (street != null) {
c.listOfStreets.add(street);
}
}
}
return c;
}
}

View file

@ -1,19 +1,23 @@
package net.osmand.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.osmand.Collator;
import net.osmand.OsmAndCollator;
import net.osmand.util.Algorithms;
import net.sf.junidecode.Junidecode;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
public abstract class MapObject implements Comparable<MapObject> {
@ -289,4 +293,48 @@ public abstract class MapObject implements Comparable<MapObject> {
return referenceFile;
}
public JSONObject toJSON() {
JSONObject json = new JSONObject();
json.put("name", name);
json.put("enName", enName);
if (names != null && names.size() > 0) {
JSONObject namesObj = new JSONObject();
for (Entry<String, String> e : names.entrySet()) {
namesObj.put(e.getKey(), e.getValue());
}
json.put("names", namesObj);
}
if (location != null) {
json.put("lat", String.format(Locale.US, "%.5f", location.getLatitude()));
json.put("lon", String.format(Locale.US, "%.5f", location.getLongitude()));
}
json.put("id", id);
return json;
}
protected static void parseJSON(JSONObject json, MapObject o) {
if (json.has("name")) {
o.name = json.getString("name");
}
if (json.has("enName")) {
o.enName = json.getString("enName");
}
if (json.has("names")) {
JSONObject namesObj = json.getJSONObject("names");
o.names = new HashMap<>();
Iterator<String> iterator = namesObj.keys();
while (iterator.hasNext()) {
String key = iterator.next();
String value = namesObj.getString(key);
o.names.put(key, value);
}
}
if (json.has("lat") && json.has("lon")) {
o.location = new LatLon(json.getDouble("lat"), json.getDouble("lon"));
}
if (json.has("id")) {
o.id = json.getLong("id");
}
}
}

View file

@ -1,12 +1,15 @@
package net.osmand.data;
import net.osmand.util.Algorithms;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.osmand.util.Algorithms;
public class Street extends MapObject {
@ -86,4 +89,53 @@ public class Street extends MapObject {
}
return nm;
}
public JSONObject toJSON() {
JSONObject json = super.toJSON();
if (buildings.size() > 0) {
JSONArray buildingsArr = new JSONArray();
for (Building b : buildings) {
buildingsArr.put(b.toJSON());
}
json.put("buildings", buildingsArr);
}
if (intersectedStreets != null) {
JSONArray intersectedStreetsArr = new JSONArray();
for (Street s : intersectedStreets) {
intersectedStreetsArr.put(s.toJSON());
}
json.put("intersectedStreets", intersectedStreetsArr);
}
return json;
}
public static Street parseJSON(City city, JSONObject json) throws IllegalArgumentException {
Street s = new Street(city);
MapObject.parseJSON(json, s);
if (json.has("buildings")) {
JSONArray buildingsArr = json.getJSONArray("buildings");
s.buildings = new ArrayList<>();
for (int i = 0; i < buildingsArr.length(); i++) {
JSONObject buildingObj = buildingsArr.getJSONObject(i);
Building building = Building.parseJSON(buildingObj);
if (building != null) {
s.buildings.add(building);
}
}
}
if (json.has("intersectedStreets")) {
JSONArray streetsArr = json.getJSONArray("intersectedStreets");
s.intersectedStreets = new ArrayList<>();
for (int i = 0; i < streetsArr.length(); i++) {
JSONObject streetObj = streetsArr.getJSONObject(i);
Street street = parseJSON(city, streetObj);
if (street != null) {
s.intersectedStreets.add(street);
}
}
}
return s;
}
}

View file

@ -6,7 +6,9 @@ import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.Amenity;
import net.osmand.data.City;
import net.osmand.data.LatLon;
import net.osmand.data.MapObject;
import net.osmand.data.Street;
import net.osmand.osm.MapPoiTypes;
import net.osmand.search.core.CustomSearchPoiFilter;
@ -25,14 +27,18 @@ import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -480,7 +486,7 @@ public class SearchUICore {
}
return;
}
searchInBackground(phrase, rm);
searchInternal(phrase, rm);
if (!rm.isCancelled()) {
SearchResultCollection collection = new SearchResultCollection(
phrase);
@ -492,6 +498,9 @@ public class SearchUICore {
LOG.info("Finishing search <" + phrase + "> Results=" + rm.getRequestResults().size());
}
currentSearchResult = collection;
if (phrase.getSettings().isExportObjects()) {
rm.createTestJSON(collection);
}
rm.searchFinished(phrase);
if (onResultsComplete != null) {
onResultsComplete.run();
@ -548,7 +557,7 @@ public class SearchUICore {
return radius;
}
private void searchInBackground(final SearchPhrase phrase, SearchResultMatcher matcher) {
void searchInternal(final SearchPhrase phrase, SearchResultMatcher matcher) {
preparePhrase(phrase);
ArrayList<SearchCoreAPI> lst = new ArrayList<>(apis);
Collections.sort(lst, new Comparator<SearchCoreAPI>() {
@ -600,10 +609,7 @@ public class SearchUICore {
}
}
public static class SearchResultMatcher implements ResultMatcher<SearchResult>{
public static class SearchResultMatcher implements ResultMatcher<SearchResult>{
private final List<SearchResult> requestResults = new ArrayList<>();
private final ResultMatcher<SearchResult> matcher;
private final int request;
@ -612,7 +618,8 @@ public class SearchUICore {
private final AtomicInteger requestNumber;
int count = 0;
private SearchPhrase phrase;
private List<MapObject> exportedObjects;
private List<City> exportedCities;
public SearchResultMatcher(ResultMatcher<SearchResult> matcher, SearchPhrase phrase, int request,
AtomicInteger requestNumber, int totalLimit) {
@ -714,6 +721,111 @@ public class SearchUICore {
boolean cancelled = request != requestNumber.get();
return cancelled || (matcher != null && matcher.isCancelled());
}
public List<MapObject> getExportedObjects() {
return exportedObjects;
}
public List<City> getExportedCities() {
return exportedCities;
}
public void exportObject(MapObject object) {
if (exportedObjects == null) {
exportedObjects = new ArrayList<>();
}
exportedObjects.add(object);
}
public void exportCity(City city) {
if (exportedCities == null) {
exportedCities = new ArrayList<>();
}
exportedCities.add(city);
}
public JSONObject createTestJSON(SearchResultCollection searchResult) {
JSONObject json = new JSONObject();
Set<Amenity> amenities = new HashSet<>();
Set<City> cities;
Set<City> matchedCities = new HashSet<>();
Set<City> streetCities = new HashSet<>();
if (exportedCities != null) {
cities = new HashSet<>(exportedCities);
} else {
cities = new HashSet<>();
}
Set<Street> streets = new HashSet<>();
for (MapObject obj : exportedObjects) {
if (obj instanceof Amenity) {
amenities.add((Amenity) obj);
} else if (obj instanceof Street) {
Street street = (Street) obj;
streets.add(street);
if (street.getCity() != null) {
final City city = street.getCity();
cities.add(city);
streetCities.add(city);
}
} else if (obj instanceof City) {
City city = (City) obj;
cities.add(city);
matchedCities.add(city);
}
}
for (City city : cities) {
List<Street> cityStreets = city.getStreets();
for (Street street : streets) {
if (city.equals(street.getCity()) && !cityStreets.contains(street)) {
cityStreets.add(street);
}
}
}
json.put("settings", phrase.getSettings().toJSON());
json.put("phrase", phrase.getRawUnknownSearchPhrase());
if (searchResult.searchResults != null && searchResult.searchResults.size() > 0) {
JSONArray resultsArr = new JSONArray();
for (SearchResult r : searchResult.searchResults) {
resultsArr.put(r.toString());
}
json.put("results", resultsArr);
}
if (amenities.size() > 0) {
JSONArray amenitiesArr = new JSONArray();
for (Amenity amenity : amenities) {
amenitiesArr.put(amenity.toJSON());
}
json.put("amenities", amenitiesArr);
}
if (exportedCities != null && exportedCities.size() > 0) {
JSONArray citiesArr = new JSONArray();
for (City city : exportedCities) {
citiesArr.put(city.toJSON());
}
json.put("cities", citiesArr);
}
if (cities.size() > 0) {
JSONArray citiesArr = new JSONArray();
for (City city : cities) {
final JSONObject cityObj = city.toJSON();
if (exportedCities.contains(city)) {
cityObj.put("init", 1);
}
if (matchedCities.contains(city)) {
cityObj.put("matchCity", 1);
}
if (streetCities.contains(city)) {
cityObj.put("matchStreet", 1);
}
citiesArr.put(cityObj);
}
json.put("cities", citiesArr);
}
return json;
}
}
public static class SearchResultComparator implements Comparator<SearchResult> {

View file

@ -226,8 +226,6 @@ public class SearchCoreFactory {
return retName;
}
public static class SearchAddressByNameAPI extends SearchBaseAPI {
private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 100 * 1000;
@ -322,6 +320,9 @@ public class SearchCoreFactory {
resArray = townCitiesQR.queryInBox(bbox, resArray);
int limit = 0;
for (City c : resArray) {
if (phrase.getSettings().isExportObjects()) {
resultMatcher.exportCity(c);
}
SearchResult res = new SearchResult(phrase);
res.object = c;
res.file = (BinaryMapIndexReader) c.getReferenceFile();
@ -347,7 +348,6 @@ public class SearchCoreFactory {
}
}
private void searchByName(final SearchPhrase phrase, final SearchResultMatcher resultMatcher)
throws IOException {
if (phrase.getRadiusLevel() > 1 || phrase.getUnknownSearchWordLength() > 3 || phrase.getUnknownSearchWords().size() > 0) {
@ -362,11 +362,13 @@ public class SearchCoreFactory {
SEARCH_ADDRESS_BY_NAME_PRIORITY : SEARCH_ADDRESS_BY_NAME_PRIORITY_RADIUS2;
final BinaryMapIndexReader[] currentFile = new BinaryMapIndexReader[1];
ResultMatcher<MapObject> rm = new ResultMatcher<MapObject>() {
int limit = 0;
@Override
public boolean publish(MapObject object) {
if (phrase.getSettings().isExportObjects()) {
resultMatcher.exportObject(object);
}
if (isCancelled()) {
return false;
}
@ -408,7 +410,6 @@ public class SearchCoreFactory {
|| !phrase.isSearchTypeAllowed(ObjectType.CITY)) {
return false;
}
sr.objectType = ObjectType.CITY;
sr.priorityDistance = 0.1;
} else if (((City)object).isPostcode()) {
@ -418,7 +419,7 @@ public class SearchCoreFactory {
}
sr.objectType = ObjectType.POSTCODE;
sr.priorityDistance = 0;
} else {
} else {
if ((locSpecified && !villagesBbox.contains(x, y, x, y))
|| !phrase.isSearchTypeAllowed(ObjectType.VILLAGE)) {
return false;
@ -453,8 +454,6 @@ public class SearchCoreFactory {
return false;
}
@Override
public boolean isCancelled() {
return limit > LIMIT * phrase.getRadiusLevel() ||
@ -497,8 +496,6 @@ public class SearchCoreFactory {
}
}
public static class SearchAmenityByNameAPI extends SearchBaseAPI {
private static final int LIMIT = 10000;
private static final int BBOX_RADIUS = 500 * 1000;
@ -543,6 +540,9 @@ public class SearchCoreFactory {
int limit = 0;
@Override
public boolean publish(Amenity object) {
if (phrase.getSettings().isExportObjects()) {
resultMatcher.exportObject(object);
}
if (limit ++ > LIMIT) {
return false;
}
@ -630,8 +630,6 @@ public class SearchCoreFactory {
}
}
public static class SearchAmenityTypesAPI extends SearchBaseAPI {
private Map<String, PoiType> translatedNames = new LinkedHashMap<>();
@ -762,8 +760,6 @@ public class SearchCoreFactory {
}
}
public static class SearchAmenityByTypeAPI extends SearchBaseAPI {
private static final int BBOX_RADIUS = 10000;
private SearchAmenityTypesAPI searchAmenityTypesAPI;
@ -884,6 +880,9 @@ public class SearchCoreFactory {
@Override
public boolean publish(Amenity object) {
if (phrase.getSettings().isExportObjects()) {
resultMatcher.exportObject(object);
}
SearchResult res = new SearchResult(phrase);
String poiID = object.getType().getKeyName() + "_" + object.getId();
if(!searchedPois.add(poiID)) {
@ -977,8 +976,6 @@ public class SearchCoreFactory {
}
}
public static class SearchStreetByCityAPI extends SearchBaseAPI {
private static final int DEFAULT_ADDRESS_BBOX_RADIUS = 100 * 1000;
@ -1076,8 +1073,6 @@ public class SearchCoreFactory {
p.isLastWord(ObjectType.VILLAGE);
}
public static class SearchBuildingAndIntersectionsByStreetAPI extends SearchBaseAPI {
Street cacheBuilding;
@ -1219,8 +1214,6 @@ public class SearchCoreFactory {
}
}
public static class SearchLocationAndUrlAPI extends SearchBaseAPI {
public SearchLocationAndUrlAPI() {
@ -1345,6 +1338,4 @@ public class SearchCoreFactory {
return SEARCH_LOCATION_PRIORITY;
}
}
}

View file

@ -1,11 +1,19 @@
package net.osmand.search.core;
import java.util.Collection;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.Amenity;
import net.osmand.data.City;
import net.osmand.data.LatLon;
import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.PoiCategory;
import net.osmand.osm.PoiFilter;
import net.osmand.osm.PoiType;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.util.Collection;
public class SearchResult {
// search phrase that makes search result valid
public SearchPhrase requiredSearchPhrase;
@ -75,10 +83,63 @@ public class SearchResult {
public Object relatedObject;
public double distRelatedObjectName;
@Override
public String toString() {
StringBuilder b = new StringBuilder();
if (!Algorithms.isEmpty(localeName)) {
b.append(localeName);
}
if (!Algorithms.isEmpty(localeRelatedObjectName)) {
if (b.length() > 0) {
b.append(", ");
}
b.append(localeRelatedObjectName);
if (relatedObject instanceof Street) {
Street street = (Street) relatedObject;
City city = street.getCity();
if (city != null) {
b.append(", ").append(city.getName(requiredSearchPhrase.getSettings().getLang(),
requiredSearchPhrase.getSettings().isTransliterate()));
}
}
} else if (object instanceof AbstractPoiType) {
if (b.length() > 0) {
b.append(" ");
}
AbstractPoiType poiType = (AbstractPoiType) object;
if (poiType instanceof PoiCategory) {
b.append("(Category)");
} else if (poiType instanceof PoiFilter) {
b.append("(Filter)");
} else if (poiType instanceof PoiType) {
PoiType p = (PoiType) poiType;
final AbstractPoiType parentType = p.getParentType();
if (parentType != null) {
final String translation = parentType.getTranslation();
b.append("(").append(translation);
if (parentType instanceof PoiCategory) {
b.append(" / Category)");
} else if (parentType instanceof PoiFilter) {
b.append(" / Filter)");
} else if (parentType instanceof PoiType) {
PoiType pp = (PoiType) poiType;
PoiFilter filter = pp.getFilter();
PoiCategory category = pp.getCategory();
if (filter != null && !filter.getTranslation().equals(translation)) {
b.append(" / ").append(filter.getTranslation()).append(")");
} else if (category != null && !category.getTranslation().equals(translation)) {
b.append(" / ").append(category.getTranslation()).append(")");
} else {
b.append(")");
}
}
} else if (p.getFilter() != null) {
b.append("(").append(p.getFilter().getTranslation()).append(")");
} else if (p.getCategory() != null) {
b.append("(").append(p.getCategory().getTranslation()).append(")");
}
}
}
return b.toString();
}
}

View file

@ -2,10 +2,18 @@ package net.osmand.search.core;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.LatLon;
import net.osmand.data.MapObject;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
// immutable object
public class SearchSettings {
@ -19,21 +27,24 @@ public class SearchSettings {
private ObjectType[] searchTypes;
private boolean emptyQueryAllowed;
private boolean sortByName;
private boolean exportObjects = true;
public SearchSettings(SearchSettings s) {
if(s != null) {
this.radiusLevel = s.radiusLevel;
this.lang = s.lang;
this.transliterateIfMissing = s.transliterateIfMissing;
this.totalLimit = s.totalLimit;
this.offlineIndexes = s.offlineIndexes;
this.originalLocation = s.originalLocation;
this.searchTypes = s.searchTypes;
this.emptyQueryAllowed = s.emptyQueryAllowed;
this.sortByName = s.sortByName;
this.exportObjects = s.exportObjects;
}
}
public SearchSettings(List<BinaryMapIndexReader> offlineIndexes) {
public SearchSettings(List<? extends BinaryMapIndexReader> offlineIndexes) {
this.offlineIndexes = Collections.unmodifiableList(offlineIndexes);
}
@ -42,7 +53,7 @@ public class SearchSettings {
return offlineIndexes;
}
public void setOfflineIndexes(List<BinaryMapIndexReader> offlineIndexes) {
public void setOfflineIndexes(List<? extends BinaryMapIndexReader> offlineIndexes) {
this.offlineIndexes = Collections.unmodifiableList(offlineIndexes);
}
@ -131,6 +142,16 @@ public class SearchSettings {
return s;
}
public boolean isExportObjects() {
return exportObjects;
}
public SearchSettings setExportObjects(boolean exportObjects) {
SearchSettings s = new SearchSettings(this);
this.exportObjects = exportObjects;
return s;
}
public boolean hasCustomSearchType(ObjectType type) {
if (searchTypes != null) {
for (ObjectType t : searchTypes) {
@ -141,4 +162,52 @@ public class SearchSettings {
}
return false;
}
public JSONObject toJSON() {
JSONObject json = new JSONObject();
if (originalLocation != null) {
json.put("lat", String.format(Locale.US, "%.5f", originalLocation.getLatitude()));
json.put("lon", String.format(Locale.US, "%.5f", originalLocation.getLongitude()));
}
json.put("radiusLevel", radiusLevel);
json.put("totalLimit", totalLimit);
json.put("lang", lang);
json.put("transliterateIfMissing", transliterateIfMissing);
json.put("emptyQueryAllowed", emptyQueryAllowed);
json.put("sortByName", sortByName);
if (searchTypes != null && searchTypes.length > 0) {
JSONArray searchTypesArr = new JSONArray();
for (ObjectType type : searchTypes) {
searchTypesArr.put(type.name());
}
json.put("searchTypes", searchTypes);
}
return json;
}
public static SearchSettings parseJSON(JSONObject json) {
SearchSettings s = new SearchSettings(new ArrayList<BinaryMapIndexReader>());
if (json.has("lat") && json.has("lon")) {
s.originalLocation = new LatLon(json.getDouble("lat"), json.getDouble("lon"));
}
s.radiusLevel = json.optInt("radiusLevel", 1);
s.totalLimit = json.optInt("totalLimit", -1);
s.transliterateIfMissing = json.optBoolean("transliterateIfMissing", false);
s.emptyQueryAllowed = json.optBoolean("emptyQueryAllowed", false);
s.sortByName = json.optBoolean("sortByName", false);
if (json.has("lang")) {
s.lang = json.getString("lang");
}
if (json.has("searchTypes")) {
JSONArray searchTypesArr = json.getJSONArray("searchTypes");
ObjectType[] searchTypes = new ObjectType[searchTypesArr.length()];
for (int i = 0; i < searchTypesArr.length(); i++) {
String name = searchTypesArr.getString(i);
searchTypes[i] = ObjectType.valueOf(name);
}
s.searchTypes = searchTypes;
}
return s;
}
}

View file

@ -2,8 +2,12 @@ package net.osmand.util;
import net.osmand.IProgress;
import net.osmand.PlatformUtil;
import net.osmand.router.GeneralRouter;
import net.osmand.router.RoutingConfiguration;
import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
@ -27,6 +31,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import java.util.zip.GZIPInputStream;
@ -691,4 +696,54 @@ public class Algorithms {
return str1.compareTo(str2);
}
public static String getFileAsString(File file) {
try {
FileInputStream fin = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(fin, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(line);
}
reader.close();
fin.close();
return sb.toString();
} catch (Exception e) {
return null;
}
}
public static Map<String, String> parseStringsXml(File file) throws IOException, XmlPullParserException {
InputStream is = new FileInputStream(file);
XmlPullParser parser = PlatformUtil.newXMLPullParser();
Map<String, String> map = new HashMap<>();
parser.setInput(is, "UTF-8");
int tok;
String key = null;
StringBuilder text = null;
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (tok == XmlPullParser.START_TAG) {
text = new StringBuilder();
String name = parser.getName();
if ("string".equals(name)) {
key = parser.getAttributeValue("", "name");
}
} else if (tok == XmlPullParser.TEXT) {
if (text != null) {
text.append(parser.getText());
}
} else if (tok == XmlPullParser.END_TAG) {
if (key != null) {
map.put(key, text.toString());
}
key = null;
text = null;
}
}
is.close();
return map;
}
}

View file

@ -1,22 +1,133 @@
package net.osmand.search;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.osmand.OsmAndCollator;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.Amenity;
import net.osmand.data.Building;
import net.osmand.data.City;
import net.osmand.data.LatLon;
import net.osmand.data.MapObject;
import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.search.SearchUICore.SearchResultCollection;
import net.osmand.search.SearchUICore.SearchResultMatcher;
import net.osmand.search.core.SearchPhrase;
import net.osmand.search.core.SearchResult;
import net.osmand.search.core.SearchSettings;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class SearchCoreUITest {
private static final String SEARCH_RESOURCES_PATH = "src/test/resources/search/";
private static Map<String, String> enPhrases = new HashMap<>();
private static Map<String, String> phrases = new HashMap<>();
static {
MapPoiTypes.setDefault(new MapPoiTypes("src/test/resources/poi_types.xml"));
MapPoiTypes poiTypes = MapPoiTypes.getDefault();
try {
enPhrases = Algorithms.parseStringsXml(new File("src/test/resources/phrases/en/phrases.xml"));
//phrases = Algorithms.parseStringsXml(new File("src/test/resources/phrases/ru/phrases.xml"));
phrases = enPhrases;
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
poiTypes.setPoiTranslator(new MapPoiTypes.PoiTranslator() {
@Override
public String getTranslation(AbstractPoiType type) {
AbstractPoiType baseLangType = type.getBaseLangType();
if (baseLangType != null) {
return getTranslation(baseLangType) + " (" + type.getLang().toLowerCase() + ")";
}
return getTranslation(type.getIconKeyName());
}
@Override
public String getTranslation(String keyName) {
String val = phrases.get("poi_" + keyName);
if (val != null) {
int ind = val.indexOf(';');
if (ind > 0) {
return val.substring(0, ind);
}
}
return val;
}
@Override
public String getSynonyms(AbstractPoiType type) {
AbstractPoiType baseLangType = type.getBaseLangType();
if (baseLangType != null) {
return getSynonyms(baseLangType);
}
return getSynonyms(type.getIconKeyName());
}
@Override
public String getSynonyms(String keyName) {
String val = phrases.get("poi_" + keyName);
if (val != null) {
int ind = val.indexOf(';');
if (ind > 0) {
return val.substring(ind + 1);
}
return "";
}
return null;
}
@Override
public String getEnTranslation(AbstractPoiType type) {
AbstractPoiType baseLangType = type.getBaseLangType();
if (baseLangType != null) {
return getEnTranslation(baseLangType) + " (" + type.getLang().toLowerCase() + ")";
}
return getEnTranslation(type.getIconKeyName());
}
@Override
public String getEnTranslation(String keyName) {
if (enPhrases.isEmpty()) {
return Algorithms.capitalizeFirstLetter(keyName.replace('_', ' '));
}
String val = enPhrases.get("poi_" + keyName);
if (val != null) {
int ind = val.indexOf(';');
if (ind > 0) {
return val.substring(0, ind);
}
}
return val;
}
});
}
@Test
public void testDuplicates() throws IOException {
SearchSettings ss = new SearchSettings((SearchSettings)null);
@ -100,4 +211,220 @@ public class SearchCoreUITest {
rs.add(res);
return res;
}
@Test
public void testSearchJsons() throws IOException {
final File[] files = new File(SEARCH_RESOURCES_PATH).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
return filename.endsWith(".json");
}
});
if (files != null) {
for (File f : files) {
testSearchImpl(f);
}
}
}
private void testSearchImpl(File jsonFile) throws IOException, JSONException {
String sourceJsonText = Algorithms.getFileAsString(jsonFile);
Assert.assertNotNull(sourceJsonText);
Assert.assertTrue(sourceJsonText.length() > 0);
BinaryMapIndexReaderTest reader = new BinaryMapIndexReaderTest();
JSONObject sourceJson = new JSONObject(sourceJsonText);
String phraseText = sourceJson.getString("phrase");
JSONObject settingsJson = sourceJson.getJSONObject("settings");
if (sourceJson.has("amenities")) {
JSONArray amenitiesArr = sourceJson.getJSONArray("amenities");
List<Amenity> amenities = new ArrayList<>();
for (int i = 0; i < amenitiesArr.length(); i++) {
JSONObject amenityObj = amenitiesArr.getJSONObject(i);
amenities.add(Amenity.parseJSON(amenityObj));
}
reader.amenities = amenities;
}
if (sourceJson.has("cities")) {
JSONArray citiesArr = sourceJson.getJSONArray("cities");
List<City> cities = new ArrayList<>();
List<City> initCities = new ArrayList<>();
List<City> matchedCities = new ArrayList<>();
List<City> streetCities = new ArrayList<>();
for (int i = 0; i < citiesArr.length(); i++) {
JSONObject cityObj = citiesArr.getJSONObject(i);
final City city = City.parseJSON(cityObj);
cities.add(city);
if (cityObj.has("init")) {
initCities.add(city);
}
if (cityObj.has("matchCity")) {
matchedCities.add(city);
}
if (cityObj.has("matchStreet")) {
streetCities.add(city);
}
}
reader.cities = cities;
reader.initCities = initCities;
reader.matchedCities = matchedCities;
reader.streetCities = streetCities;
}
List<String> results = new ArrayList<>();
if (sourceJson.has("results")) {
JSONArray resultsArr = sourceJson.getJSONArray("results");
for (int i = 0; i < resultsArr.length(); i++) {
results.add(resultsArr.getString(i));
}
}
SearchSettings s = SearchSettings.parseJSON(settingsJson);
s.setOfflineIndexes(Collections.singletonList(reader));
SearchPhrase phrase = new SearchPhrase(s, OsmAndCollator.primaryCollator());
phrase = phrase.generateNewPhrase(phraseText, s);
final SearchUICore core = new SearchUICore(MapPoiTypes.getDefault(), "en", false);
core.init();
ResultMatcher<SearchResult> rm = new ResultMatcher<SearchResult>() {
@Override
public boolean publish(SearchResult object) {
return true;
}
@Override
public boolean isCancelled() {
return false;
}
};
SearchResultMatcher matcher = new SearchResultMatcher(rm, phrase, 1, new AtomicInteger(1), -1);
core.searchInternal(phrase, matcher);
SearchResultCollection collection = new SearchResultCollection(phrase);
collection.addSearchResults(matcher.getRequestResults(), true, true);
List<SearchResult> searchResults = collection.getCurrentSearchResults();
int i = 0;
for (SearchResult result : searchResults) {
String expected = results.get(i++);
String present = result.toString();
//System.out.println(present);
Assert.assertEquals(expected, present);
if (i >= results.size()) {
break;
}
}
}
private static class BinaryMapIndexReaderTest extends BinaryMapIndexReader {
List<Amenity> amenities = Collections.emptyList();
List<City> cities = Collections.emptyList();
List<City> initCities = Collections.emptyList();
List<City> matchedCities = Collections.emptyList();
List<City> streetCities = Collections.emptyList();
BinaryMapIndexReaderTest() throws IOException {
super(null, null, false);
}
@Override
public List<Amenity> searchPoiByName(SearchRequest<Amenity> req) throws IOException {
for (Amenity amenity : amenities) {
req.publish(amenity);
}
return req.getSearchResults();
}
@Override
public List<Amenity> searchPoi(SearchRequest<Amenity> req) throws IOException {
for (Amenity amenity : amenities) {
req.publish(amenity);
}
return req.getSearchResults();
}
@Override
public List<City> getCities(SearchRequest<City> resultMatcher, int cityType) throws IOException {
for (City city : initCities) {
if (resultMatcher != null) {
resultMatcher.publish(city);
}
}
return initCities;
}
@Override
public int preloadStreets(City c, SearchRequest<Street> resultMatcher) throws IOException {
return 0;
}
@Override
public void preloadBuildings(Street s, SearchRequest<Building> resultMatcher) throws IOException {
// cities must be filled with streets and buildings
}
@Override
public List<MapObject> searchAddressDataByName(SearchRequest<MapObject> req) throws IOException {
for (City city : streetCities) {
for (Street street : city.getStreets()) {
req.publish(street);
}
}
for (City city : matchedCities) {
req.publish(city);
}
return req.getSearchResults();
}
@Override
public String getRegionName() {
return "Test region";
}
@Override
public boolean containsPoiData(int left31x, int top31y, int right31x, int bottom31y) {
return true;
}
@Override
public boolean containsMapData() {
return true;
}
@Override
public boolean containsPoiData() {
return true;
}
@Override
public boolean containsRouteData() {
return true;
}
@Override
public boolean containsRouteData(int left31x, int top31y, int right31x, int bottom31y, int zoom) {
return true;
}
@Override
public boolean containsAddressData(int left31x, int top31y, int right31x, int bottom31y) {
return true;
}
@Override
public boolean containsMapData(int tile31x, int tile31y, int zoom) {
return true;
}
@Override
public boolean containsMapData(int left31x, int top31y, int right31x, int bottom31y, int zoom) {
return true;
}
@Override
public boolean containsAddressData() {
return true;
}
}
}

View file

@ -1,3 +1,5 @@
*.json
/*.json
/osm_live/*.json
*.obf
*.osm
phrases.xml

View file

@ -0,0 +1,700 @@
{
"settings": {
"lat": "55.28666",
"lon": "52.00556",
"radiusLevel": 1,
"totalLimit": -1,
"lang": "",
"transliterateIfMissing": false,
"emptyQueryAllowed": false,
"sortByName": false
},
"phrase": "parking",
"results": [
"Park (Leisure)",
"Parking (Filter)",
"Parking entrance (Personal transport)",
"Parking fee (Charging station / Transportation)",
"Parking fee: no (Charging station / Transportation)",
"Parking fee: yes (Charging station / Transportation)",
"Parking lot (Fire hydrant / Emergency infrastructure)",
"Parking tickets (Vending machine / Store)",
"Parking tickets (Vending machine / Store)",
"Parking time limit (Parking / Personal transport)",
"Parking",
"Parking",
"Parking",
"Parking",
"Parking",
"Parking"
],
"amenities": [
{
"lat": "55.29801",
"lon": "51.99100",
"id": 881010149,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.29481",
"lon": "51.98964",
"id": 803545283,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"parking_surface": "surface"
}
},
{
"name": "Заинская ГРЭС",
"lat": "55.28492",
"lon": "52.02125",
"id": 481494555,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_yes": "yes",
"parking_surface": "surface"
}
},
{
"lat": "55.29105",
"lon": "51.99531",
"id": 540237721,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28683",
"lon": "52.01479",
"id": 888343263,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_unpaved": "unpaved",
"access_permissive": "permissive",
"supervised_yes": "yes"
}
},
{
"lat": "55.30317",
"lon": "52.00192",
"id": 1161722765,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"parking_surface": "surface",
"operator": "cахарный завод"
}
},
{
"name": "для техосмотра",
"lat": "55.30439",
"lon": "52.01634",
"id": 484385195,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28615",
"lon": "52.00702",
"id": 1040771455,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28582",
"lon": "52.00758",
"id": 535925577,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.30950",
"lon": "51.96954",
"id": 1228158833,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"parking_surface": "surface"
}
},
{
"lat": "55.29345",
"lon": "51.99385",
"id": 535897911,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.30957",
"lon": "52.00374",
"id": 897019441,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28602",
"lon": "52.00908",
"id": 268235957,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28777",
"lon": "51.99608",
"id": 4410403520512,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_unpaved": "unpaved",
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes",
"capacity": "70"
}
},
{
"lat": "55.34092",
"lon": "52.05172",
"id": 2136388576,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no"
}
},
{
"lat": "55.28271",
"lon": "52.00248",
"id": 536030271,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28391",
"lon": "52.00273",
"id": 536035007,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"name": "Служебная",
"lat": "55.28615",
"lon": "52.02350",
"id": 481491939,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_asphalt": "asphalt",
"fee_no": "no",
"access_permissive": "permissive",
"supervised_yes": "yes",
"parking_surface": "surface"
}
},
{
"lat": "55.30969",
"lon": "51.96917",
"id": 1228158821,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.31022",
"lon": "51.97104",
"id": 1228158819,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"parking_surface": "surface"
}
},
{
"lat": "55.29275",
"lon": "51.99355",
"id": 892959215,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"name": "для посетителей",
"lat": "55.28688",
"lon": "52.00578",
"id": 11390213698,
"subType": "parking",
"type": "transportation"
},
{
"lat": "55.30838",
"lon": "51.96767",
"id": 1164434353,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"parking_surface": "surface"
}
},
{
"name": "Южная",
"lat": "55.27739",
"lon": "52.00544",
"id": 641567205,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_unpaved": "unpaved",
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes"
}
},
{
"lat": "55.28045",
"lon": "51.99550",
"id": 478137507,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes"
}
},
{
"name": "Автостоянка №1",
"lat": "55.29028",
"lon": "51.99934",
"id": 502948005,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_gravel": "gravel",
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes"
}
},
{
"lat": "55.27839",
"lon": "52.00301",
"id": 1168315587,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"parking_surface": "surface",
"operator": "Заинская ЦРБ"
}
},
{
"lat": "55.30468",
"lon": "52.01335",
"id": 897014805,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.32509",
"lon": "51.99930",
"id": 1172111487,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"name": "Штрафстоянка (Эвакуатор)",
"lat": "55.30439",
"lon": "52.01346",
"id": 5153530824,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes",
"phone": "+7 (85558) 7-77-01"
}
},
{
"name": "Три тополя",
"lat": "55.29666",
"lon": "51.99048",
"id": 642175341,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_unpaved": "unpaved",
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes"
}
},
{
"lat": "55.29077",
"lon": "52.00812",
"id": 1168356553,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_asphalt": "asphalt",
"supervised_yes": "yes",
"parking_surface": "surface",
"fee_yes": "yes"
}
},
{
"lat": "55.29429",
"lon": "51.99190",
"id": 893048919,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.29959",
"lon": "52.00516",
"id": 1022216961,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28355",
"lon": "51.99881",
"id": 943827057,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"parking_surface": "surface"
}
},
{
"lat": "55.28651",
"lon": "52.00479",
"id": 905757839,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28928",
"lon": "52.00977",
"id": 190467181,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_gravel": "gravel",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28674",
"lon": "52.00282",
"id": 1168411743,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"name": "для клиентов",
"lat": "55.29116",
"lon": "51.99394",
"id": 821840897,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"surface_asphalt": "asphalt",
"parking_surface": "surface",
"access_customers": "customers"
}
},
{
"lat": "55.29068",
"lon": "51.99490",
"id": 540238031,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.28982",
"lon": "51.98911",
"id": 190489189,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.29341",
"lon": "51.99072",
"id": 806562897,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no"
}
},
{
"lat": "55.28042",
"lon": "52.00155",
"id": 1159734951,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.30493",
"lon": "52.01007",
"id": 1172110357,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.30500",
"lon": "52.01108",
"id": 1172110359,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface",
"capacity": "13"
}
},
{
"lat": "55.29816",
"lon": "51.99222",
"id": 1160388645,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.29015",
"lon": "51.99366",
"id": 503278061,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.30624",
"lon": "52.00475",
"id": 691494051,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface",
"operator": "ЗЗМК - Тимер"
}
},
{
"name": "для регистрации в ГИБДД",
"lat": "55.30438",
"lon": "52.01483",
"id": 484385289,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
},
{
"lat": "55.29258",
"lon": "51.99188",
"id": 892959265,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no"
}
},
{
"lat": "55.28050",
"lon": "52.00200",
"id": 1159662915,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface",
"capacity": "10"
}
},
{
"lat": "55.29845",
"lon": "51.99057",
"id": 881010015,
"subType": "parking",
"type": "transportation",
"additionalInfo": {
"fee_no": "no",
"surface_asphalt": "asphalt",
"supervised_no": "no",
"parking_surface": "surface"
}
}
]
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -438,26 +438,6 @@ public class AndroidUtils {
return !TextUtils.isEmpty(target) && android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
public static String getFileAsString(File file) {
try {
FileInputStream fin = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(fin, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(line);
}
reader.close();
fin.close();
return sb.toString();
} catch (Exception e) {
return null;
}
}
public static PointF centroidForPoly(PointF[] points) {
float centroidX = 0, centroidY = 0;

View file

@ -11,7 +11,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.Location;
import net.osmand.PlatformUtil;
@ -824,7 +823,7 @@ public class ExternalApiHelper {
// test show gpx (data)
uri = Uri.parse("osmand.api://show_gpx");
intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("data", AndroidUtils.getFileAsString(
intent.putExtra("data", Algorithms.getFileAsString(
new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), gpxName)));
}
@ -836,7 +835,7 @@ public class ExternalApiHelper {
// test navigate gpx (data)
uri = Uri.parse("osmand.api://navigate_gpx?force=true");
intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("data", AndroidUtils.getFileAsString(
intent.putExtra("data", Algorithms.getFileAsString(
new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), gpxName)));
}