From f6a40887172674a52db404bded63873d0ff1548a Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Thu, 21 May 2020 15:43:14 +0300 Subject: [PATCH 01/19] Fix #9016 --- OsmAnd/res/layout/global_preference_toolbar.xml | 9 ++------- .../layout/global_preferences_toolbar_with_switch.xml | 9 ++------- OsmAnd/res/layout/profile_preference_toolbar.xml | 9 ++------- .../layout/profile_preference_toolbar_with_switch.xml | 9 ++------- 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/OsmAnd/res/layout/global_preference_toolbar.xml b/OsmAnd/res/layout/global_preference_toolbar.xml index dd754224b4..bd31e3240b 100644 --- a/OsmAnd/res/layout/global_preference_toolbar.xml +++ b/OsmAnd/res/layout/global_preference_toolbar.xml @@ -21,14 +21,9 @@ diff --git a/OsmAnd/res/layout/profile_preference_toolbar_with_switch.xml b/OsmAnd/res/layout/profile_preference_toolbar_with_switch.xml index 502dfde3ca..d34c987376 100644 --- a/OsmAnd/res/layout/profile_preference_toolbar_with_switch.xml +++ b/OsmAnd/res/layout/profile_preference_toolbar_with_switch.xml @@ -27,14 +27,9 @@ From b0713af648b1a979a442214111c63228704f66f5 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Thu, 21 May 2020 18:42:06 +0300 Subject: [PATCH 02/19] Fix #9017 --- .../res/layout/point_editor_fragment_new.xml | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/OsmAnd/res/layout/point_editor_fragment_new.xml b/OsmAnd/res/layout/point_editor_fragment_new.xml index 53b1578816..0b2ca56e50 100644 --- a/OsmAnd/res/layout/point_editor_fragment_new.xml +++ b/OsmAnd/res/layout/point_editor_fragment_new.xml @@ -18,27 +18,26 @@ - + android:layout_marginStart="@dimen/list_item_button_padding" + android:layout_marginLeft="@dimen/list_item_button_padding" + android:layout_marginEnd="@dimen/list_item_button_padding" + android:layout_marginRight="@dimen/list_item_button_padding" + android:contentDescription="@string/access_shared_string_navigate_up" + app:srcCompat="@drawable/ic_action_replace" /> From f2dc4cdc4d63dbb3da936d2d1d28384544e4d4ed Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Fri, 22 May 2020 14:29:11 +0300 Subject: [PATCH 03/19] Check activity state before showing dialog --- .../osmand/plus/dialogs/ConfigureMapMenu.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java b/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java index 4c3378c77e..0ab07cc75b 100644 --- a/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java +++ b/OsmAnd/src/net/osmand/plus/dialogs/ConfigureMapMenu.java @@ -37,9 +37,6 @@ import net.osmand.plus.DialogListItemAdapter; import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; -import net.osmand.plus.settings.backend.OsmandSettings; -import net.osmand.plus.settings.backend.OsmandSettings.CommonPreference; -import net.osmand.plus.settings.backend.OsmandSettings.ListStringPreference; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; import net.osmand.plus.activities.MapActivity; @@ -51,6 +48,9 @@ import net.osmand.plus.inapp.InAppPurchaseHelper; import net.osmand.plus.poi.PoiFiltersHelper; import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; import net.osmand.plus.render.RendererRegistry; +import net.osmand.plus.settings.backend.OsmandSettings; +import net.osmand.plus.settings.backend.OsmandSettings.CommonPreference; +import net.osmand.plus.settings.backend.OsmandSettings.ListStringPreference; import net.osmand.plus.srtmplugin.SRTMPlugin; import net.osmand.plus.transport.TransportLinesMenu; import net.osmand.plus.views.OsmandMapTileView; @@ -529,6 +529,9 @@ public class ConfigureMapMenu { @Override public boolean onContextMenuClick(final ArrayAdapter ad, int itemId, final int pos, boolean isChecked, int[] viewCoordinates) { + if (!AndroidUtils.isActivityNotDestroyed(activity)) { + return false; + } final OsmandMapTileView view = activity.getMapView(); AlertDialog.Builder bld = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), themeRes)); bld.setTitle(R.string.daynight); @@ -570,6 +573,9 @@ public class ConfigureMapMenu { @Override public boolean onContextMenuClick(final ArrayAdapter ad, int itemId, final int pos, boolean isChecked, int[] viewCoordinates) { + if (!AndroidUtils.isActivityNotDestroyed(activity)) { + return false; + } final OsmandMapTileView view = activity.getMapView(); final OsmandSettings.OsmandPreference mapDensity = view.getSettings().MAP_DENSITY; AlertDialog.Builder bld = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), themeRes)); @@ -638,6 +644,9 @@ public class ConfigureMapMenu { @Override public boolean onContextMenuClick(final ArrayAdapter ad, int itemId, final int pos, boolean isChecked, int[] viewCoordinates) { + if (!AndroidUtils.isActivityNotDestroyed(activity)) { + return false; + } final OsmandMapTileView view = activity.getMapView(); AlertDialog.Builder b = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), themeRes)); // test old descr as title @@ -682,6 +691,9 @@ public class ConfigureMapMenu { @Override public boolean onContextMenuClick(final ArrayAdapter ad, int itemId, final int pos, boolean isChecked, int[] viewCoordinates) { + if (!AndroidUtils.isActivityNotDestroyed(activity)) { + return false; + } final OsmandMapTileView view = activity.getMapView(); AlertDialog.Builder b = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), themeRes)); @@ -991,7 +1003,9 @@ public class ConfigureMapMenu { final int themeRes, final boolean nightMode, @ColorInt final int selectedProfileColor) { - + if (!AndroidUtils.isActivityNotDestroyed(activity)) { + return; + } AlertDialog.Builder bld = new AlertDialog.Builder(new ContextThemeWrapper(activity, themeRes)); boolean[] checkedItems = new boolean[prefs.size()]; final boolean[] tempPrefs = new boolean[prefs.size()]; @@ -1245,7 +1259,10 @@ public class ConfigureMapMenu { @Override public boolean onContextMenuClick(final ArrayAdapter ad, - final int itemId, final int pos, boolean isChecked, int[] viewCoordinates) { + final int itemId, final int pos, boolean isChecked, int[] viewCoordinates) { + if (!AndroidUtils.isActivityNotDestroyed(activity)) { + return false; + } AlertDialog.Builder b = new AlertDialog.Builder(new ContextThemeWrapper(view.getContext(), themeRes)); // test old descr as title b.setTitle(propertyDescr); From 8a63a0ce53651ed05cb7bed0258006a9ece35a81 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Fri, 22 May 2020 14:50:14 +0300 Subject: [PATCH 04/19] Fix dashboard back button --- OsmAnd/res/layout/dashboard_toolbar.xml | 22 ++++++++++--------- .../osmand/plus/dashboard/DashboardOnMap.java | 7 +++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/OsmAnd/res/layout/dashboard_toolbar.xml b/OsmAnd/res/layout/dashboard_toolbar.xml index 24cff7957f..361dfc190f 100644 --- a/OsmAnd/res/layout/dashboard_toolbar.xml +++ b/OsmAnd/res/layout/dashboard_toolbar.xml @@ -7,8 +7,8 @@ android:layout_width="fill_parent" android:layout_height="@dimen/dashboard_map_toolbar" android:background="@color/app_bar_color_light" - app:contentInsetLeft="4dp" - app:contentInsetStart="4dp" + app:contentInsetLeft="0dp" + app:contentInsetStart="0dp" app:contentInsetRight="0dp" app:contentInsetEnd="0dp"> @@ -25,17 +25,18 @@ android:gravity="start" android:orientation="horizontal"> - + tools:visibility="visible" /> Date: Fri, 22 May 2020 15:01:42 +0300 Subject: [PATCH 05/19] Fix possible npe --- OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java b/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java index 55adfc9eaf..843a9576b7 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java @@ -393,7 +393,7 @@ public class MapQuickActionLayer extends OsmandMapLayer implements QuickActionRe canvas.translate(box.getCenterPixelX() - contextMarker.getWidth() / 2, box.getCenterPixelY() - contextMarker.getHeight()); contextMarker.draw(canvas); } - if (this.nightMode != nightMode) { + if (this.nightMode != nightMode && currentWidgetState != null) { this.nightMode = nightMode; updateQuickActionButton(currentWidgetState); } From 88a6d620803e19538e39cf24023c3c941a8dc307 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Fri, 22 May 2020 14:57:55 +0200 Subject: [PATCH 06/19] Fix map poi types --- .../main/java/net/osmand/osm/MapPoiTypes.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java b/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java index 330a21c156..4199abee89 100644 --- a/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java +++ b/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java @@ -29,6 +29,7 @@ import java.util.TreeSet; public class MapPoiTypes { + private static final String OTHER_MAP_CATEGORY = "Other"; private static MapPoiTypes DEFAULT_INSTANCE = null; private static final Log log = PlatformUtil.getLog(MapRenderingTypes.class); private String resourceName; @@ -96,7 +97,7 @@ public class MapPoiTypes { public PoiCategory getOtherMapCategory() { if (otherMapCategory == null) { - otherMapCategory = getPoiCategoryByName("Other", true); + otherMapCategory = getPoiCategoryByName(OTHER_MAP_CATEGORY, true); } return otherMapCategory; } @@ -111,7 +112,8 @@ public class MapPoiTypes { public List getTopVisibleFilters() { List lf = new ArrayList(); - for (PoiCategory pc : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory pc = categories.get(i); if (pc.isTopVisible()) { lf.add(pc); } @@ -131,7 +133,8 @@ public class MapPoiTypes { } public PoiCategory getOsmwiki() { - for (PoiCategory category : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory category = categories.get(i); if (category.isWiki()) { return category; } @@ -167,7 +170,8 @@ public class MapPoiTypes { } public PoiType getPoiTypeByKey(String name) { - for (PoiCategory pc : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory pc = categories.get(i); PoiType pt = pc.getPoiTypeByKeyName(name); if (pt != null && !pt.isReference()) { return pt; @@ -184,7 +188,8 @@ public class MapPoiTypes { } public AbstractPoiType getAnyPoiTypeByKey(String name) { - for (PoiCategory pc : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory pc = categories.get(i); if (pc.getKeyName().equals(name)) { return pc; } @@ -203,7 +208,8 @@ public class MapPoiTypes { public Map getAllTranslatedNames(boolean skipNonEditable) { Map translation = new HashMap(); - for (PoiCategory pc : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory pc = categories.get(i); if (skipNonEditable && pc.isNotEditableOsm()) { continue; } @@ -231,7 +237,8 @@ public class MapPoiTypes { public List getAllTypesTranslatedNames(StringMatcher matcher) { List tm = new ArrayList(); - for (PoiCategory pc : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory pc = categories.get(i); if (pc == otherMapCategory) { continue; } @@ -294,7 +301,7 @@ public class MapPoiTypes { } if (create) { PoiCategory lastCategory = new PoiCategory(this, name, categories.size()); - if (!lastCategory.getKeyName().equals("Other")) { + if (!lastCategory.getKeyName().equals(OTHER_MAP_CATEGORY)) { lastCategory.setTopVisible(true); } addCategory(lastCategory); @@ -365,6 +372,8 @@ public class MapPoiTypes { PoiType lastType = null; Set lastTypePoiAdditionalsCategories = new TreeSet(); String lastPoiAdditionalCategory = null; + PoiCategory localOtherMapCategory = new PoiCategory(this, OTHER_MAP_CATEGORY, categoriesList.size()); + categoriesList.add(localOtherMapCategory); while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) { if (tok == XmlPullParser.START_TAG) { String name = parser.getName(); @@ -404,7 +413,7 @@ public class MapPoiTypes { lastCategory.addPoiType(tp); } else if (name.equals("poi_additional")) { if (lastCategory == null) { - lastCategory = getOtherMapCategory(); + lastCategory = localOtherMapCategory; } PoiType baseType = parsePoiAdditional(parser, lastCategory, lastFilter, lastType, null, null, lastPoiAdditionalCategory); if ("true".equals(parser.getAttributeValue("", "lang"))) { @@ -433,7 +442,7 @@ public class MapPoiTypes { } else if (name.equals("poi_type")) { if (lastCategory == null) { - lastCategory = getOtherMapCategory(); + lastCategory = localOtherMapCategory; } if(!Algorithms.isEmpty(parser.getAttributeValue("", "deprecated_of"))){ String vl = parser.getAttributeValue("", "name"); @@ -705,7 +714,8 @@ public class MapPoiTypes { public AbstractPoiType getAnyPoiAdditionalTypeByKey(String name) { PoiType add = null; - for (PoiCategory pc : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory pc = categories.get(i); add = getPoiAdditionalByKey(pc, name); if (add != null) { return add; @@ -811,7 +821,8 @@ public class MapPoiTypes { if (!poiTypesByTag.isEmpty()) { return; } - for (PoiCategory poic : categories) { + for (int i = 0; i < categories.size(); i++) { + PoiCategory poic = categories.get(i); for (PoiType p : poic.getPoiTypes()) { initPoiType(p); for (PoiType pts : p.getPoiAdditionals()) { From 82c8349b3fceb87cc02711cfd5ad4af1371dae24 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Fri, 22 May 2020 15:58:08 +0300 Subject: [PATCH 07/19] Fix possible npe and concurrent exception --- OsmAnd/src/net/osmand/plus/MapMarkersHelper.java | 6 ++---- .../osmand/plus/activities/ContributionVersionActivity.java | 2 +- OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java index da3d5c8fce..556d7ad57b 100644 --- a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java +++ b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java @@ -1161,12 +1161,10 @@ public class MapMarkersHelper { removeGroupActiveMarkers(group, true); return; } - - for (FavouritePoint fp : favGroup.getPoints()) { + List favPoints = new ArrayList<>(favGroup.getPoints()); + for (FavouritePoint fp : favPoints) { addNewMarkerIfNeeded(group, groupMarkers, new LatLon(fp.getLatitude(), fp.getLongitude()), fp.getName(), fp, null); } - - } else if (group.getType() == MapMarkersGroup.GPX_TYPE) { GpxSelectionHelper gpxHelper = ctx.getSelectedGpxHelper(); File file = new File(group.getId()); diff --git a/OsmAnd/src/net/osmand/plus/activities/ContributionVersionActivity.java b/OsmAnd/src/net/osmand/plus/activities/ContributionVersionActivity.java index f1d28dfa2b..916f64fc59 100644 --- a/OsmAnd/src/net/osmand/plus/activities/ContributionVersionActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/ContributionVersionActivity.java @@ -132,7 +132,7 @@ public class ContributionVersionActivity extends OsmandListActivity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if(ACTIVITY_TO_INSTALL == requestCode && resultCode != RESULT_OK){ + if (ACTIVITY_TO_INSTALL == requestCode && resultCode != RESULT_OK && currentInstalledDate != null) { updateInstalledApp(false, currentInstalledDate); } } diff --git a/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java b/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java index 843a9576b7..33344bcf3a 100644 --- a/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/MapQuickActionLayer.java @@ -393,9 +393,9 @@ public class MapQuickActionLayer extends OsmandMapLayer implements QuickActionRe canvas.translate(box.getCenterPixelX() - contextMarker.getWidth() / 2, box.getCenterPixelY() - contextMarker.getHeight()); contextMarker.draw(canvas); } - if (this.nightMode != nightMode && currentWidgetState != null) { + if (this.nightMode != nightMode) { this.nightMode = nightMode; - updateQuickActionButton(currentWidgetState); + updateQuickActionButton(currentWidgetState != null && currentWidgetState); } setupQuickActionBtnVisibility(); } From a03bad42f7a25abc516a2e4406643ec65a94fe81 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Fri, 22 May 2020 16:03:36 +0300 Subject: [PATCH 08/19] Remove unnecessary changes --- OsmAnd/src/net/osmand/plus/MapMarkersHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java index 556d7ad57b..322c19e8e4 100644 --- a/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java +++ b/OsmAnd/src/net/osmand/plus/MapMarkersHelper.java @@ -1161,10 +1161,11 @@ public class MapMarkersHelper { removeGroupActiveMarkers(group, true); return; } - List favPoints = new ArrayList<>(favGroup.getPoints()); - for (FavouritePoint fp : favPoints) { + for (FavouritePoint fp : favGroup.getPoints()) { addNewMarkerIfNeeded(group, groupMarkers, new LatLon(fp.getLatitude(), fp.getLongitude()), fp.getName(), fp, null); } + + } else if (group.getType() == MapMarkersGroup.GPX_TYPE) { GpxSelectionHelper gpxHelper = ctx.getSelectedGpxHelper(); File file = new File(group.getId()); From 61fe550b52adda8333dbbb069b406689ebd40eee Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sat, 23 May 2020 10:47:05 +0200 Subject: [PATCH 09/19] Fix concurrent modification exception on start --- .../main/java/net/osmand/osm/MapPoiTypes.java | 40 ++++++++++++------- .../net/osmand/plus/poi/PoiFiltersHelper.java | 4 ++ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java b/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java index 4199abee89..60d835dbec 100644 --- a/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java +++ b/OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java @@ -360,6 +360,11 @@ public class MapPoiTypes { final Map allTypes = new LinkedHashMap(); final Map> categoryPoiAdditionalMap = new LinkedHashMap>(); final Map> abstractTypeAdditionalCategories = new LinkedHashMap>(); + final Map poiTypesByTag = new LinkedHashMap(); + final Map deprecatedTags = new LinkedHashMap(); + final Map poiAdditionalCategoryIconNames = new LinkedHashMap(); + final List textPoiAdditionals = new ArrayList(); + List categoriesList = new ArrayList<>(); try { XmlPullParser parser = PlatformUtil.newXMLPullParser(); @@ -415,12 +420,15 @@ public class MapPoiTypes { if (lastCategory == null) { lastCategory = localOtherMapCategory; } - PoiType baseType = parsePoiAdditional(parser, lastCategory, lastFilter, lastType, null, null, lastPoiAdditionalCategory); + PoiType baseType = parsePoiAdditional(parser, lastCategory, lastFilter, lastType, null, null, + lastPoiAdditionalCategory, textPoiAdditionals); if ("true".equals(parser.getAttributeValue("", "lang"))) { for (String lng : MapRenderingTypes.langs) { - parsePoiAdditional(parser, lastCategory, lastFilter, lastType, lng, baseType, lastPoiAdditionalCategory); + parsePoiAdditional(parser, lastCategory, lastFilter, lastType, lng, baseType, + lastPoiAdditionalCategory, textPoiAdditionals); } - parsePoiAdditional(parser, lastCategory, lastFilter, lastType, "en", baseType, lastPoiAdditionalCategory); + parsePoiAdditional(parser, lastCategory, lastFilter, lastType, "en", baseType, + lastPoiAdditionalCategory, textPoiAdditionals); } if (lastPoiAdditionalCategory != null) { List categoryAdditionals = categoryPoiAdditionalMap.get(lastPoiAdditionalCategory); @@ -491,7 +499,7 @@ public class MapPoiTypes { } } } - categories = categoriesList; + is.close(); } catch (IOException e) { log.error("Unexpected error", e); //$NON-NLS-1$ @@ -519,17 +527,25 @@ public class MapPoiTypes { List poiAdditionals = categoryPoiAdditionalMap.get(category); if (poiAdditionals != null) { for (PoiType poiType : poiAdditionals) { - buildPoiAdditionalReference(poiType, entry.getKey()); + buildPoiAdditionalReference(poiType, entry.getKey(), textPoiAdditionals); } } } } - findDefaultOtherCategory(); + this.categories = categoriesList; + this.poiTypesByTag = poiTypesByTag; + this.deprecatedTags = deprecatedTags; + this.poiAdditionalCategoryIconNames = poiAdditionalCategoryIconNames; + this.textPoiAdditionals = textPoiAdditionals; + otherCategory = getPoiCategoryByName("user_defined_other"); + if (otherCategory == null) { + throw new IllegalArgumentException("No poi category other"); + } init = true; log.info("Time to init poi types " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ } - private PoiType buildPoiAdditionalReference(PoiType poiAdditional, AbstractPoiType parent) { + private PoiType buildPoiAdditionalReference(PoiType poiAdditional, AbstractPoiType parent, List textPoiAdditionals) { PoiCategory lastCategory = null; PoiFilter lastFilter = null; PoiType lastType = null; @@ -580,7 +596,8 @@ public class MapPoiTypes { } private PoiType parsePoiAdditional(XmlPullParser parser, PoiCategory lastCategory, PoiFilter lastFilter, - PoiType lastType, String lang, PoiType langBaseType, String poiAdditionalCategory) { + PoiType lastType, String lang, PoiType langBaseType, + String poiAdditionalCategory, List textPoiAdditionals) { String oname = parser.getAttributeValue("", "name"); if (lang != null) { oname += ":" + lang; @@ -662,13 +679,6 @@ public class MapPoiTypes { return tp; } - private void findDefaultOtherCategory() { - PoiCategory pc = getPoiCategoryByName("user_defined_other"); - if (pc == null) { - throw new IllegalArgumentException("No poi category other"); - } - otherCategory = pc; - } public List getCategories(boolean includeMapCategory) { ArrayList lst = new ArrayList(categories); diff --git a/OsmAnd/src/net/osmand/plus/poi/PoiFiltersHelper.java b/OsmAnd/src/net/osmand/plus/poi/PoiFiltersHelper.java index 0037c5634b..d24109f6f2 100644 --- a/OsmAnd/src/net/osmand/plus/poi/PoiFiltersHelper.java +++ b/OsmAnd/src/net/osmand/plus/poi/PoiFiltersHelper.java @@ -617,6 +617,10 @@ public class PoiFiltersHelper { } public void loadSelectedPoiFilters() { + // don't deal with not loaded poi types + if(!application.getPoiTypes().isInit()) { + return; + } selectedPoiFilters.clear(); OsmandSettings settings = application.getSettings(); Set filters = settings.getSelectedPoiFilters(); From 92cdc61477d3f96819aa806e2064cd46eb7f4881 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sat, 23 May 2020 11:42:39 +0200 Subject: [PATCH 10/19] Fix no ctx exception --- OsmAnd/src/net/osmand/plus/mapmarkers/PlanRouteFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/PlanRouteFragment.java b/OsmAnd/src/net/osmand/plus/mapmarkers/PlanRouteFragment.java index a73e8a812f..8050da14d9 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/PlanRouteFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/PlanRouteFragment.java @@ -525,7 +525,7 @@ public class PlanRouteFragment extends BaseOsmAndFragment implements OsmAndLocat if (loc != null) { end = TargetPoint.createStartPoint(new LatLon(loc.getLatitude(), loc.getLongitude()), new PointDescription(PointDescription.POINT_TYPE_MY_LOCATION, - getString(R.string.shared_string_my_location))); + mapActivity.getString(R.string.shared_string_my_location))); } } if (end != null) { From ff20409fee51aa30ebbb81252d8a7d4bc106dc62 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 15:01:43 +0200 Subject: [PATCH 11/19] Refactor comparator to avoid comparator mistakes (no logical change were made) --- .../java/net/osmand/search/SearchUICore.java | 171 ++++++++++++------ 1 file changed, 111 insertions(+), 60 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java index 89e422ec60..48e85541ee 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java @@ -848,12 +848,119 @@ public class SearchUICore { return json; } } + + private enum ResultCompareStep { + TOP_VISIBLE, + UNKNOWN_PHRASE_MATCH_WEIGHT, + FOUND_WORD_COUNT, + SEARCH_DISTANCE_IF_NOT_BY_NAME, + COMPARE_FIRST_NUMBER_IN_NAME, + COMPARE_DISTANCE_TO_PARENT_SEARCH_RESULT, // makes sense only for inner subqueries + COMPARE_BY_NAME, + COMPARE_BY_DISTANCE, + AMENITY_LAST_AND_SORT_BY_SUBTYPE + ; + + // -1 - means 1st is less (higher) than 2nd + public int compare(SearchResult o1, SearchResult o2, SearchResultComparator c) { + switch(this) { + case TOP_VISIBLE: + boolean topVisible1 = ObjectType.isTopVisible(o1.objectType); + boolean topVisible2 = ObjectType.isTopVisible(o2.objectType); + if (topVisible1 != topVisible2) { + // -1 - means 1st is less than 2nd + return topVisible1 ? -1 : 1; + } + break; + case UNKNOWN_PHRASE_MATCH_WEIGHT: + if (o1.getUnknownPhraseMatchWeight() != o2.getUnknownPhraseMatchWeight()) { + return -Double.compare(o1.getUnknownPhraseMatchWeight(), o2.getUnknownPhraseMatchWeight()); + } + break; + case FOUND_WORD_COUNT: + if (o1.getFoundWordCount() != o2.getFoundWordCount()) { + return -Algorithms.compare(o1.getFoundWordCount(), o2.getFoundWordCount()); + } + break; + case SEARCH_DISTANCE_IF_NOT_BY_NAME: + if (!c.sortByName) { + double s1 = o1.getSearchDistance(c.loc); + double s2 = o2.getSearchDistance(c.loc); + if (s1 != s2) { + return Double.compare(s1, s2); + } + } + break; + case COMPARE_FIRST_NUMBER_IN_NAME: { + String localeName1 = o1.localeName == null ? "" : o1.localeName; + String localeName2 = o2.localeName == null ? "" : o2.localeName; + int st1 = Algorithms.extractFirstIntegerNumber(localeName1); + int st2 = Algorithms.extractFirstIntegerNumber(localeName2); + if (st1 != st2) { + return Algorithms.compare(st1, st2); + } + break; + } + case COMPARE_DISTANCE_TO_PARENT_SEARCH_RESULT: + double ps1 = o1.parentSearchResult == null ? 0 : o1.parentSearchResult.getSearchDistance(c.loc); + double ps2 = o2.parentSearchResult == null ? 0 : o2.parentSearchResult.getSearchDistance(c.loc); + if (ps1 != ps2) { + return Double.compare(ps1, ps2); + } + break; + case COMPARE_BY_NAME: { + String localeName1 = o1.localeName == null ? "" : o1.localeName; + String localeName2 = o2.localeName == null ? "" : o2.localeName; + int cmp = c.collator.compare(localeName1, localeName2); + if (cmp != 0) { + return cmp; + } + break; + } + case COMPARE_BY_DISTANCE: + double s1 = o1.getSearchDistance(c.loc, 1); + double s2 = o2.getSearchDistance(c.loc, 1); + if (s1 != s2) { + return Double.compare(s1, s2); + } + break; + case AMENITY_LAST_AND_SORT_BY_SUBTYPE: { + boolean am1 = o1.object instanceof Amenity; + boolean am2 = o2.object instanceof Amenity; + if (am1 != am2) { + // amenity second + return am1 ? 1 : -1; + } else if (am1 && am2) { + // here 2 points are amenity + Amenity a1 = (Amenity) o1.object; + Amenity a2 = (Amenity) o2.object; + String type1 = a1.getType().getKeyName(); + String type2 = a2.getType().getKeyName(); + int cmp = c.collator.compare(type1, type2); + if (cmp != 0) { + return cmp; + } + + String subType1 = a1.getSubType() == null ? "" : a1.getSubType(); + String subType2 = a2.getSubType() == null ? "" : a2.getSubType(); + cmp = c.collator.compare(subType1, subType2); + if (cmp != 0) { + return cmp; + } + } + break; + } + } + return 0; + } + } public static class SearchResultComparator implements Comparator { private SearchPhrase sp; private Collator collator; private LatLon loc; private boolean sortByName; + public SearchResultComparator(SearchPhrase sp) { this.sp = sp; @@ -865,66 +972,10 @@ public class SearchUICore { @Override public int compare(SearchResult o1, SearchResult o2) { - boolean topVisible1 = ObjectType.isTopVisible(o1.objectType); - boolean topVisible2 = ObjectType.isTopVisible(o2.objectType); - if (topVisible1 != topVisible2) { - // -1 - means 1st is less than 2nd - return topVisible1 ? -1 : 1; - } - if (o1.getUnknownPhraseMatchWeight() != o2.getUnknownPhraseMatchWeight()) { - return -Double.compare(o1.getUnknownPhraseMatchWeight(), o2.getUnknownPhraseMatchWeight()); - } - if (o1.getFoundWordCount() != o2.getFoundWordCount()) { - return -Algorithms.compare(o1.getFoundWordCount(), o2.getFoundWordCount()); - } - if (!sortByName) { - double s1 = o1.getSearchDistance(loc); - double s2 = o2.getSearchDistance(loc); - if (s1 != s2) { - return Double.compare(s1, s2); - } - } - String localeName1 = o1.localeName == null ? "" : o1.localeName; - String localeName2 = o2.localeName == null ? "" : o2.localeName; - int st1 = Algorithms.extractFirstIntegerNumber(localeName1); - int st2 = Algorithms.extractFirstIntegerNumber(localeName2); - if (st1 != st2) { - return Algorithms.compare(st1, st2); - } - double s1 = o1.getSearchDistance(loc, 1); - double s2 = o2.getSearchDistance(loc, 1); - double ps1 = o1.parentSearchResult == null ? 0 : o1.parentSearchResult.getSearchDistance(loc); - double ps2 = o2.parentSearchResult == null ? 0 : o2.parentSearchResult.getSearchDistance(loc); - if (ps1 != ps2) { - return Double.compare(ps1, ps2); - } - int cmp = collator.compare(localeName1, localeName2); - if (cmp != 0) { - return cmp; - } - if (s1 != s2) { - return Double.compare(s1, s2); - } - boolean am1 = o1.object instanceof Amenity; - boolean am2 = o2.object instanceof Amenity; - if (am1 != am2) { - return Boolean.compare(am1, am2); - } else if (am1 && am2) { - // here 2 points are amenity - Amenity a1 = (Amenity) o1.object; - Amenity a2 = (Amenity) o2.object; - String type1 = a1.getType().getKeyName(); - String type2 = a2.getType().getKeyName(); - cmp = collator.compare(type1, type2); - if (cmp != 0) { - return cmp; - } - - String subType1 = a1.getSubType() == null ? "" : a1.getSubType(); - String subType2 = a2.getSubType() == null ? "" : a2.getSubType(); - cmp = collator.compare(subType1, subType2); - if (cmp != 0) { - return cmp; + for(ResultCompareStep step : ResultCompareStep.values()) { + int r = step.compare(o1, o2, this); + if(r != 0) { + return r; } } return 0; From cf28032858a8684c6ea4723e108d4705e738f501 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 15:36:41 +0200 Subject: [PATCH 12/19] Refactor tests --- .../search/SearchUICoreGenericTest.java | 111 ++++++ ...hCoreUITest.java => SearchUICoreTest.java} | 344 ++++++++---------- 2 files changed, 258 insertions(+), 197 deletions(-) create mode 100644 OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreGenericTest.java rename OsmAnd-java/src/test/java/net/osmand/search/{SearchCoreUITest.java => SearchUICoreTest.java} (56%) diff --git a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreGenericTest.java b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreGenericTest.java new file mode 100644 index 0000000000..aa4d7430d6 --- /dev/null +++ b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreGenericTest.java @@ -0,0 +1,111 @@ +package net.osmand.search; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import net.osmand.OsmAndCollator; +import net.osmand.data.LatLon; +import net.osmand.search.SearchUICore.SearchResultCollection; +import net.osmand.search.core.SearchPhrase; +import net.osmand.search.core.SearchResult; +import net.osmand.search.core.SearchSettings; +import net.osmand.util.MapUtils; + +public class SearchUICoreGenericTest { + + + @BeforeClass + public static void setUp() { + SearchUICoreTest.defaultSetup(); + } + + + @Test + public void testDuplicates() throws IOException { + SearchSettings ss = new SearchSettings((SearchSettings)null); + ss = ss.setOriginalLocation(new LatLon(0, 0)); + SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); + SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); + List rs = new ArrayList<>(); + SearchResult a1 = searchResult(rs, phrase, "a", 100); + SearchResult b2 = searchResult(rs, phrase, "b", 200); + SearchResult b1 = searchResult(rs, phrase, "b", 100); + /*SearchResult a3 = */ searchResult(rs, phrase, "a", 100); + cll.addSearchResults(rs, true, true); + Assert.assertEquals(3, cll.getCurrentSearchResults().size()); + Assert.assertSame(a1, cll.getCurrentSearchResults().get(0)); + Assert.assertSame(b1, cll.getCurrentSearchResults().get(1)); + Assert.assertSame(b2, cll.getCurrentSearchResults().get(2)); + } + + @Test + public void testNoResort() throws IOException { + SearchSettings ss = new SearchSettings((SearchSettings)null); + ss = ss.setOriginalLocation(new LatLon(0, 0)); + SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); + SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); + List rs = new ArrayList<>(); + SearchResult a1 = searchResult(rs, phrase, "a", 100); + cll.addSearchResults(rs, false, true); + rs.clear(); + + SearchResult b2 = searchResult(rs, phrase, "b", 200); + cll.addSearchResults(rs, false, true); + rs.clear(); + + SearchResult b1 = searchResult(rs, phrase, "b", 100); + cll.addSearchResults(rs, false, true); + rs.clear(); + + /*SearchResult a3 = */ searchResult(rs, phrase, "a", 100); + cll.addSearchResults(rs, false, true); + rs.clear(); + + Assert.assertEquals(3, cll.getCurrentSearchResults().size()); + Assert.assertSame(a1, cll.getCurrentSearchResults().get(0)); + Assert.assertSame(b2, cll.getCurrentSearchResults().get(1)); + Assert.assertSame(b1, cll.getCurrentSearchResults().get(2)); + + + + } + + + @Test + public void testNoResortDuplicate() throws IOException { + SearchSettings ss = new SearchSettings((SearchSettings)null); + ss = ss.setOriginalLocation(new LatLon(0, 0)); + SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); + SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); + List rs = new ArrayList<>(); + SearchResult a1 = searchResult(rs, phrase, "a", 100); + SearchResult b2 = searchResult(rs, phrase, "b", 200); + SearchResult b1 = searchResult(rs, phrase, "b", 100); + cll.addSearchResults(rs, false, true); + rs.clear(); + /*SearchResult a3 = */ searchResult(rs, phrase, "a", 100); + cll.addSearchResults(rs, false, true); + rs.clear(); + + Assert.assertEquals(3, cll.getCurrentSearchResults().size()); + Assert.assertSame(a1, cll.getCurrentSearchResults().get(0)); + Assert.assertSame(b1, cll.getCurrentSearchResults().get(1)); + Assert.assertSame(b2, cll.getCurrentSearchResults().get(2)); + } + + private SearchResult searchResult(List rs, SearchPhrase phrase, String text, int dist) { + SearchResult res = new SearchResult(phrase); + res.localeName = text; + double d1 = MapUtils.getDistance(0, 0, 0, 1); + res.location = new LatLon(0, dist / d1); + rs.add(res); + return res; + } + + +} diff --git a/OsmAnd-java/src/test/java/net/osmand/search/SearchCoreUITest.java b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java similarity index 56% rename from OsmAnd-java/src/test/java/net/osmand/search/SearchCoreUITest.java rename to OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java index 80d92b7bf1..92af480864 100644 --- a/OsmAnd-java/src/test/java/net/osmand/search/SearchCoreUITest.java +++ b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java @@ -1,34 +1,10 @@ package net.osmand.search; -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.io.InputStreamReader; +import java.io.Reader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -36,16 +12,61 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -public class SearchCoreUITest { +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.xmlpull.v1.XmlPullParserException; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +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.MapObject; +import net.osmand.data.Street; +import net.osmand.osm.AbstractPoiType; +import net.osmand.osm.MapPoiTypes; +import net.osmand.router.RouteTestingTest; +import net.osmand.router.TestEntry; +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; + +@RunWith(Parameterized.class) +public class SearchUICoreTest { private static final String SEARCH_RESOURCES_PATH = "src/test/resources/search/"; - private static Map enPhrases = new HashMap<>(); - private static Map phrases = new HashMap<>(); + + private File testFile; - static { + public SearchUICoreTest(String name, File file) { + this.testFile = file; + } + + + @BeforeClass + public static void setUp() { + defaultSetup(); + } + + + static void defaultSetup() { MapPoiTypes.setDefault(new MapPoiTypes("src/test/resources/poi_types.xml")); MapPoiTypes poiTypes = MapPoiTypes.getDefault(); - + Map enPhrases = new HashMap<>(); + Map phrases = new HashMap<>(); 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")); @@ -56,178 +77,29 @@ public class SearchCoreUITest { 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); - ss = ss.setOriginalLocation(new LatLon(0, 0)); - SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); - SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); - List rs = new ArrayList<>(); - SearchResult a1 = searchResult(rs, phrase, "a", 100); - SearchResult b2 = searchResult(rs, phrase, "b", 200); - SearchResult b1 = searchResult(rs, phrase, "b", 100); - /*SearchResult a3 = */ searchResult(rs, phrase, "a", 100); - cll.addSearchResults(rs, true, true); - Assert.assertEquals(3, cll.getCurrentSearchResults().size()); - Assert.assertSame(a1, cll.getCurrentSearchResults().get(0)); - Assert.assertSame(b1, cll.getCurrentSearchResults().get(1)); - Assert.assertSame(b2, cll.getCurrentSearchResults().get(2)); - } - - @Test - public void testNoResort() throws IOException { - SearchSettings ss = new SearchSettings((SearchSettings)null); - ss = ss.setOriginalLocation(new LatLon(0, 0)); - SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); - SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); - List rs = new ArrayList<>(); - SearchResult a1 = searchResult(rs, phrase, "a", 100); - cll.addSearchResults(rs, false, true); - rs.clear(); - - SearchResult b2 = searchResult(rs, phrase, "b", 200); - cll.addSearchResults(rs, false, true); - rs.clear(); - - SearchResult b1 = searchResult(rs, phrase, "b", 100); - cll.addSearchResults(rs, false, true); - rs.clear(); - - /*SearchResult a3 = */ searchResult(rs, phrase, "a", 100); - cll.addSearchResults(rs, false, true); - rs.clear(); - - Assert.assertEquals(3, cll.getCurrentSearchResults().size()); - Assert.assertSame(a1, cll.getCurrentSearchResults().get(0)); - Assert.assertSame(b2, cll.getCurrentSearchResults().get(1)); - Assert.assertSame(b1, cll.getCurrentSearchResults().get(2)); - - - + poiTypes.setPoiTranslator(new TestSearchTranslator(phrases, enPhrases)); } - @Test - public void testNoResortDuplicate() throws IOException { - SearchSettings ss = new SearchSettings((SearchSettings)null); - ss = ss.setOriginalLocation(new LatLon(0, 0)); - SearchPhrase phrase = new SearchPhrase(ss, OsmAndCollator.primaryCollator()); - SearchResultCollection cll = new SearchUICore.SearchResultCollection(phrase); - List rs = new ArrayList<>(); - SearchResult a1 = searchResult(rs, phrase, "a", 100); - SearchResult b2 = searchResult(rs, phrase, "b", 200); - SearchResult b1 = searchResult(rs, phrase, "b", 100); - cll.addSearchResults(rs, false, true); - rs.clear(); - /*SearchResult a3 = */ searchResult(rs, phrase, "a", 100); - cll.addSearchResults(rs, false, true); - rs.clear(); - - Assert.assertEquals(3, cll.getCurrentSearchResults().size()); - Assert.assertSame(a1, cll.getCurrentSearchResults().get(0)); - Assert.assertSame(b1, cll.getCurrentSearchResults().get(1)); - Assert.assertSame(b2, cll.getCurrentSearchResults().get(2)); - - - } - - private SearchResult searchResult(List rs, SearchPhrase phrase, String text, int dist) { - SearchResult res = new SearchResult(phrase); - res.localeName = text; - double d1 = MapUtils.getDistance(0, 0, 0, 1); - res.location = new LatLon(0, dist / d1); - 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); + @Parameterized.Parameters(name = "{index}: {0}") + public static Iterable data() throws IOException { + final File[] files = new File(SEARCH_RESOURCES_PATH).listFiles(); + ArrayList arrayList = new ArrayList<>(); + if (files != null) { + for (File file : files) { + String fileName = file.getName(); + if(fileName.endsWith(".json")) { + String name = fileName.substring(0, fileName.length() - ".json".length()); + arrayList.add(new Object[] {name, file}); + } } } - } + return arrayList; + } - private void testSearchImpl(File jsonFile) throws IOException, JSONException { + @Test + public void testSearchImpl() throws IOException, JSONException { + File jsonFile = testFile; String sourceJsonText = Algorithms.getFileAsString(jsonFile); Assert.assertNotNull(sourceJsonText); Assert.assertTrue(sourceJsonText.length() > 0); @@ -316,6 +188,84 @@ public class SearchCoreUITest { } } + static class TestSearchTranslator implements MapPoiTypes.PoiTranslator { + + private Map enPhrases; + private Map phrases; + public TestSearchTranslator(Map phrases, Map enPhrases) { + this.phrases = phrases; + this.enPhrases = enPhrases; + } + + @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; + } + }; + private static class BinaryMapIndexReaderTest extends BinaryMapIndexReader { List amenities = Collections.emptyList(); From f980ec4340668a04ebe295bb26735e8b1fdf267a Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 15:55:14 +0200 Subject: [PATCH 13/19] Update ui tests & search fixing #8647 Conflicts: OsmAnd-java/src/test/resources/search/navacerrada.json --- .../java/net/osmand/search/SearchUICore.java | 2 +- .../net/osmand/search/SearchUICoreTest.java | 23 +- .../search/free_street_portland.json | 25 +- .../test/resources/search/navacerrada.json | 3373 +++++++++++++++++ 4 files changed, 3402 insertions(+), 21 deletions(-) create mode 100644 OsmAnd-java/src/test/resources/search/navacerrada.json diff --git a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java index 48e85541ee..7eec13cd94 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java @@ -851,8 +851,8 @@ public class SearchUICore { private enum ResultCompareStep { TOP_VISIBLE, - UNKNOWN_PHRASE_MATCH_WEIGHT, FOUND_WORD_COUNT, + UNKNOWN_PHRASE_MATCH_WEIGHT, SEARCH_DISTANCE_IF_NOT_BY_NAME, COMPARE_FIRST_NUMBER_IN_NAME, COMPARE_DISTANCE_TO_PARENT_SEARCH_RESULT, // makes sense only for inner subqueries diff --git a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java index 92af480864..0af85e9acb 100644 --- a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java +++ b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java @@ -1,10 +1,7 @@ package net.osmand.search; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -22,9 +19,6 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.xmlpull.v1.XmlPullParserException; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - import net.osmand.OsmAndCollator; import net.osmand.ResultMatcher; import net.osmand.binary.BinaryMapIndexReader; @@ -35,8 +29,6 @@ import net.osmand.data.MapObject; import net.osmand.data.Street; import net.osmand.osm.AbstractPoiType; import net.osmand.osm.MapPoiTypes; -import net.osmand.router.RouteTestingTest; -import net.osmand.router.TestEntry; import net.osmand.search.SearchUICore.SearchResultCollection; import net.osmand.search.SearchUICore.SearchResultMatcher; import net.osmand.search.core.SearchPhrase; @@ -48,6 +40,7 @@ import net.osmand.util.Algorithms; public class SearchUICoreTest { private static final String SEARCH_RESOURCES_PATH = "src/test/resources/search/"; + private static boolean TEST_EXTRA_RESULTS = true; private File testFile; @@ -98,7 +91,7 @@ public class SearchUICoreTest { } @Test - public void testSearchImpl() throws IOException, JSONException { + public void testSearch() throws IOException, JSONException { File jsonFile = testFile; String sourceJsonText = Algorithms.getFileAsString(jsonFile); Assert.assertNotNull(sourceJsonText); @@ -149,6 +142,12 @@ public class SearchUICoreTest { results.add(resultsArr.getString(i)); } } + if (TEST_EXTRA_RESULTS && sourceJson.has("extra-results")) { + JSONArray resultsArr = sourceJson.getJSONArray("extra-results"); + for (int i = 0; i < resultsArr.length(); i++) { + results.add(resultsArr.getString(i)); + } + } SearchSettings s = SearchSettings.parseJSON(settingsJson); s.setOfflineIndexes(Collections.singletonList(reader)); @@ -181,6 +180,12 @@ public class SearchUICoreTest { String expected = results.get(i++); String present = result.toString(); //System.out.println(present); + if(!Algorithms.stringsEqual(expected, present)) { + System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present)); + for (SearchResult r : searchResults) { + System.out.println("\t\""+r.toString()+"\","); + } + } Assert.assertEquals(expected, present); if (i >= results.size()) { break; diff --git a/OsmAnd-java/src/test/resources/search/free_street_portland.json b/OsmAnd-java/src/test/resources/search/free_street_portland.json index 3f73bf1a3e..a4926a4877 100644 --- a/OsmAnd-java/src/test/resources/search/free_street_portland.json +++ b/OsmAnd-java/src/test/resources/search/free_street_portland.json @@ -12,17 +12,20 @@ "phrase": "48 Free Street Portland", "results": [ "48.0, ", - "48, Free Street (Downtown), Portland", - "48, Portland Street, North Berwick", - "48, Portland Avenue, Old Orchard Beach", - "Portland Street (Downtown), Portland", - "Portland Street Pier, South Portland", - "Portland Street, Yarmouth", - "Portland Street, North Berwick", - "Portland Street, Berwick", - "Portland Street, South Berwick", - "Portland Street, Fryeburg", - "Portland Square, Portland" + "48, Free Street (Downtown), Portland"], + "extra-results": [ + "48, Portland Street, North Berwick", + "Free Street (Downtown), Portland", + "Free Street (Ferry Village), South Portland", + "Portland Street", + "48, Portland Avenue, Old Orchard Beach", + "Portland Street (Downtown), Portland", + "Portland Street Pier, South Portland", + "Portland Street, Yarmouth", + "Portland Street, North Berwick", + "Portland Street, Berwick", + "Portland Street, South Berwick", + "Portland Street, Fryeburg" ], "amenities": [ { diff --git a/OsmAnd-java/src/test/resources/search/navacerrada.json b/OsmAnd-java/src/test/resources/search/navacerrada.json new file mode 100644 index 0000000000..1358fb0e32 --- /dev/null +++ b/OsmAnd-java/src/test/resources/search/navacerrada.json @@ -0,0 +1,3373 @@ +{ + "settings": { + "lat": "40.22203", + "lon": "-3.52043", + "radiusLevel": 1, + "totalLimit": -1, + "lang": "", + "transliterateIfMissing": false, + "emptyQueryAllowed": false, + "sortByName": false + }, + "phrase": "Calle de las eras 5, Navacerrada", + "results": [ + "5, Calle de las Eras (Uranización Los Corales), Navacerrada" + ], + "extra-results": [ + "Calle de las Eras (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada", + "Calle del Sotillo (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada", + "5, Calle Navacerrada (Urb. Las Suertes), Las Suertes", + "50, Calle de Francisco Navacerrada, Salamanca", + "52, Calle de Francisco Navacerrada, Salamanca", + "53, Calle de Francisco Navacerrada, Salamanca", + "54, Calle de Francisco Navacerrada, Salamanca", + "55, Calle de Francisco Navacerrada, Salamanca", + "56, Calle de Francisco Navacerrada, Salamanca", + "57, Calle de Francisco Navacerrada, Salamanca", + "58, Calle de Francisco Navacerrada, Salamanca", + "59, Calle de Francisco Navacerrada, Salamanca", + "Calle del Puerto de Navacerrada, Las Nieves", + "Pasaje de las Eras (Uranización Los Corales), Navacerrada", + "Calle Barrio de las Peñas, Navacerrada", + "Calle de las Cruces (Residencial Sanabria), Navacerrada", + "Calle de las Escuelas, Navacerrada", + "Calle de las Huertas (Residencial Sanabria), Navacerrada", + "Calle de la Virgen de las Nieves, Puerto de Navacerrada", + "Calle Puerto de Navacerrada, La Poveda", + "Calle del Embalse de Navacerrada, Villa de Vallecas", + "Calle del Puerto de Navacerrada, Puente de Vallecas", + "Calle de Francisco Navacerrada, Salamanca", + "Calle de Navacerrada, Moraleja de Enmedio", + "Calle Navacerrada (Urb. Las Suertes), Las Suertes", + "Calle Puerto de Navacerrada, Roman Candelas", + "Calle Navacerrada, Becerril de la Sierra", + "Carretera de Collado Villalba a Navacerrada, El Baillo y las Hojarascas", + "Calle de Ángel Rojas, Navacerrada", + "Calle de los Robles (Uranización Los Corales), Navacerrada", + "Calle de los Enebros (Uranización Los Corales), Navacerrada", + "Calle de la Bola del Mundo (Residencial Sanabria), Navacerrada", + "Calle de la Maliciosa (Residencial Sanabria), Navacerrada", + ], + "amenities": [ + { + "name": "CIMA MA05-2", + "lat": "40.70529", + "lon": "-4.06895", + "id": 637431647, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680", + "ref": "M-614", + "operator": "CIMA, Larrea" + } + }, + { + "name": "Plaça Navacerrada", + "lat": "41.57014", + "lon": "2.09182", + "id": 580630395, + "subType": "square", + "type": "man_made", + "additionalInfo": { + "surface_paving_stones": "paving_stones", + "lit_yes": "yes" + } + }, + { + "name": "CIMA MA05-2", + "lat": "40.70722", + "lon": "-4.06816", + "id": 637431645, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "ref": "M-614", + "operator": "CIMA" + } + }, + { + "name": "Arroyo de Navacerrada", + "lat": "40.79763", + "lon": "-3.71254", + "id": 504296555, + "subType": "stream", + "type": "natural" + }, + { + "name": "CIMA MA05-2", + "lat": "40.71215", + "lon": "-4.06445", + "id": 1549410751, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "ref": "M-614", + "operator": "CIMA" + } + }, + { + "name": "Residencia Militar de Acción Social de Descanso (RMASD) Navacerrada", + "lat": "40.78568", + "lon": "-4.00229", + "id": 206884273, + "subType": "hotel", + "type": "tourism", + "additionalInfo": { + "internet_access_type_wlan": "wlan", + "website": "https://ejercito.defensa.gob.es/diaper/Galerias/ocio/residencias/nacionales/ficheros/20180724_RMASD_NAVACERRADA.pdf", + "phone": "+34 91 849 45 00; +34 91 880 45 00", + "beds": "196", + "email": "navacerrada@et.mde.es", + "operator": "ET", + "rooms": "90", + "fax": "+34 91 749 46 29" + } + }, + { + "name": "Residencia Militar de Acción Social de Descanso (RMASD) Navacerrada", + "lat": "40.78568", + "lon": "-4.00229", + "id": 206884273, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "internet_access_type_wlan": "wlan", + "website": "https://ejercito.defensa.gob.es/diaper/Galerias/ocio/residencias/nacionales/ficheros/20180724_RMASD_NAVACERRADA.pdf", + "phone": "+34 91 849 45 00; +34 91 880 45 00", + "beds": "196", + "email": "navacerrada@et.mde.es", + "operator": "ET", + "rooms": "90", + "fax": "+34 91 749 46 29" + } + }, + { + "name": "Puerto de Navacerrada", + "lat": "40.78892", + "lon": "-4.00344", + "id": 8117318832, + "subType": "saddle", + "type": "natural", + "additionalInfo": { + "ele": "1858" + } + }, + { + "name": "Embalse de Navacerrada", + "lat": "40.71831", + "lon": "-4.00823", + "id": 38209571, + "subType": "water", + "type": "natural" + }, + { + "name": "Puerto de Navacerrada", + "lat": "40.78629", + "lon": "-4.00267", + "id": 607141782, + "subType": "hamlet", + "type": "administrative", + "additionalInfo": { + "population": "105", + "ele": "1812" + } + }, + { + "name": "Plaça Navacerrada", + "lat": "41.57024", + "lon": "2.09157", + "id": 580630399, + "subType": "square", + "type": "man_made", + "additionalInfo": { + "surface_paving_stones": "paving_stones" + } + }, + { + "name": "CIMA MA05-2", + "lat": "40.70070", + "lon": "-4.07155", + "id": 1277749125, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680", + "ref": "M-614", + "operator": "CIMA, Larrea" + } + }, + { + "name": "Depósito de agua Navacerrada", + "lat": "40.73776", + "lon": "-4.01776", + "id": 632179871, + "subType": "storage_tank", + "type": "man_made" + }, + { + "name": "Depósito de agua Navacerrada", + "lat": "40.73776", + "lon": "-4.01776", + "id": 632179871, + "subType": "building", + "type": "man_made" + }, + { + "name": "Arroyo de Navacerrada", + "lat": "40.82982", + "lon": "-3.72370", + "id": 504296571, + "subType": "stream", + "type": "natural" + }, + { + "name": "ADESGAM", + "lat": "40.67421", + "lon": "-4.08404", + "id": 54534453, + "subType": "rcn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "El Porron de Navacerrada", + "lat": "40.73069", + "lon": "-4.01074", + "id": 3638099748, + "subType": "restaurant", + "type": "sustenance", + "additionalInfo": { + "phone": "+34 669 888 301" + } + }, + { + "name": "Pto. Navacerrada", + "lat": "40.78444", + "lon": "-4.00473", + "id": 12363492954, + "subType": "public_transport_station", + "type": "transportation", + "additionalInfo": { + "wikipedia": "http://es.wikipedia.org/wiki/Estación de Puerto de Navacerrada" + } + }, + { + "name": "Pto. Navacerrada", + "lat": "40.78444", + "lon": "-4.00473", + "id": 12363492954, + "subType": "railway_station", + "type": "transportation", + "additionalInfo": { + "wikipedia": "http://es.wikipedia.org/wiki/Estación de Puerto de Navacerrada" + } + }, + { + "name": "Navacerrada", + "lat": "40.72880", + "lon": "-4.01518", + "id": 513208556, + "subType": "village", + "type": "administrative", + "additionalInfo": { + "website": "https://www.aytonavacerrada.org/", + "population": "2863", + "ele": "1195" + } + }, + { + "name": "CIMA MA05-2", + "lat": "40.70646", + "lon": "-4.06848", + "id": 486489283, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680", + "ref": "M-614", + "operator": "CIMA, Larrea" + } + }, + { + "name": "Tanatorio de Navacerrada", + "lat": "40.73280", + "lon": "-4.01261", + "id": 612724219, + "subType": "building", + "type": "man_made" + }, + { + "name": "Presa del Embalse de Navacerrada", + "lat": "40.75282", + "lon": "-3.99287", + "id": 193455239, + "subType": "dam", + "type": "man_made", + "additionalInfo": { + "ele": "1383" + } + }, + { + "name": "Presa del Embalse de Navacerrada", + "lat": "40.75282", + "lon": "-3.99287", + "id": 193455239, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "ele": "1383" + } + }, + { + "name": "ADESGAM", + "lat": "40.67437", + "lon": "-4.08406", + "id": 54534469, + "subType": "rcn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "Casa de Guías de Navacerrada", + "lat": "40.75423", + "lon": "-3.99422", + "id": 5372781178, + "subType": "building", + "type": "man_made" + }, + { + "name": "Pto. Navacerrada", + "lat": "40.78416", + "lon": "-4.00488", + "id": 685245267, + "subType": "public_transport_platform", + "type": "transportation" + }, + { + "name": "Avenida de Navacerrada", + "lat": "40.46203", + "lon": "-3.80318", + "id": 48756909, + "subType": "bridge", + "type": "man_made", + "additionalInfo": { + "bridge_car": "yes" + } + }, + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.63854", + "lon": "-4.00602", + "id": 599484149, + "subType": "bridge", + "type": "man_made", + "additionalInfo": { + "bridge_car": "yes", + "route_bus_ref": "691", + "ref": "M-601", + "operator": "Larrea" + } + }, + { + "name": "Carretera de Colmenar Viejo a Navacerrada", + "lat": "40.69764", + "lon": "-3.92253", + "id": 64972109, + "subType": "bridge", + "type": "man_made", + "additionalInfo": { + "bridge_car": "yes", + "ref": "M-607" + } + }, + { + "name": "Carnicería Navacerrada", + "lat": "40.72947", + "lon": "-4.01482", + "id": 6298684474, + "subType": "butcher", + "type": "shop", + "additionalInfo": { + "phone": "+34 91 856 06 60" + } + }, + { + "name": "Parada 17649 Peñalara - Av Navacerrada", + "lat": "40.45939", + "lon": "-3.80052", + "id": 7508826650, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "bench_no": "no", + "covered_no": "no", + "bus_yes": "yes", + "network": "Linea 563 - 656A", + "ref": "17649" + } + }, + { + "name": "Río Navacerrada", + "lat": "40.74012", + "lon": "-3.99430", + "id": 193455251, + "subType": "river", + "type": "natural" + }, + { + "name": "Baltasar Santos - Pto. Navacerrada", + "lat": "40.40194", + "lon": "-3.65729", + "id": 2879406200, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "bus_yes": "yes", + "bench_yes": "yes", + "covered_yes": "yes", + "route_bus_ref": "141", + "ref": "3333", + "operator": "EMT Madrid" + } + }, + { + "name": "Baltasar Santos - Pto. Navacerrada", + "lat": "40.40194", + "lon": "-3.65690", + "id": 2879406204, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "bus_yes": "yes", + "bench_yes": "yes", + "covered_yes": "yes", + "route_bus_ref": "141", + "ref": "3318", + "operator": "EMT Madrid" + } + }, + { + "name": "Estación de Tratamiento de Agua Potable de Navacerrada", + "lat": "40.71319", + "lon": "-4.00578", + "id": 788909087, + "subType": "water_works", + "type": "man_made", + "additionalInfo": { + "operator": "Canal de Isabel II" + } + }, + { + "name": "Estación de Esquí Puerto de Navacerrada", + "lat": "40.78759", + "lon": "-4.00834", + "id": 4410455019520, + "subType": "skiing", + "type": "sport" + }, + { + "name": "Estación de Esquí Puerto de Navacerrada", + "lat": "40.78759", + "lon": "-4.00834", + "id": 4410455019520, + "subType": "ski_resort", + "type": "entertainment" + }, + { + "name": "Alameda Baja-Navacerrada", + "lat": "40.61227", + "lon": "-3.68424", + "id": 14632991214, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "covered_no": "no", + "bus_yes": "yes", + "bench_no": "no" + } + }, + { + "name": "Río Navacerrada", + "lat": "40.70574", + "lon": "-3.91495", + "id": 166715571, + "subType": "river", + "type": "natural", + "additionalInfo": { + "alt_name": "Río Samburiel; Río San Muriel; Río Berrocal" + } + }, + { + "name": "ADESGAM", + "lat": "40.67478", + "lon": "-4.08382", + "id": 489539697, + "subType": "rcn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "Puerto de Navacerrada", + "lat": "40.78923", + "lon": "-4.00342", + "id": 8556022052, + "subType": "viewpoint", + "type": "tourism" + }, + { + "name": "Guardia Civil - GREIM Navacerrada.", + "lat": "40.78727", + "lon": "-4.00158", + "id": 789772209, + "subType": "police", + "type": "emergency", + "additionalInfo": { + "operator": "Ministerio del Interior." + } + }, + { + "name": "Guardia Civil - GREIM Navacerrada.", + "lat": "40.78727", + "lon": "-4.00158", + "id": 789772209, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "operator": "Ministerio del Interior." + } + }, + { + "name": "Río Navacerrada", + "lat": "40.70981", + "lon": "-3.99435", + "id": 166715529, + "subType": "river", + "type": "natural" + }, + { + "name": "Río Navacerrada", + "lat": "40.72427", + "lon": "-4.00134", + "id": 166715649, + "subType": "river", + "type": "natural" + }, + { + "name": "Ctra. M861-Presa de Navacerrada", + "lat": "40.71340", + "lon": "-4.00786", + "id": 6367849404, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "bench_no": "no", + "covered_no": "no", + "bus_yes": "yes", + "website": "https://www.crtm.es/widgets/#/stop/8_10987", + "route_bus_ref": "690, 691, 691 Nocturno, 696", + "ref": "10987", + "operator": "Larrea" + } + }, + { + "name": "Cementerio de Navacerrada", + "lat": "40.73280", + "lon": "-4.01291", + "id": 376766597, + "subType": "cemetery", + "type": "man_made" + }, + { + "name": "Parque de Bomberos - Navacerrada. Nº46.", + "lat": "40.74058", + "lon": "-4.00434", + "id": 401232413, + "subType": "fire_station", + "type": "emergency", + "additionalInfo": { + "operator": "Comunidad de Madrid." + } + }, + { + "name": "Parque de Bomberos - Navacerrada. Nº46.", + "lat": "40.74058", + "lon": "-4.00434", + "id": 401232413, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "operator": "Comunidad de Madrid." + } + }, + { + "name": "Hotel Rural El Torreón de Navacerrada", + "lat": "40.72547", + "lon": "-4.02117", + "id": 400568089, + "subType": "hostel", + "type": "tourism", + "additionalInfo": { + "website": "http://www.eltorreondenavacerrada.com/", + "phone": "+34 900 365 062" + } + }, + { + "name": "Hotel Rural El Torreón de Navacerrada", + "lat": "40.72547", + "lon": "-4.02117", + "id": 400568089, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "website": "http://www.eltorreondenavacerrada.com/", + "phone": "+34 900 365 062" + } + }, + { + "name": "Parque de Navacerrada", + "lat": "40.46048", + "lon": "-3.80616", + "id": 60953689, + "subType": "park", + "type": "entertainment" + }, + { + "name": "ADESGAM", + "lat": "40.67374", + "lon": "-4.08423", + "id": 624211279, + "subType": "rcn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "CIMA MA05-2", + "lat": "40.70958", + "lon": "-4.06666", + "id": 46025413, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "ref": "M-614", + "operator": "CIMA" + } + }, + { + "name": "Escuela de Esquí de Navacerrada", + "lat": "40.78756", + "lon": "-4.00301", + "id": 206884207, + "subType": "school", + "type": "education" + }, + { + "name": "Escuela de Esquí de Navacerrada", + "lat": "40.78756", + "lon": "-4.00301", + "id": 206884207, + "subType": "building", + "type": "man_made" + }, + { + "name": "Consultorio local de Navacerrada", + "lat": "40.72897", + "lon": "-4.01613", + "id": 608506111, + "subType": "clinic", + "type": "healthcare", + "additionalInfo": { + "phone": "+34 91 856 02 94" + } + }, + { + "name": "Consultorio local de Navacerrada", + "lat": "40.72897", + "lon": "-4.01613", + "id": 608506111, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "phone": "+34 91 856 02 94" + } + }, + { + "name": "Embalse del Pueblo de Navacerrada", + "lat": "40.75311", + "lon": "-3.99302", + "id": 75433477, + "subType": "water", + "type": "natural" + }, + { + "name": "Pto. Navacerrada - Vía 2", + "lat": "40.78431", + "lon": "-4.00467", + "id": 6991750080, + "subType": "public_transport_stop_position", + "type": "transportation", + "additionalInfo": { + "operator": "Renfe", + "route_train_ref": "C-9" + } + }, + { + "name": "Calle Marqués de Santillana", + "lat": "40.67533", + "lon": "-4.08329", + "id": 54534529, + "subType": "bridge", + "type": "man_made", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bridge_car": "yes", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "ADESGAM", + "lat": "40.67533", + "lon": "-4.08329", + "id": 54534529, + "subType": "rcn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bridge_car": "yes", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "Estación esquí Puerto de Navacerrada", + "lat": "40.78910", + "lon": "-3.99497", + "id": 1476307709, + "subType": "ski_resort", + "type": "entertainment" + }, + { + "name": "Glorieta de Navacerrada", + "lat": "40.43148", + "lon": "-3.66559", + "id": 120026928, + "subType": "square", + "type": "man_made" + }, + { + "name": "Ayuntamiento de Navacerrada", + "lat": "40.72900", + "lon": "-4.01456", + "id": 376766589, + "subType": "townhall", + "type": "administrative", + "additionalInfo": { + "website": "https://www.aytonavacerrada.org/", + "phone": "+34 91 856 00 06" + } + }, + { + "name": "Ayuntamiento de Navacerrada", + "lat": "40.72900", + "lon": "-4.01456", + "id": 376766589, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "website": "https://www.aytonavacerrada.org/", + "phone": "+34 91 856 00 06" + } + }, + { + "name": "CIMA MA05-2", + "lat": "40.71194", + "lon": "-4.06460", + "id": 794422033, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "ref": "M-614", + "operator": "CIMA" + } + }, + { + "name": "Ctra. M-601-Puerto de Navacerrada", + "lat": "40.78795", + "lon": "-4.00289", + "id": 7568805810, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "bench_no": "no", + "covered_no": "no", + "bus_yes": "yes", + "website": "https://www.crtm.es/widgets/#/stop/8_09195", + "route_bus_ref": "691", + "ref": "09195", + "operator": "Larrea" + } + }, + { + "name": "Residencia Navacerrada", + "lat": "40.78701", + "lon": "-4.00259", + "id": 206884231, + "subType": "hostel", + "type": "tourism", + "additionalInfo": { + "internet_access_type_wlan": "wlan", + "wheelchair_yes": "yes", + "website": "http://www.madrid.org/cs/Satellite?c=CM_InfPractica_FA&cid=1142638848709&pagename=ComunidadMadrid%2FEstructura", + "phone": "+34 91 852 39 84", + "beds": "107", + "email": "residencia.navacerrada@madrid.org", + "operator": "Comunidad de Madrid", + "rooms": "44", + "fax": "+34 91 852 02 68" + } + }, + { + "name": "Residencia Navacerrada", + "lat": "40.78701", + "lon": "-4.00259", + "id": 206884231, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "internet_access_type_wlan": "wlan", + "wheelchair_yes": "yes", + "website": "http://www.madrid.org/cs/Satellite?c=CM_InfPractica_FA&cid=1142638848709&pagename=ComunidadMadrid%2FEstructura", + "phone": "+34 91 852 39 84", + "beds": "107", + "email": "residencia.navacerrada@madrid.org", + "operator": "Comunidad de Madrid", + "rooms": "44", + "fax": "+34 91 852 02 68" + } + }, + { + "name": "Centro Municipal de Mayores «Navacerrada»", + "lat": "40.40118", + "lon": "-3.65658", + "id": 722127199, + "subType": "community_centre", + "type": "entertainment" + }, + { + "name": "Centro Municipal de Mayores «Navacerrada»", + "lat": "40.40118", + "lon": "-3.65658", + "id": 722127199, + "subType": "building", + "type": "man_made" + }, + { + "name": "ADESGAM", + "lat": "40.67395", + "lon": "-4.08410", + "id": 400005635, + "subType": "rcn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "rcn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680, 690", + "ref": "M-614", + "operator": "Larrea" + } + }, + { + "name": "Ctra. M-601-Puerto de Navacerrada", + "lat": "40.78797", + "lon": "-4.00304", + "id": 7568805812, + "subType": "public_transport_platform", + "type": "transportation", + "additionalInfo": { + "bench_no": "no", + "covered_no": "no", + "bus_yes": "yes", + "website": "https://www.crtm.es/widgets/#/stop/8_09199", + "route_bus_ref": "691", + "ref": "09199", + "operator": "Larrea" + } + }, + { + "name": "Residencia Militar de Acción Social de Descanso (RMD) Navacerrada", + "lat": "40.78499", + "lon": "-4.00419", + "id": 478335835, + "subType": "hotel", + "type": "tourism", + "additionalInfo": { + "phone": "+34 91 849 4300", + "operator": "EA", + "fax": "+34 918494315" + } + }, + { + "name": "Residencia Militar de Acción Social de Descanso (RMD) Navacerrada", + "lat": "40.78499", + "lon": "-4.00419", + "id": 478335835, + "subType": "building", + "type": "man_made", + "additionalInfo": { + "phone": "+34 91 849 4300", + "operator": "EA", + "fax": "+34 918494315" + } + }, + { + "name": "Avenida de Navacerrada", + "lat": "40.46202", + "lon": "-3.80327", + "id": 48731007, + "subType": "bridge", + "type": "man_made", + "additionalInfo": { + "bridge_car": "yes", + "route_bus_ref": "563" + } + }, + { + "name": "El Torreón de Navacerrada", + "lat": "40.72547", + "lon": "-4.02108", + "id": 6852071664, + "subType": "restaurant", + "type": "sustenance", + "additionalInfo": { + "website": "http://www.eltorreondenavacerrada.com/", + "phone": "+34 900 365 062", + "mobile": "+34 648 227 909" + } + }, + { + "name": "CIMA MA05-2", + "lat": "40.70444", + "lon": "-4.06938", + "id": 637431653, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680", + "ref": "M-614", + "operator": "CIMA, Larrea" + } + }, + { + "name": "Estación de Navacerrada", + "lat": "40.78444", + "lon": "-4.00475", + "id": 478335833, + "subType": "public_transport_station", + "type": "transportation" + }, + { + "name": "Estación de Navacerrada", + "lat": "40.78444", + "lon": "-4.00475", + "id": 478335833, + "subType": "building", + "type": "man_made" + }, + { + "name": "CIMA MA05-2", + "lat": "40.70496", + "lon": "-4.06904", + "id": 637431651, + "subType": "ncn_ref", + "type": "transportation", + "additionalInfo": { + "surface_asphalt": "asphalt", + "bicycle_yes": "yes", + "network": "ncn", + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada", + "route_bus_ref": "680", + "ref": "M-614", + "operator": "CIMA, Larrea" + } + }, + { + "name": "Puerta de Navacerrada", + "lat": "40.73362", + "lon": "-4.00668", + "id": 8823389690, + "subType": "artwork", + "type": "tourism", + "additionalInfo": { + "artwork_type_sculpture": "sculpture", + "artist_name": "Vicente Palacios" + } + }, + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.70291", + "lon": "-4.00402", + "id": 46814485, + "subType": "bridge", + "type": "man_made", + "additionalInfo": { + "bridge_car": "yes", + "ref": "M-601", + "operator": "CIMA", + "network": "ncn" + } + }, + { + "name": "Río de Navacerrada", + "lat": "40.75946", + "lon": "-3.99336", + "id": 715513915, + "subType": "river", + "type": "natural" + } + ], + "cities": [ + { + "name": "Villa de Vallecas", + "lat": "40.37396", + "lon": "-3.61216", + "id": 316755084, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Calle del Embalse de Navacerrada", + "lat": "40.36299", + "lon": "-3.60289", + "id": 23126, + "intersectedStreets": [ + { + "name": "Calle de José Gutiérrez Maroto", + "lat": "40.36388", + "lon": "-3.60470" + }, + { + "name": "Calle del Embalse de Picadas", + "lat": "40.36347", + "lon": "-3.60384" + }, + { + "name": "Calle del Embalse de La Jarosa", + "lat": "40.36299", + "lon": "-3.60289" + }, + { + "name": "Calle del Embalse de San Juan", + "lat": "40.36138", + "lon": "-3.59959" + }, + { + "name": "Calle del Embalse de Pinilla", + "lat": "40.35943", + "lon": "-3.59564" + }, + { + "name": "Gran Vía del Sureste", + "lat": "40.35843", + "lon": "-3.59365" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Buitrago del Lozoya", + "lat": "40.99535", + "lon": "-3.63505", + "id": 291749136, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Calle Navacerrada", + "lat": "40.98835", + "lon": "-3.63540", + "id": 49557, + "intersectedStreets": [ + { + "name": "Calle Somosierra", + "lat": "40.98813", + "lon": "-3.63564" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Cercedilla", + "lat": "40.74129", + "lon": "-4.05580", + "id": 287860053, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Carretera de Guadarrama a Navacerrada", + "lat": "40.71770", + "lon": "-4.06192", + "id": 33948 + } + ], + "matchStreet": 1 + }, + { + "name": "Salamanca", + "names": { + "ar": "سلامنكا" + }, + "lat": "40.42705", + "lon": "-3.68060", + "id": 365886835, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Calle de Francisco Navacerrada", + "lat": "40.43133", + "lon": "-3.66699", + "id": 12315, + "buildings": [ + { + "name": "50", + "lat": "40.43127", + "lon": "-3.66664", + "postcode": "28028" + }, + { + "name": "52", + "lat": "40.43130", + "lon": "-3.66645", + "postcode": "28028" + }, + { + "name": "53", + "lat": "40.43155", + "lon": "-3.66624", + "postcode": "28028" + }, + { + "name": "54", + "lat": "40.43130", + "lon": "-3.66632", + "postcode": "28028" + }, + { + "name": "55", + "lat": "40.43158", + "lon": "-3.66604", + "postcode": "28028" + }, + { + "name": "56", + "lat": "40.43132", + "lon": "-3.66624", + "postcode": "28028" + }, + { + "name": "57", + "lat": "40.43173", + "lon": "-3.66542", + "postcode": "28028" + }, + { + "name": "58", + "lat": "40.43133", + "lon": "-3.66589", + "postcode": "28028" + }, + { + "name": "59", + "lat": "40.43164", + "lon": "-3.66521", + "postcode": "28028" + }, + { + "name": "60", + "lat": "40.43137", + "lon": "-3.66542", + "postcode": "28028" + }, + { + "name": "62", + "lat": "40.43143", + "lon": "-3.66527", + "postcode": "28028" + }, + { + "name": "63", + "lat": "40.43171", + "lon": "-3.66480", + "postcode": "28028" + }, + { + "name": "64", + "lat": "40.43150", + "lon": "-3.66465", + "postcode": "28028" + } + ], + "intersectedStreets": [ + { + "name": "Calle de Julio Camba", + "lat": "40.43171", + "lon": "-3.66441" + }, + { + "name": "Calle del Cardenal Belluga", + "lat": "40.43150", + "lon": "-3.66561" + }, + { + "name": "Glorieta del Campanar", + "lat": "40.43133", + "lon": "-3.66699" + }, + { + "name": "Calle de Campanar", + "lat": "40.43132", + "lon": "-3.66720" + }, + { + "name": "Calle Cartagena", + "lat": "40.43093", + "lon": "-3.67057" + }, + { + "name": "Calle de Cartagena", + "lat": "40.43093", + "lon": "-3.67057" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "La Poveda", + "lat": "40.31492", + "lon": "-3.47827", + "id": 1779479627, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Calle Puerto de Navacerrada", + "lat": "40.31771", + "lon": "-3.47848", + "id": 51201, + "intersectedStreets": [ + { + "name": "Calle Monte Rosa", + "lat": "40.31695", + "lon": "-3.47964" + }, + { + "name": "Calle Puerto de Somosierra", + "lat": "40.31723", + "lon": "-3.47925" + }, + { + "name": "Calle Puerto de la Morcuera", + "lat": "40.31749", + "lon": "-3.47889" + }, + { + "name": "Calle Puerto de Pajares", + "lat": "40.31772", + "lon": "-3.47848" + }, + { + "name": "Calle Puerto de Contreras", + "lat": "40.31790", + "lon": "-3.47803" + }, + { + "name": "Calle Montes Pirineos", + "lat": "40.31650", + "lon": "-3.48018" + }, + { + "name": "Calle Puerto de Cotos", + "lat": "40.31656", + "lon": "-3.48007" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Polideportivo Dehesa Boyal", + "lat": "40.64154", + "lon": "-4.00246", + "id": 4385398747, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.64118", + "lon": "-4.00557", + "id": 16939 + } + ], + "matchStreet": 1 + }, + { + "name": "Jazmines", + "lat": "40.64216", + "lon": "-4.00733", + "id": 4385398744, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Carretera de Navacerrada", + "lat": "40.64424", + "lon": "-4.00739", + "id": 2270, + "buildings": [ + { + "name": "km0.600", + "lat": "40.64424", + "lon": "-4.00739", + "postcode": "28400" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Manzanares el Real", + "lat": "40.72676", + "lon": "-3.86498", + "id": 200986413, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Carretera de Colmenar Viejo a Navacerrada", + "lat": "40.68646", + "lon": "-3.89476", + "id": 30733, + "intersectedStreets": [ + { + "name": "Cordel de Navalcaide", + "lat": "40.68679", + "lon": "-3.82938" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Collado Mediano", + "lat": "40.69437", + "lon": "-4.02472", + "id": 198062829, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Camino de Los Molinos a Navacerrada", + "lat": "40.71308", + "lon": "-4.05142", + "id": 53626, + "intersectedStreets": [ + { + "name": "Calle de las Pozas (Reajo del Roble)", + "lat": "40.71439", + "lon": "-4.01891" + }, + { + "name": "Avenida Lago", + "lat": "40.71439", + "lon": "-4.01891" + } + ] + }, + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.68539", + "lon": "-4.01346", + "id": 13946, + "buildings": [ + { + "name": "Km 7", + "lat": "40.70254", + "lon": "-4.00368", + "postcode": "28450" + } + ], + "intersectedStreets": [ + { + "name": "Avenida de Buenos Aires", + "lat": "40.68524", + "lon": "-4.01381" + }, + { + "name": "Camino de Navacerrada (Serranía de la Paloma)", + "lat": "40.70834", + "lon": "-4.00555" + } + ] + }, + { + "name": "Camino de Navacerrada (Serranía de la Paloma)", + "lat": "40.70426", + "lon": "-4.00756", + "id": 36508, + "intersectedStreets": [ + { + "name": "Calle Los Abetos (Serranía de la Paloma)", + "lat": "40.70478", + "lon": "-4.00726" + }, + { + "name": "Calle Tejera (Serranía de la Paloma)", + "lat": "40.70490", + "lon": "-4.00726" + }, + { + "name": "Calle Begoña (Serranía de la Paloma)", + "lat": "40.70550", + "lon": "-4.00735" + }, + { + "name": "Calle de Cotos (Serranía de la Paloma)", + "lat": "40.70550", + "lon": "-4.00735" + }, + { + "name": "Calle Pilar (Serranía de la Paloma)", + "lat": "40.70673", + "lon": "-4.00675" + }, + { + "name": "Calle Somosierra (Serranía de la Paloma)", + "lat": "40.70737", + "lon": "-4.00651" + }, + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.70833", + "lon": "-4.00555" + }, + { + "name": "Calle Ignacio", + "lat": "40.70830", + "lon": "-4.00574" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Las Nieves", + "lat": "40.34919", + "lon": "-3.88357", + "id": 1482408061, + "type": "HAMLET", + "listOfStreets": [ + { + "name": "Calle del Puerto de Navacerrada", + "lat": "40.34908", + "lon": "-3.88234", + "id": 54919, + "buildings": [ + { + "name": "94", + "lat": "40.34898", + "lon": "-3.88139" + }, + { + "name": "102", + "lat": "40.34910", + "lon": "-3.88234" + }, + { + "name": "104", + "lat": "40.34921", + "lon": "-3.88262" + }, + { + "name": "106", + "lat": "40.34926", + "lon": "-3.88281" + }, + { + "name": "108", + "lat": "40.34946", + "lon": "-3.88294" + }, + { + "name": "110", + "lat": "40.34950", + "lon": "-3.88311" + }, + { + "name": "112", + "lat": "40.34941", + "lon": "-3.88335" + }, + { + "name": "114", + "lat": "40.34955", + "lon": "-3.88345" + }, + { + "name": "116", + "lat": "40.34957", + "lon": "-3.88367" + }, + { + "name": "118", + "lat": "40.34957", + "lon": "-3.88390" + }, + { + "name": "120", + "lat": "40.34955", + "lon": "-3.88414" + }, + { + "name": "122", + "lat": "40.34965", + "lon": "-3.88446" + }, + { + "name": "126", + "lat": "40.34980", + "lon": "-3.88472" + }, + { + "name": "128", + "lat": "40.34980", + "lon": "-3.88508" + } + ], + "intersectedStreets": [ + { + "name": "Calle del Puerto de la Cruz Verde", + "lat": "40.34973", + "lon": "-3.88575" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Becerril de la Sierra", + "lat": "40.71634", + "lon": "-3.98907", + "id": 198062823, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Carretera de Colmenar Viejo a Navacerrada", + "lat": "40.68160", + "lon": "-3.86704", + "id": 58412 + }, + { + "name": "Calle Navacerrada", + "lat": "40.71101", + "lon": "-3.99834", + "id": 36184, + "intersectedStreets": [ + { + "name": "Calle Campuzano", + "lat": "40.71124", + "lon": "-3.99911" + }, + { + "name": "Calle Marqués de Santillana", + "lat": "40.71129", + "lon": "-3.99754" + }, + { + "name": "Calle del Caz", + "lat": "40.71129", + "lon": "-3.99754" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Roman Candelas", + "lat": "40.62944", + "lon": "-4.02360", + "id": 4328359686, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Calle Puerto de Navacerrada", + "lat": "40.63021", + "lon": "-4.02261", + "id": 17879, + "intersectedStreets": [ + { + "name": "Paseo del Río Guadarrama", + "lat": "40.63021", + "lon": "-4.02261" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Cerca de Cascarrilla", + "lat": "40.65262", + "lon": "-4.01000", + "id": 4328359659, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.65295", + "lon": "-4.00853", + "id": 16936, + "intersectedStreets": [ + { + "name": "Rotonda del Lobo Cojo", + "lat": "40.65163", + "lon": "-4.00866" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Dehesa Boyal", + "lat": "40.64003", + "lon": "-4.00020", + "id": 4328359661, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.64037", + "lon": "-4.00544", + "id": 16941, + "intersectedStreets": [ + { + "name": "Carretera de La Granja", + "lat": "40.63947", + "lon": "-4.00557" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Puente de Vallecas", + "enName": "Vallecas", + "lat": "40.38686", + "lon": "-3.65918", + "id": 316750327, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Calle del Puerto de Navacerrada", + "lat": "40.39972", + "lon": "-3.65789", + "id": 10385, + "buildings": [ + { + "name": "1", + "lat": "40.40119", + "lon": "-3.65662", + "postcode": "28038" + }, + { + "name": "17", + "lat": "40.39972", + "lon": "-3.65789", + "postcode": "28038" + } + ], + "intersectedStreets": [ + { + "name": "Camino de Valderribas", + "lat": "40.39843", + "lon": "-3.65873" + }, + { + "name": "Calle Alto del León", + "lat": "40.39938", + "lon": "-3.65823" + }, + { + "name": "Calle Puerto de Canencia", + "lat": "40.40020", + "lon": "-3.65780" + }, + { + "name": "Calle Sierra de Cuerda Larga", + "lat": "40.40100", + "lon": "-3.65740" + }, + { + "name": "Calle de Baltasar Santos", + "lat": "40.40190", + "lon": "-3.65695" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Las Suertes", + "lat": "40.62089", + "lon": "-4.00423", + "id": 4327015634, + "type": "SUBURB", + "listOfStreets": [ + { + "name": "Calle Navacerrada (Urb. Las Suertes)", + "lat": "40.62377", + "lon": "-4.00347", + "id": 18728, + "buildings": [ + { + "name": "1", + "lat": "40.62343", + "lon": "-4.00368", + "postcode": "28400" + }, + { + "name": "2", + "lat": "40.62358", + "lon": "-4.00351", + "postcode": "28400" + }, + { + "name": "3", + "lat": "40.62353", + "lon": "-4.00321", + "postcode": "28400" + }, + { + "name": "4", + "lat": "40.62333", + "lon": "-4.00314", + "postcode": "28400" + }, + { + "name": "5", + "lat": "40.62330", + "lon": "-4.00284", + "postcode": "28400" + }, + { + "name": "6", + "lat": "40.62348", + "lon": "-4.00265", + "postcode": "28400" + }, + { + "name": "7", + "lat": "40.62345", + "lon": "-4.00235", + "postcode": "28400" + }, + { + "name": "8", + "lat": "40.62364", + "lon": "-4.00274", + "postcode": "28400" + }, + { + "name": "17", + "lat": "40.62399", + "lon": "-4.00355", + "postcode": "28400" + }, + { + "name": "18", + "lat": "40.62420", + "lon": "-4.00319", + "postcode": "28400" + }, + { + "name": "19", + "lat": "40.62403", + "lon": "-4.00299", + "postcode": "28400" + } + ], + "intersectedStreets": [ + { + "name": "Avenida Las Suertes", + "lat": "40.62384", + "lon": "-4.00389" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Bustarviejo", + "names": { + "ru": "Бустарвьехо" + }, + "lat": "40.85867", + "lon": "-3.71015", + "id": 310996890, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Calle Navacerrada (El Pedregal)", + "lat": "40.86253", + "lon": "-3.70147", + "id": 37253, + "intersectedStreets": [ + { + "name": "Calle Canencia", + "lat": "40.86211", + "lon": "-3.70398" + }, + { + "name": "Calle Prado Redondo (El Pedregal)", + "lat": "40.86253", + "lon": "-3.70147" + }, + { + "name": "Calle María de las Casas", + "lat": "40.86253", + "lon": "-3.70147" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "El Baillo y las Hojarascas", + "lat": "40.74321", + "lon": "-4.04124", + "id": 1482405188, + "type": "HAMLET", + "listOfStreets": [ + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.75496", + "lon": "-4.02076", + "id": 52475 + } + ], + "matchStreet": 1 + }, + { + "name": "El Boalo", + "lat": "40.71735", + "lon": "-3.92025", + "id": 174984610, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Carretera de Navacerrada", + "lat": "40.70197", + "lon": "-3.94332", + "id": 13564, + "intersectedStreets": [ + { + "name": "Avenida Central", + "lat": "40.70211", + "lon": "-3.94300" + }, + { + "name": "Calle Cerrillo Agustín", + "lat": "40.70072", + "lon": "-3.94120" + }, + { + "name": "Calle Depósito", + "lat": "40.70068", + "lon": "-3.94104" + }, + { + "name": "Calle Prado Gómez", + "lat": "40.70104", + "lon": "-3.94165" + }, + { + "name": "Carretera de Colmenar Viejo a Navacerrada (Cerceda)", + "lat": "40.69964", + "lon": "-3.93158" + }, + { + "name": "Calle Pajar Madedero", + "lat": "40.69995", + "lon": "-3.93641" + }, + { + "name": "Calle Becerril", + "lat": "40.69980", + "lon": "-3.93534" + }, + { + "name": "Carretera de Cerceda-Moralzarzal (San Muriel)", + "lat": "40.70013", + "lon": "-3.93746" + } + ] + }, + { + "name": "Carretera de Colmenar Viejo a Navacerrada (Cerceda)", + "lat": "40.69863", + "lon": "-3.92778", + "id": 11811, + "intersectedStreets": [ + { + "name": "Carretera de Cerceda a Manzanares", + "names": { + "alt_name": "Paseo de Madrid" + }, + "lat": "40.69976", + "lon": "-3.93122" + }, + { + "name": "Carretera de Navacerrada", + "lat": "40.69964", + "lon": "-3.93158" + }, + { + "name": "Calle Granito (San Muriel)", + "lat": "40.69828", + "lon": "-3.92472" + }, + { + "name": "Avenida de los Canteros (Cerceda)", + "lat": "40.69935", + "lon": "-3.93156" + } + ] + }, + { + "name": "Calle Navacerrada (Cerceda)", + "lat": "40.69845", + "lon": "-3.92768", + "id": 39122, + "intersectedStreets": [ + { + "name": "Calle Vista Nieve", + "lat": "40.69845", + "lon": "-3.92768" + }, + { + "name": "Calle Colmenar (Cerceda)", + "lat": "40.69793", + "lon": "-3.93010" + }, + { + "name": "Calle Guadarrama (San Muriel)", + "lat": "40.70132", + "lon": "-3.92931" + }, + { + "name": "Calle Navafría (San Muriel)", + "lat": "40.70172", + "lon": "-3.92866" + }, + { + "name": "Calle Pedriza (Montes Claros)", + "lat": "40.70210", + "lon": "-3.92789" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Navacerrada", + "lat": "40.72879", + "lon": "-4.01517", + "id": 256604278, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Avenida de Madrid", + "lat": "40.72871", + "lon": "-4.01643", + "id": 2175 + }, + { + "name": "Calle Antonio Buero Vallejo", + "lat": "40.72181", + "lon": "-4.01836", + "id": 36357 + }, + { + "name": "Calle Barrio de las Peñas", + "lat": "40.72849", + "lon": "-4.01349", + "id": 6847 + }, + { + "name": "Calle Canto Gordo", + "lat": "40.72085", + "lon": "-4.01499", + "id": 36366 + }, + { + "name": "Calle Dos Castillas", + "lat": "40.78860", + "lon": "-4.00271", + "id": 40864 + }, + { + "name": "Calle Fernando Vizcaíno Casas", + "lat": "40.72836", + "lon": "-4.01849", + "id": 36397 + }, + { + "name": "Calle Fuenlabrada", + "lat": "40.72833", + "lon": "-4.01711", + "id": 5985 + }, + { + "name": "Calle Linar", + "lat": "40.73158", + "lon": "-4.01615", + "id": 9435 + }, + { + "name": "Calle Miguel Antón", + "lat": "40.73077", + "lon": "-4.01926", + "id": 49790 + }, + { + "name": "Calle de Abel", + "lat": "40.73088", + "lon": "-4.01565", + "id": 1914 + }, + { + "name": "Calle de Andrés Segovia", + "lat": "40.72848", + "lon": "-4.01849", + "id": 36394 + }, + { + "name": "Calle de la Audiencia", + "lat": "40.72869", + "lon": "-4.01449", + "id": 8954 + }, + { + "name": "Calle de la Encinilla", + "lat": "40.72991", + "lon": "-4.01501", + "id": 2469 + }, + { + "name": "Calle de la Iglesia", + "lat": "40.72932", + "lon": "-4.01495", + "id": 2468 + }, + { + "name": "Calle de la Magdalena", + "lat": "40.72832", + "lon": "-4.01342", + "id": 6848 + }, + { + "name": "Calle de la Perdiz", + "lat": "40.73328", + "lon": "-4.00353", + "id": 36400 + }, + { + "name": "Calle de la Tejera", + "lat": "40.72645", + "lon": "-4.02040", + "id": 6815 + }, + { + "name": "Calle de las Escuelas", + "lat": "40.72791", + "lon": "-4.01591", + "id": 8329 + }, + { + "name": "Calle de los Arcos", + "lat": "40.73129", + "lon": "-4.02040", + "id": 36868 + }, + { + "name": "Calle de Álvaro Iglesia", + "lat": "40.73513", + "lon": "-4.01134", + "id": 36411 + }, + { + "name": "Calle del Cuartel", + "lat": "40.72958", + "lon": "-4.01432", + "id": 3521 + }, + { + "name": "Calle del Halcón", + "lat": "40.73415", + "lon": "-4.00387", + "id": 36393 + }, + { + "name": "Calle del Mayo", + "lat": "40.72919", + "lon": "-4.01520", + "id": 6000 + }, + { + "name": "Calle del Águila", + "lat": "40.73267", + "lon": "-4.00274", + "id": 36414 + }, + { + "name": "Camino de la Tubería", + "lat": "40.77937", + "lon": "-3.99460", + "id": 33047 + }, + { + "name": "Camino del Calvario", + "lat": "40.74797", + "lon": "-4.03372", + "id": 35661 + }, + { + "name": "Camino del Dedo", + "lat": "40.72718", + "lon": "-3.99801", + "id": 58961 + }, + { + "name": "Camino del Río", + "lat": "40.73563", + "lon": "-4.00188", + "id": 36308 + }, + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.73397", + "lon": "-4.02005", + "id": 31367 + }, + { + "name": "Carretera de Guadarrama a Navacerrada", + "lat": "40.73402", + "lon": "-4.02205", + "id": 35662 + }, + { + "name": "GR-10", + "lat": "40.74550", + "lon": "-4.03284", + "id": 34099 + }, + { + "name": "La Bola del Mundo", + "lat": "40.78389", + "lon": "-3.99113", + "id": 40865 + }, + { + "name": "PR-M 16", + "lat": "40.78007", + "lon": "-3.97435", + "id": 55578 + }, + { + "name": "Paseo de la Magdalena", + "lat": "40.72484", + "lon": "-4.01113", + "id": 36415 + }, + { + "name": "Plaza del Álamo", + "lat": "40.72893", + "lon": "-4.01424", + "id": 6001 + }, + { + "name": "Travesía de la Tejera", + "lat": "40.72438", + "lon": "-4.02140", + "id": 36354 + }, + { + "name": "Travesía de las Huertas", + "lat": "40.72864", + "lon": "-4.01374", + "id": 3500 + }, + { + "name": "Travesía del Cuartel", + "lat": "40.72937", + "lon": "-4.01419", + "id": 36386 + }, + { + "name": "Travesía del Rosal", + "lat": "40.71997", + "lon": "-4.01449", + "id": 36356 + }, + { + "name": "Vereda de las Encinillas", + "lat": "40.78098", + "lon": "-4.02091", + "id": 17270 + }, + { + "name": "Whistler", + "lat": "40.77357", + "lon": "-4.01132", + "id": 35918 + }, + { + "name": "Calle Amanecer (Uranización Los Corales)", + "lat": "40.73220", + "lon": "-4.00503", + "id": 36403 + }, + { + "name": "Calle Atardecer (Uranización Los Corales)", + "lat": "40.73261", + "lon": "-4.00746", + "id": 5476 + }, + { + "name": "Calle Lucero (Uranización Los Corales)", + "lat": "40.73095", + "lon": "-4.00527", + "id": 36405 + }, + { + "name": "Calle Manzanares (Residencial Sanabria)", + "lat": "40.73014", + "lon": "-4.01102", + "id": 1670 + }, + { + "name": "Calle Orión (Uranización Los Corales)", + "lat": "40.73173", + "lon": "-4.00724", + "id": 5477 + }, + { + "name": "Calle Poniente (Uranización Los Corales)", + "lat": "40.73295", + "lon": "-4.00621", + "id": 36422 + }, + { + "name": "Calle de Carmen Conde (Residencial Sanabria)", + "lat": "40.72986", + "lon": "-4.01374", + "id": 36404 + }, + { + "name": "Calle de San Sebastián (Residencial Sanabria)", + "lat": "40.73280", + "lon": "-4.01520", + "id": 8330 + }, + { + "name": "Calle de la Bola del Mundo (Residencial Sanabria)", + "lat": "40.72729", + "lon": "-4.01218", + "id": 6854 + }, + { + "name": "Calle de la Canaleja (Residencial Sanabria)", + "lat": "40.73053", + "lon": "-4.01428", + "id": 6974 + }, + { + "name": "Calle de la Maliciosa (Residencial Sanabria)", + "lat": "40.72801", + "lon": "-4.01166", + "id": 6853 + }, + { + "name": "Calle de las Cruces (Residencial Sanabria)", + "lat": "40.72941", + "lon": "-4.01265", + "id": 5792 + }, + { + "name": "Calle de las Eras (Uranización Los Corales)", + "lat": "40.73121", + "lon": "-4.00964", + "id": 3395, + "buildings": [ + { + "name": "1", + "lat": "40.73123", + "lon": "-4.00997", + "postcode": "28491" + }, + { + "name": "2", + "lat": "40.73121", + "lon": "-4.00964", + "postcode": "28491" + }, + { + "name": "3", + "lat": "40.73154", + "lon": "-4.00958", + "postcode": "28491" + }, + { + "name": "4", + "lat": "40.73181", + "lon": "-4.00874", + "postcode": "28491" + }, + { + "name": "5", + "lat": "40.73163", + "lon": "-4.00943", + "postcode": "28491" + }, + { + "name": "6", + "lat": "40.73186", + "lon": "-4.00859", + "postcode": "28491" + }, + { + "name": "7", + "lat": "40.73173", + "lon": "-4.00932", + "postcode": "28491" + }, + { + "name": "8", + "lat": "40.73197", + "lon": "-4.00855", + "postcode": "28491" + }, + { + "name": "9", + "lat": "40.73183", + "lon": "-4.00924" + }, + { + "name": "10", + "lat": "40.73222", + "lon": "-4.00801", + "postcode": "28491" + }, + { + "name": "11", + "lat": "40.73214", + "lon": "-4.00874", + "postcode": "28491" + }, + { + "name": "12", + "lat": "40.73227", + "lon": "-4.00797", + "postcode": "28491" + }, + { + "name": "13", + "lat": "40.73220", + "lon": "-4.00859", + "postcode": "28491" + }, + { + "name": "14", + "lat": "40.73269", + "lon": "-4.00748", + "postcode": "28491" + }, + { + "name": "15", + "lat": "40.73223", + "lon": "-4.00849", + "postcode": "28491" + }, + { + "name": "16", + "lat": "40.73272", + "lon": "-4.00741", + "postcode": "28491" + }, + { + "name": "17", + "lat": "40.73228", + "lon": "-4.00840", + "postcode": "28491" + }, + { + "name": "18", + "lat": "40.73275", + "lon": "-4.00726", + "postcode": "28491" + }, + { + "name": "19", + "lat": "40.73235", + "lon": "-4.00855", + "postcode": "28491" + }, + { + "name": "20", + "lat": "40.73280", + "lon": "-4.00735", + "postcode": "28491" + }, + { + "name": "21", + "lat": "40.73241", + "lon": "-4.00831", + "postcode": "28491" + }, + { + "name": "22", + "lat": "40.73284", + "lon": "-4.00711", + "postcode": "28491" + }, + { + "name": "24", + "lat": "40.73288", + "lon": "-4.00731", + "postcode": "28491" + }, + { + "name": "26", + "lat": "40.73292", + "lon": "-4.00711", + "postcode": "28491" + }, + { + "name": "28", + "lat": "40.73297", + "lon": "-4.00720", + "postcode": "28491" + }, + { + "name": "30", + "lat": "40.73300", + "lon": "-4.00703", + "postcode": "28491" + }, + { + "name": "32", + "lat": "40.73305", + "lon": "-4.00709", + "postcode": "28491" + }, + { + "name": "34", + "lat": "40.73308", + "lon": "-4.00688", + "postcode": "28491" + }, + { + "name": "36", + "lat": "40.73313", + "lon": "-4.00686", + "postcode": "28491" + } + ], + "intersectedStreets": [ + { + "name": "Pasaje de las Eras (Uranización Los Corales)", + "lat": "40.73139", + "lon": "-4.00958" + }, + { + "name": "Travesía de los Robles", + "lat": "40.73163", + "lon": "-4.00924" + }, + { + "name": "Plaza del Gargantón (Residencial Sanabria)", + "lat": "40.73092", + "lon": "-4.01020" + }, + { + "name": "Calle de los Robles (Uranización Los Corales)", + "lat": "40.73111", + "lon": "-4.00992" + }, + { + "name": "Calle del Sotillo (Uranización Los Corales)", + "lat": "40.73184", + "lon": "-4.00894" + }, + { + "name": "Calle los Corrales", + "lat": "40.73220", + "lon": "-4.00844" + }, + { + "name": "Travesía del Sotillo", + "lat": "40.73246", + "lon": "-4.00808" + }, + { + "name": "Calle Atardecer (Uranización Los Corales)", + "lat": "40.73272", + "lon": "-4.00771" + } + ] + }, + { + "name": "Calle de las Huertas (Residencial Sanabria)", + "lat": "40.72934", + "lon": "-4.01364", + "id": 5659 + }, + { + "name": "Calle de los Enebros (Uranización Los Corales)", + "lat": "40.72993", + "lon": "-4.00703", + "id": 36417 + }, + { + "name": "Calle de los Pradillos (Residencial Sanabria)", + "lat": "40.73202", + "lon": "-4.01314", + "id": 6970 + }, + { + "name": "Calle de los Robles (Uranización Los Corales)", + "lat": "40.73054", + "lon": "-4.00471", + "id": 36387 + }, + { + "name": "Calle del Cóndor (Uranización Los Corales)", + "lat": "40.73315", + "lon": "-4.00568", + "id": 36313 + }, + { + "name": "Calle del Nogal (Residencial Sanabria)", + "lat": "40.73040", + "lon": "-4.01183", + "id": 36416 + }, + { + "name": "Calle del Santísimo (Residencial Sanabria)", + "lat": "40.73036", + "lon": "-4.01394", + "id": 8952 + }, + { + "name": "Calle del Sol Naciente (Uranización Los Corales)", + "lat": "40.73152", + "lon": "-4.00600", + "id": 36406 + }, + { + "name": "Calle del Sotillo (Uranización Los Corales)", + "lat": "40.73277", + "lon": "-4.01098", + "id": 6972 + }, + { + "name": "Calle la Granja (Uranización Los Corales)", + "lat": "40.72994", + "lon": "-4.00501", + "id": 36385 + }, + { + "name": "Calle los Acebos (Uranización Los Corales)", + "lat": "40.72971", + "lon": "-4.00377", + "id": 36419 + }, + { + "name": "Pasaje de las Eras (Uranización Los Corales)", + "lat": "40.73223", + "lon": "-4.00954", + "id": 5479, + "buildings": [ + { + "name": "1", + "lat": "40.73154", + "lon": "-4.00986", + "postcode": "28491" + }, + { + "name": "2", + "lat": "40.73162", + "lon": "-4.00969", + "postcode": "28491" + }, + { + "name": "3", + "lat": "40.73165", + "lon": "-4.01003", + "postcode": "28491" + }, + { + "name": "4", + "lat": "40.73170", + "lon": "-4.00982", + "postcode": "28491" + }, + { + "name": "5", + "lat": "40.73223", + "lon": "-4.00954", + "postcode": "28491" + }, + { + "name": "6", + "lat": "40.73175", + "lon": "-4.00975", + "postcode": "28491" + }, + { + "name": "8", + "lat": "40.73176", + "lon": "-4.00958", + "postcode": "28491" + }, + { + "name": "10", + "lat": "40.73183", + "lon": "-4.00969", + "postcode": "28491" + }, + { + "name": "12", + "lat": "40.73188", + "lon": "-4.00954", + "postcode": "28491" + }, + { + "name": "14", + "lat": "40.73191", + "lon": "-4.00947", + "postcode": "28491" + } + ], + "intersectedStreets": [ + { + "name": "Calle del Sotillo (Uranización Los Corales)", + "lat": "40.73225", + "lon": "-4.00945" + }, + { + "name": "Calle de las Eras (Uranización Los Corales)", + "lat": "40.73137", + "lon": "-4.00958" + } + ] + }, + { + "name": "Plaza del Gargantón (Residencial Sanabria)", + "lat": "40.73071", + "lon": "-4.01074", + "id": 1673 + }, + { + "name": "Avenida del Rosal", + "lat": "40.72097", + "lon": "-4.01353", + "id": 6818 + }, + { + "name": "Barrio de la Fragua", + "lat": "40.73075", + "lon": "-4.01282", + "id": 3408 + }, + { + "name": "Calle Cuarto Creciente", + "lat": "40.73095", + "lon": "-4.00527", + "id": 48420 + }, + { + "name": "Calle Cuarto Menguante", + "lat": "40.73087", + "lon": "-4.00329", + "id": 36396 + }, + { + "name": "Calle Doctor Julio González Villasante", + "lat": "40.72913", + "lon": "-4.01716", + "id": 5660 + }, + { + "name": "Calle Huertona", + "lat": "40.73210", + "lon": "-4.01685", + "id": 36401 + }, + { + "name": "Calle Luna Llena", + "lat": "40.73144", + "lon": "-4.00398", + "id": 36418 + }, + { + "name": "Calle Luna Nueva", + "lat": "40.73129", + "lon": "-4.00553", + "id": 36413 + }, + { + "name": "Calle Namadilla", + "lat": "40.72700", + "lon": "-4.01239", + "id": 6851 + }, + { + "name": "Calle Praderas de San Sebastián", + "lat": "40.72832", + "lon": "-4.02057", + "id": 36402 + }, + { + "name": "Calle Prado Rubia", + "lat": "40.72757", + "lon": "-4.01269", + "id": 6852 + }, + { + "name": "Calle Presbítero Blanco", + "lat": "40.73136", + "lon": "-4.01310", + "id": 36391 + }, + { + "name": "Calle Saúco", + "lat": "40.73155", + "lon": "-4.01117", + "id": 6955 + }, + { + "name": "Calle de Prado Jerez", + "lat": "40.72838", + "lon": "-4.01555", + "id": 1908 + }, + { + "name": "Calle de Rafael Alvarado", + "lat": "40.72819", + "lon": "-4.01868", + "id": 36398 + }, + { + "name": "Calle de Ángel Rojas", + "lat": "40.72129", + "lon": "-4.01713", + "id": 36370 + }, + { + "name": "Calle del Arzobispado", + "lat": "40.73072", + "lon": "-4.01353", + "id": 49624 + }, + { + "name": "Calle del Párroco Desiderio García", + "lat": "40.73339", + "lon": "-4.01900", + "id": 36869 + }, + { + "name": "Calle del Señor Rubio", + "lat": "40.72872", + "lon": "-4.01398", + "id": 2470 + }, + { + "name": "Calle del Trigal", + "lat": "40.72936", + "lon": "-4.00490", + "id": 36399 + }, + { + "name": "Calle la Longuera", + "lat": "40.72921", + "lon": "-4.00336", + "id": 36409 + }, + { + "name": "Calle las Jaras", + "lat": "40.72858", + "lon": "-4.01385", + "id": 49623 + }, + { + "name": "Calle los Corrales", + "lat": "40.73191", + "lon": "-4.00842", + "id": 36408 + }, + { + "name": "Calle los Fresnos", + "lat": "40.72910", + "lon": "-4.00413", + "id": 36421 + }, + { + "name": "Camino Sur de la Maliciosa", + "lat": "40.76727", + "lon": "-3.96892", + "id": 55411 + }, + { + "name": "Carretera M-607", + "lat": "40.73292", + "lon": "-3.99484", + "id": 10727 + }, + { + "name": "Carretera de la Barranca", + "lat": "40.74207", + "lon": "-4.00351", + "id": 13632 + }, + { + "name": "PR-M 26", + "lat": "40.77368", + "lon": "-3.98319", + "id": 30601 + }, + { + "name": "Paseo de la Longuera", + "lat": "40.72593", + "lon": "-4.00321", + "id": 46080 + }, + { + "name": "Paseo de los Abetos", + "lat": "40.72254", + "lon": "-4.01960", + "id": 36347 + }, + { + "name": "Paseo de los Españoles", + "lat": "40.72804", + "lon": "-4.01643", + "id": 5728 + }, + { + "name": "Plaza de la Canaleja", + "lat": "40.73116", + "lon": "-4.01503", + "id": 9516 + }, + { + "name": "Plaza de los Ángeles", + "lat": "40.72921", + "lon": "-4.01456", + "id": 1669 + }, + { + "name": "Plaza del Doctor Gereda", + "lat": "40.72875", + "lon": "-4.01486", + "id": 2467 + }, + { + "name": "SLMN-4", + "lat": "40.76411", + "lon": "-3.98954", + "id": 57164 + }, + { + "name": "Senda Alakan", + "lat": "40.76455", + "lon": "-3.99437", + "id": 30603 + }, + { + "name": "Sendero Local", + "lat": "40.75508", + "lon": "-4.00329", + "id": 57821 + }, + { + "name": "Travesía de Abel", + "lat": "40.73049", + "lon": "-4.01458", + "id": 46084 + }, + { + "name": "Travesía de Prado Jerez", + "lat": "40.72788", + "lon": "-4.01518", + "id": 8953 + }, + { + "name": "Travesía de la Audiencia", + "lat": "40.72828", + "lon": "-4.01385", + "id": 36407 + }, + { + "name": "Travesía de la Encinilla", + "lat": "40.72941", + "lon": "-4.01516", + "id": 5802 + }, + { + "name": "Travesía de los Abetos", + "lat": "40.71879", + "lon": "-4.01527", + "id": 6819 + }, + { + "name": "Travesía de los Robles", + "lat": "40.73136", + "lon": "-4.00810", + "id": 5480 + }, + { + "name": "Travesía del Santísimo", + "lat": "40.72975", + "lon": "-4.01413", + "id": 5794 + }, + { + "name": "Travesía del Sotillo", + "lat": "40.73232", + "lon": "-4.00898", + "id": 5478 + }, + { + "name": "Trialera del Escorpión", + "lat": "40.75031", + "lon": "-4.02840", + "id": 45720 + }, + { + "name": "Urbanización Prado Molero", + "lat": "40.73007", + "lon": "-4.01831", + "id": 36389 + }, + { + "name": "Urbanización el Manantial", + "lat": "40.72531", + "lon": "-4.01778", + "id": 36392 + }, + { + "name": "Urbanización la Garza", + "lat": "40.72937", + "lon": "-4.01688", + "id": 36388 + }, + { + "name": "Urbanización las Brisas", + "lat": "40.73036", + "lon": "-4.01724", + "id": 36420 + }, + { + "name": "Urbanización las Brisas Manzana A", + "lat": "40.73072", + "lon": "-4.01685", + "id": 36412 + }, + { + "name": "Urbanización las Brisas Manzana B", + "lat": "40.73040", + "lon": "-4.01692", + "id": 36395 + }, + { + "name": "Urbanización las Brisas Manzana C", + "lat": "40.73020", + "lon": "-4.01670", + "id": 55675 + }, + { + "name": "Urbanización las Brisas Manzana D", + "lat": "40.72991", + "lon": "-4.01643", + "id": 55674 + }, + { + "name": "Urbanización las Brisas Manzana E", + "lat": "40.72978", + "lon": "-4.01705", + "id": 36410 + } + ], + "matchCity": 1, + "matchStreet": 1 + }, + { + "name": "Los Molinos", + "lat": "40.71481", + "lon": "-4.07423", + "id": 198063628, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Carretera de Guadarrama a Navacerrada", + "lat": "40.71238", + "lon": "-4.06451", + "id": 13947, + "intersectedStreets": [ + { + "name": "Avenida de la Concordia", + "names": { + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada" + }, + "lat": "40.71228", + "lon": "-4.06451" + }, + { + "name": "Travesía Eduardo López Palop", + "lat": "40.71373", + "lon": "-4.06440" + } + ] + }, + { + "name": "Avenida de la Concordia", + "names": { + "alt_name": "Carretera de Guadarrama (AP-6) a Navacerrada" + }, + "lat": "40.70960", + "lon": "-4.06666", + "id": 13948, + "intersectedStreets": [ + { + "name": "Calle Arizona", + "lat": "40.71143", + "lon": "-4.06505" + }, + { + "name": "Calle del Olmo", + "lat": "40.71100", + "lon": "-4.06546" + }, + { + "name": "Travesía de Majalastablas", + "lat": "40.71052", + "lon": "-4.06586" + }, + { + "name": "Calle de Santa Engracia", + "lat": "40.70960", + "lon": "-4.06666" + }, + { + "name": "Calle San Pascual", + "lat": "40.70869", + "lon": "-4.06745" + }, + { + "name": "Paseo Miguel Menéndez Boneta", + "lat": "40.70725", + "lon": "-4.06818" + }, + { + "name": "Calle Pedro Gutiérrez", + "lat": "40.70725", + "lon": "-4.06818" + }, + { + "name": "Carretera de Guadarrama a Navacerrada", + "lat": "40.71230", + "lon": "-4.06451" + }, + { + "name": "Avenida de los Molinos", + "lat": "40.71218", + "lon": "-4.06475" + }, + { + "name": "Calle de la Capilla", + "lat": "40.70649", + "lon": "-4.06848" + }, + { + "name": "Calle San Joaquín (Matarrubia)", + "lat": "40.70603", + "lon": "-4.06868" + }, + { + "name": "Calle Matarrubias", + "lat": "40.70447", + "lon": "-4.06940" + }, + { + "name": "Calle San Agustín", + "lat": "40.70366", + "lon": "-4.06988" + }, + { + "name": "Calle Buenos Aires (Matarrubia)", + "lat": "40.70366", + "lon": "-4.06988" + }, + { + "name": "Calle Miralmonte", + "lat": "40.70280", + "lon": "-4.07041" + }, + { + "name": "Calle Bellas Vistas", + "lat": "40.70154", + "lon": "-4.07110" + }, + { + "name": "Calle del Río Guadalquivir (Matarrubia)", + "lat": "40.70073", + "lon": "-4.07157" + }, + { + "name": "Calle Río Duero (Matarrubia)", + "lat": "40.69980", + "lon": "-4.07204" + } + ] + } + ], + "matchStreet": 1 + }, + { + "name": "Puerto de Navacerrada", + "lat": "40.78629", + "lon": "-4.00266", + "id": 303570891, + "type": "HAMLET", + "listOfStreets": [ + { + "name": "Calle Dos Castillas", + "lat": "40.78782", + "lon": "-4.00201", + "id": 59815 + }, + { + "name": "Calle Vitoria", + "lat": "40.78473", + "lon": "-4.00419", + "id": 17273 + }, + { + "name": "Calle de Peñalara", + "lat": "40.78493", + "lon": "-4.00093", + "id": 36632 + }, + { + "name": "Calle de la Bola del Mundo", + "lat": "40.78400", + "lon": "-4.00437", + "id": 17272 + }, + { + "name": "Calle de la Estación", + "lat": "40.78501", + "lon": "-4.00267", + "id": 55425 + }, + { + "name": "Calle de la Virgen de las Nieves", + "lat": "40.78327", + "lon": "-4.00308", + "id": 31362 + }, + { + "name": "Camino Schmidt", + "lat": "40.78824", + "lon": "-4.02630", + "id": 34134 + }, + { + "name": "Camino del Calvario", + "lat": "40.77029", + "lon": "-4.01235", + "id": 56605 + }, + { + "name": "Carretera de Collado Villalba a Navacerrada", + "lat": "40.76806", + "lon": "-4.00982", + "id": 52476 + }, + { + "name": "Carril del Gallo", + "lat": "40.80168", + "lon": "-4.03818", + "id": 58970 + }, + { + "name": "Cuerda Larga", + "lat": "40.78579", + "lon": "-3.97995", + "id": 18495 + }, + { + "name": "La Bola del Mundo", + "lat": "40.78514", + "lon": "-3.98061", + "id": 59123 + }, + { + "name": "PR-8 Senda Herreros", + "lat": "40.78413", + "lon": "-4.01647", + "id": 36544 + }, + { + "name": "Calle Ginos", + "lat": "40.78542", + "lon": "-4.00259", + "id": 17256 + }, + { + "name": "El Bosque", + "lat": "40.78813", + "lon": "-4.00844", + "id": 36543 + } + ], + "matchCity": 1, + "matchStreet": 1 + }, + { + "name": "Moraleja de Enmedio", + "enName": "Moraleja de Enmedio", + "names": { + "ru": "Уманес-де-Мадрид", + "ja": "モラレハ・デ・エンメディオ", + "zh": "莫拉莱哈登梅迪奥" + }, + "lat": "40.26155", + "lon": "-3.86121", + "id": 306945944, + "type": "VILLAGE", + "listOfStreets": [ + { + "name": "Calle de Navacerrada", + "lat": "40.26170", + "lon": "-3.86255", + "id": 51011, + "intersectedStreets": [ + { + "name": "Calle de Somosierra", + "lat": "40.26194", + "lon": "-3.86227" + }, + { + "name": "Travesía Real", + "lat": "40.26194", + "lon": "-3.86227" + }, + { + "name": "Calle Real", + "lat": "40.26155", + "lon": "-3.86296" + } + ] + } + ], + "matchStreet": 1 + } + ] +} \ No newline at end of file From d587bee30952ee9afeee1a4f2c2e03ffbfa196ed Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 17:30:43 +0200 Subject: [PATCH 14/19] Fix search & terrain action --- .../net/osmand/search/core/ObjectType.java | 20 +++++++++---------- .../net/osmand/search/core/SearchPhrase.java | 17 ++++++++-------- .../net/osmand/search/core/SearchResult.java | 17 +++++----------- OsmAnd/res/values/strings.xml | 2 +- .../osmand/plus/srtmplugin/TerrainAction.java | 2 +- 5 files changed, 26 insertions(+), 32 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java b/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java index 64ed8710cd..4de83b932d 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java @@ -45,27 +45,27 @@ public enum ObjectType { return null; } - public static double getTypeWeight(ObjectType t) { + public static int getTypeWeight(ObjectType t) { if (t == null) { - return 1.0; + return 1; } switch (t) { case CITY: - return 1.0; + return 1; case VILLAGE: - return 1.0; + return 1; case POSTCODE: - return 1.0; + return 1; case STREET: - return 2.0; + return 2; case HOUSE: - return 3.0; + return 3; case STREET_INTERSECTION: - return 3.0; + return 3; case POI: - return 2.0; + return 2; default: - return 1.0; + return 1; } } } diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java index 7a8e506647..41cc8b7929 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java @@ -724,16 +724,17 @@ public class SearchPhrase { } public void countUnknownWordsMatch(SearchResult sr, String localeName, Collection otherNames) { - if(unknownWords.size() > 0) { - for(int i = 0; i < unknownWords.size(); i++) { - if(unknownWordsMatcher.size() == i) { - unknownWordsMatcher.add(new NameStringMatcher(unknownWords.get(i), - i < unknownWords.size() - 1 || isLastUnknownSearchWordComplete() ? StringMatcherMode.CHECK_EQUALS_FROM_SPACE : - StringMatcherMode.CHECK_STARTS_FROM_SPACE)); + if (unknownWords.size() > 0) { + for (int i = 0; i < unknownWords.size(); i++) { + if (unknownWordsMatcher.size() == i) { + unknownWordsMatcher.add(new NameStringMatcher(unknownWords.get(i), + i < unknownWords.size() - 1 || isLastUnknownSearchWordComplete() + ? StringMatcherMode.CHECK_EQUALS_FROM_SPACE + : StringMatcherMode.CHECK_STARTS_FROM_SPACE)); } NameStringMatcher ms = unknownWordsMatcher.get(i); - if(ms.matches(localeName) || ms.matches(otherNames)) { - if(sr.otherWordsMatch == null) { + if (ms.matches(localeName) || ms.matches(otherNames)) { + if (sr.otherWordsMatch == null) { sr.otherWordsMatch = new TreeSet<>(); } sr.otherWordsMatch.add(unknownWords.get(i)); diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java index 93f0acfafd..8c235713b4 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java @@ -33,20 +33,13 @@ public class SearchResult { this.requiredSearchPhrase = sp; } - public double getUnknownPhraseMatchWeight() { - return getUnknownPhraseMatchWeight(false); - } - - private double getUnknownPhraseMatchWeight(boolean isHouse) { - double res = 0; - isHouse = isHouse || objectType == ObjectType.HOUSE; + public int getUnknownPhraseMatchWeight() { if (unknownPhraseMatches) { - res = isHouse ? ObjectType.getTypeWeight(ObjectType.HOUSE) : ObjectType.getTypeWeight(objectType); + return ObjectType.getTypeWeight(objectType); + } else if (parentSearchResult != null) { + return parentSearchResult.getUnknownPhraseMatchWeight(); } - if (res == 0 && parentSearchResult != null) { - return parentSearchResult.getUnknownPhraseMatchWeight(isHouse); - } - return res; + return 0; } public int getFoundWordCount() { diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 8308881ea1..65a1231387 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -23,7 +23,7 @@ Parking positions Create / Edit POI Button showing or hiding public transport on the map. - Show / hide public transport + Show/hide public transport Show public transport Hide public transport diff --git a/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainAction.java b/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainAction.java index 43f94c2401..2202a1f174 100644 --- a/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainAction.java +++ b/OsmAnd/src/net/osmand/plus/srtmplugin/TerrainAction.java @@ -16,7 +16,7 @@ import net.osmand.plus.quickaction.QuickActionType; public class TerrainAction extends QuickAction { public static final QuickActionType TYPE = new QuickActionType(30, - "contourlines.showhide", TerrainAction.class). + "terrain.showhide", TerrainAction.class). nameRes(R.string.quick_action_show_hide_hillshade).iconRes(R.drawable.ic_action_hillshade_dark).nonEditable(). category(QuickActionType.CONFIGURE_MAP); From 108c2b5704a11ed60d4f2fe272b227343f6d3969 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 18:53:55 +0200 Subject: [PATCH 15/19] Fix search type and more comments --- .../java/net/osmand/search/SearchUICore.java | 12 ++++--- .../net/osmand/search/core/ObjectType.java | 14 +++------ .../net/osmand/search/core/SearchResult.java | 14 ++++++--- .../search/free_street_portland.json | 12 +++---- .../test/resources/search/navacerrada.json | 31 +++++++++++++++++-- 5 files changed, 54 insertions(+), 29 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java index 7eec13cd94..1739d83fb6 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java @@ -872,16 +872,18 @@ public class SearchUICore { return topVisible1 ? -1 : 1; } break; - case UNKNOWN_PHRASE_MATCH_WEIGHT: - if (o1.getUnknownPhraseMatchWeight() != o2.getUnknownPhraseMatchWeight()) { - return -Double.compare(o1.getUnknownPhraseMatchWeight(), o2.getUnknownPhraseMatchWeight()); - } - break; case FOUND_WORD_COUNT: if (o1.getFoundWordCount() != o2.getFoundWordCount()) { return -Algorithms.compare(o1.getFoundWordCount(), o2.getFoundWordCount()); } break; + case UNKNOWN_PHRASE_MATCH_WEIGHT: + // here we check how much each sub search result matches the phrase + // also we sort it by type house -> street/poi -> city/postcode/village/other + if (o1.getUnknownPhraseMatchWeight() != o2.getUnknownPhraseMatchWeight()) { + return -Double.compare(o1.getUnknownPhraseMatchWeight(), o2.getUnknownPhraseMatchWeight()); + } + break; case SEARCH_DISTANCE_IF_NOT_BY_NAME: if (!c.sortByName) { double s1 = o1.getSearchDistance(c.loc); diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java b/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java index 4de83b932d..3236fa6032 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java @@ -50,20 +50,16 @@ public enum ObjectType { return 1; } switch (t) { - case CITY: - return 1; - case VILLAGE: - return 1; - case POSTCODE: - return 1; - case STREET: - return 2; case HOUSE: - return 3; case STREET_INTERSECTION: return 3; + case STREET: case POI: return 2; + case CITY: + case VILLAGE: + case POSTCODE: + return 1; default: return 1; } diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java index 8c235713b4..9319e225ef 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java @@ -33,13 +33,17 @@ public class SearchResult { this.requiredSearchPhrase = sp; } - public int getUnknownPhraseMatchWeight() { + public double getUnknownPhraseMatchWeight() { + // if result is a complete match in the search we prioritize it highers + double res = 0; if (unknownPhraseMatches) { - return ObjectType.getTypeWeight(objectType); - } else if (parentSearchResult != null) { - return parentSearchResult.getUnknownPhraseMatchWeight(); + res = ObjectType.getTypeWeight(objectType); } - return 0; + if (parentSearchResult != null) { + // 5 is a maximum type + res += parentSearchResult.getUnknownPhraseMatchWeight() / 5; + } + return res; } public int getFoundWordCount() { diff --git a/OsmAnd-java/src/test/resources/search/free_street_portland.json b/OsmAnd-java/src/test/resources/search/free_street_portland.json index a4926a4877..d39fbcab43 100644 --- a/OsmAnd-java/src/test/resources/search/free_street_portland.json +++ b/OsmAnd-java/src/test/resources/search/free_street_portland.json @@ -12,20 +12,16 @@ "phrase": "48 Free Street Portland", "results": [ "48.0, ", - "48, Free Street (Downtown), Portland"], + "48, Free Street (Downtown), Portland" + ], "extra-results": [ - "48, Portland Street, North Berwick", + "48, Portland Street, North Berwick", "Free Street (Downtown), Portland", "Free Street (Ferry Village), South Portland", "Portland Street", - "48, Portland Avenue, Old Orchard Beach", "Portland Street (Downtown), Portland", "Portland Street Pier, South Portland", - "Portland Street, Yarmouth", - "Portland Street, North Berwick", - "Portland Street, Berwick", - "Portland Street, South Berwick", - "Portland Street, Fryeburg" + "Portland Street, Yarmouth" ], "amenities": [ { diff --git a/OsmAnd-java/src/test/resources/search/navacerrada.json b/OsmAnd-java/src/test/resources/search/navacerrada.json index 1358fb0e32..b4c94a734e 100644 --- a/OsmAnd-java/src/test/resources/search/navacerrada.json +++ b/OsmAnd-java/src/test/resources/search/navacerrada.json @@ -14,8 +14,9 @@ "5, Calle de las Eras (Uranización Los Corales), Navacerrada" ], "extra-results": [ - "Calle de las Eras (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada", + "Calle de las Eras (Uranización Los Corales), Navacerrada", "Calle del Sotillo (Uranización Los Corales), Pasaje de las Eras (Uranización Los Corales), Navacerrada", + "Calle del Puerto de Navacerrada, Las Nieves", "5, Calle Navacerrada (Urb. Las Suertes), Las Suertes", "50, Calle de Francisco Navacerrada, Salamanca", "52, Calle de Francisco Navacerrada, Salamanca", @@ -26,7 +27,6 @@ "57, Calle de Francisco Navacerrada, Salamanca", "58, Calle de Francisco Navacerrada, Salamanca", "59, Calle de Francisco Navacerrada, Salamanca", - "Calle del Puerto de Navacerrada, Las Nieves", "Pasaje de las Eras (Uranización Los Corales), Navacerrada", "Calle Barrio de las Peñas, Navacerrada", "Calle de las Cruces (Residencial Sanabria), Navacerrada", @@ -47,6 +47,33 @@ "Calle de los Enebros (Uranización Los Corales), Navacerrada", "Calle de la Bola del Mundo (Residencial Sanabria), Navacerrada", "Calle de la Maliciosa (Residencial Sanabria), Navacerrada", + "Calle de la Perdiz, Navacerrada", + "Calle de la Magdalena, Navacerrada", + "Calle las Jaras, Navacerrada", + "Calle de la Audiencia, Navacerrada", + "Calle de Prado Jerez, Navacerrada", + "Calle de Carmen Conde (Residencial Sanabria), Navacerrada", + "Calle de la Iglesia, Navacerrada", + "Calle de la Tejera, Navacerrada", + "Calle de la Encinilla, Navacerrada", + "Calle de la Canaleja (Residencial Sanabria), Navacerrada", + "Calle de Rafael Alvarado, Navacerrada", + "Calle de Andrés Segovia, Navacerrada", + "Calle de los Pradillos (Residencial Sanabria), Navacerrada", + "Calle de Abel, Navacerrada", + "Calle Praderas de San Sebastián, Navacerrada", + "Calle de San Sebastián (Residencial Sanabria), Navacerrada", + "Calle de Álvaro Iglesia, Navacerrada", + "Calle de los Arcos, Navacerrada", + "Calle de Peñalara, Puerto de Navacerrada", + "Calle de la Bola del Mundo, Puerto de Navacerrada", + "Calle de la Estación, Puerto de Navacerrada", + "Calle Ginos, Puerto de Navacerrada", + "Calle Vitoria, Puerto de Navacerrada", + "Calle Dos Castillas, Puerto de Navacerrada", + "Travesía de las Huertas, Navacerrada", + "Vereda de las Encinillas, Navacerrada", + "Centro Municipal de Mayores «Navacerrada»", ], "amenities": [ { From edd10cb092f1e928854e430f0e88395551d2086e Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 19:41:23 +0200 Subject: [PATCH 16/19] Fix #9061 --- .../src/main/java/net/osmand/search/core/ObjectType.java | 3 ++- .../src/main/java/net/osmand/search/core/SearchPhrase.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java b/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java index 3236fa6032..9844f52646 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/ObjectType.java @@ -52,8 +52,9 @@ public enum ObjectType { switch (t) { case HOUSE: case STREET_INTERSECTION: - return 3; + return 4; case STREET: + return 3; case POI: return 2; case CITY: diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java index 41cc8b7929..8f6799e3be 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java @@ -121,7 +121,7 @@ public class SearchPhrase { int i1 = CommonWords.getCommonSearch(o1.toLowerCase()); int i2 = CommonWords.getCommonSearch(o2.toLowerCase()); if (i1 != i2) { - return icompare(i1, i2); + return -icompare(i1, i2); } // compare length without numbers to not include house numbers return -icompare(lengthWithoutNumbers(o1), lengthWithoutNumbers(o2)); From 022ed7e705b7acb80f4336a386ea690a2234eefc Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 19:55:19 +0200 Subject: [PATCH 17/19] Fix critical bug in search comparator --- .../src/main/java/net/osmand/search/core/SearchPhrase.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java index 8f6799e3be..b15c5a377a 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java @@ -121,6 +121,11 @@ public class SearchPhrase { int i1 = CommonWords.getCommonSearch(o1.toLowerCase()); int i2 = CommonWords.getCommonSearch(o2.toLowerCase()); if (i1 != i2) { + if(i1 == -1) { + return -1; + } else if(i2 == -1) { + return 1; + } return -icompare(i1, i2); } // compare length without numbers to not include house numbers From 0944dc16f9b783dd152c64f8ea4ba825e4bd2927 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 21:26:56 +0200 Subject: [PATCH 18/19] Temporarily fix tests --- .../osmand/search/core/SearchCoreFactory.java | 2 +- .../net/osmand/search/core/SearchPhrase.java | 5 +- .../net/osmand/search/core/SearchResult.java | 5 +- .../net/osmand/search/SearchUICoreTest.java | 7 +- .../test/resources/search/spring_street.json | 142 +++++++++++------- 5 files changed, 103 insertions(+), 58 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java index ed9924d69f..c3923759af 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java @@ -146,7 +146,7 @@ public class SearchCoreFactory { phrase.countUnknownWordsMatch(res); // int cnt = resultMatcher.getCount(); List ws = phrase.getUnknownSearchWords(res.otherWordsMatch); - if(!res.firstUnknownWordMatches) { + if (!res.firstUnknownWordMatches) { ws.add(phrase.getUnknownSearchWord()); } // publish result to set parentSearchResult before search diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java index b15c5a377a..869c44d005 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java @@ -468,7 +468,7 @@ public class SearchPhrase { prnt = prnt.parentSearchResult; } sp.words.addAll(0, this.words); - if(unknownWords != null) { + if (unknownWords != null) { sp.lastUnknownSearchWordComplete = lastComplete; for (int i = 0; i < unknownWords.size(); i++) { if (i == 0) { @@ -477,6 +477,9 @@ public class SearchPhrase { sp.unknownWords.add(unknownWords.get(i)); } } + // TODO +// sp.rawUnknownSearchPhrase = rawUnknownSearchPhrase; +// sp.unknownSearchPhrase = unknownSearchPhrase; } return sp; } diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java index 9319e225ef..269694eae9 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchResult.java @@ -40,8 +40,9 @@ public class SearchResult { res = ObjectType.getTypeWeight(objectType); } if (parentSearchResult != null) { - // 5 is a maximum type - res += parentSearchResult.getUnknownPhraseMatchWeight() / 5; + // 10 > maximum type + // res = Math.max(res,parentSearchResult.getUnknownPhraseMatchWeight()) ; + res += parentSearchResult.getUnknownPhraseMatchWeight() / 10; } return res; } diff --git a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java index 0af85e9acb..40a8585cb9 100644 --- a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java +++ b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java @@ -181,9 +181,12 @@ public class SearchUICoreTest { String present = result.toString(); //System.out.println(present); if(!Algorithms.stringsEqual(expected, present)) { - System.out.println(String.format("Mismatch for '%s' != '%s'. Result: ", expected, present)); + System.out.println(String.format("Mismatch for '%s' != '%s' (%d, %.3f, %s). Result: ", expected, + present, result.getFoundWordCount(), result.getUnknownPhraseMatchWeight(), result.objectType.toString())); for (SearchResult r : searchResults) { - System.out.println("\t\""+r.toString()+"\","); + System.out.println(String.format("\t\"%s\",", r.toString())); +// System.out.println(String.format("\"%s\", (%d, %.3f, %s),", r.toString(), +// r.getFoundWordCount(), r.getUnknownPhraseMatchWeight(), r.objectType.toString())); } } Assert.assertEquals(expected, present); diff --git a/OsmAnd-java/src/test/resources/search/spring_street.json b/OsmAnd-java/src/test/resources/search/spring_street.json index 5ad960f31b..c0c6e4e189 100644 --- a/OsmAnd-java/src/test/resources/search/spring_street.json +++ b/OsmAnd-java/src/test/resources/search/spring_street.json @@ -12,58 +12,96 @@ "phrase": "spring street", "results": [ "Spring (Natural)", - "Spring (Spring / Natural)", - "Spring (Ice rink / Sport)", - "Spring (Bridge / Transport construction)", - "Spring Street, South Nyack", - "Spring Street, Tomkins Cove", - "Spring Street, Southfields", - "Spring Street, Hastings-on-Hudson", - "Spring Street, Pleasantville", - "Spring Street (Mount Pleasant), Hawthorne", - "Spring Street, Durland", - "Spring Street, Warwick", - "Spring Street, Nelsonville", - "Spring Street, Goshen", - "Spring Street (Little Italy), Manhattan", - "Spring Street, Maybrook", - "West Spring Street, Maybrook", - "Spring Street, South Salem", - "Spring Street, Groveville", - "Spring Street, East Middletown", - "Spring Street, Montgomery", - "Spring Street, Chelsea", - "Spring Street, Wappingers Falls", - "Spring Street, Cold Spring Harbor", - "Spring Street, Staten Island", - "Spring Street, East Meadow", - "Spring Street, Inwood", - "Spring Street, Port Jervis", - "Spring Street, Roosevelt", - "Spring Street, Pawling", - "Spring Street, Fairview", - "Spring Street (Wyandanch), Wheatley Heights", - "Spring Street, Wyandanch", - "Spring Street, East Massapequa", - "Spring Street, Ellenville", - "Spring Street, Monticello", - "Spring Street, Tillson", - "Spring Street, Port Jefferson", - "Spring Street (Smallwood), Bethel", - "Spring Street, Liberty", - "Spring Street (Livingston Manor), Rockland", - "Spring Street, Livingston Manor", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street", - "Spring Street" + "Spring (Spring / Natural)", + "Spring (Ice rink / Sport)", + "Spring (Bridge / Transport construction)", + "Spring Street, Cold Spring Harbor", + "Spring Street, South Nyack", + "Spring Street, Tomkins Cove", + "Spring Street, Southfields", + "Spring Street, Hastings-on-Hudson", + "Spring Street, Pleasantville", + "Spring Street (Mount Pleasant), Hawthorne", + "Spring Street, Durland", + "Spring Street, Warwick", + "Spring Street, Nelsonville", + "Spring Street, Goshen", + "Spring Street (Little Italy), Manhattan", + "Spring Street, Maybrook", + "West Spring Street, Maybrook", + "Spring Street, South Salem", + "Spring Street, Groveville", + "Spring Street, East Middletown", + "Spring Street, Montgomery", + "Spring Street, Chelsea", + "Spring Street, Wappingers Falls", + "Spring Street, Staten Island", + "Spring Street, East Meadow", + "Spring Street, Inwood", + "Spring Street, Port Jervis", + "Spring Street, Roosevelt", + "Spring Street, Pawling", + "Spring Street, Fairview", + "Spring Street (Wyandanch), Wheatley Heights", + "Spring Street, Wyandanch", + "Spring Street, East Massapequa", + "Spring Street, Ellenville", + "Spring Street, Monticello", + "Spring Street, Tillson", + "Spring Street, Port Jefferson", + "Spring Street (Smallwood), Bethel", + "Spring Street, Liberty", + "Spring Street (Livingston Manor), Rockland", + "Spring Street, Livingston Manor", + "Market Street, Cold Spring", + "New Street, Cold Spring", + "West Street, Cold Spring", + "Fish Street, Cold Spring", + "North Street, Cold Spring", + "Rock Street, Cold Spring", + "Stone Street, Cold Spring", + "Wall Street, Cold Spring", + "Cross Street, Cold Spring", + "Main Street, Cold Spring", + "Chestnut Street, Cold Spring", + "Furnace Street, Cold Spring", + "Garden Street, Cold Spring", + "Church Street, Cold Spring", + "Oak Street, Cold Spring", + "Cherry Street, Cold Spring", + "High Street, Cold Spring", + "Academy Street, Cold Spring", + "Haldane Street, Cold Spring", + "West Bank Street, Cold Spring", + "B Street, Cold Spring", + "West Belvedere Street, Cold Spring", + "Parrot Street, Cold Spring", + "Bank Street, Cold Spring", + "Orchard Street, Cold Spring", + "East Belvedere Street, Cold Spring", + "Pine Street, Cold Spring", + "Parsonage Street, Cold Spring", + "Hamilton Street, Cold Spring", + "Fair Street, Cold Spring", + "Cedar Street, Cold Spring", + "Flora Street, Cold Spring Harbor", + "West Main Street, Cold Spring Harbor", + "Grove Street, Cold Spring Harbor", + "Midland Street, Cold Spring Harbor", + "Rusco Street, Cold Spring Harbor", + "Main Street, Cold Spring Harbor", + "Chestnut Street, Cold Spring Harbor", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street" ], "amenities": [ { From 9ca1dbd9cfcb37c5f049f10e3025b2846ff224ca Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sun, 24 May 2020 22:05:54 +0200 Subject: [PATCH 19/19] Temporarily fix test results --- .../java/net/osmand/search/SearchUICore.java | 7 +- .../osmand/search/core/SearchCoreFactory.java | 8 +-- .../net/osmand/search/core/SearchPhrase.java | 9 +-- .../net/osmand/search/SearchUICoreTest.java | 9 ++- .../test/resources/search/spring_street.json | 70 ++++++++++++++++++- 5 files changed, 84 insertions(+), 19 deletions(-) diff --git a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java index 1739d83fb6..b49ec81d94 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/SearchUICore.java @@ -651,6 +651,10 @@ public class SearchUICore { this.parentSearchResult = parentSearchResult; return prev; } + + public SearchResult getParentSearchResult() { + return parentSearchResult; + } public List getRequestResults() { return requestResults; @@ -730,9 +734,9 @@ public class SearchUICore { object.localeName = object.alternateName; object.alternateName = null; } + object.parentSearchResult = parentSearchResult; if (matcher == null || matcher.publish(object)) { count++; - object.parentSearchResult = parentSearchResult; if (totalLimit == -1 || count < totalLimit) { requestResults.add(object); } @@ -740,6 +744,7 @@ public class SearchUICore { } return false; } + @Override public boolean isCancelled() { boolean cancelled = request != requestNumber.get(); diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java index c3923759af..0d01c98391 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java @@ -154,14 +154,10 @@ public class SearchCoreFactory { if (!ws.isEmpty() && api != null && api.isSearchAvailable(phrase)) { SearchPhrase nphrase = phrase.selectWord(res, ws, phrase.isLastUnknownSearchWordComplete()); - SearchResult prev = resultMatcher.setParentSearchResult(res); - res.parentSearchResult = prev; + resultMatcher.setParentSearchResult(res); api.search(nphrase, resultMatcher); - resultMatcher.setParentSearchResult(prev); + resultMatcher.setParentSearchResult(res.parentSearchResult); } -// if (resultMatcher.getCount() == cnt) { -// resultMatcher.publish(res); -// } } @Override diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java index 869c44d005..3e153f906e 100644 --- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java +++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchPhrase.java @@ -463,23 +463,24 @@ public class SearchPhrase { SearchPhrase sp = new SearchPhrase(this.settings, this.clt); addResult(res, sp); SearchResult prnt = res.parentSearchResult; - while(prnt != null) { + while (prnt != null) { addResult(prnt, sp); prnt = prnt.parentSearchResult; } sp.words.addAll(0, this.words); if (unknownWords != null) { sp.lastUnknownSearchWordComplete = lastComplete; + StringBuilder genUnknownSearchPhrase = new StringBuilder(); for (int i = 0; i < unknownWords.size(); i++) { if (i == 0) { sp.unknownSearchWordTrim = unknownWords.get(0); } else { sp.unknownWords.add(unknownWords.get(i)); } + genUnknownSearchPhrase.append(unknownWords.get(i)).append(" "); } - // TODO -// sp.rawUnknownSearchPhrase = rawUnknownSearchPhrase; -// sp.unknownSearchPhrase = unknownSearchPhrase; + + sp.rawUnknownSearchPhrase = sp.unknownSearchPhrase = genUnknownSearchPhrase.toString().trim(); } return sp; } diff --git a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java index 40a8585cb9..13c9668741 100644 --- a/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java +++ b/OsmAnd-java/src/test/java/net/osmand/search/SearchUICoreTest.java @@ -179,14 +179,13 @@ public class SearchUICoreTest { for (SearchResult result : searchResults) { String expected = results.get(i++); String present = result.toString(); - //System.out.println(present); - if(!Algorithms.stringsEqual(expected, present)) { + if (!Algorithms.stringsEqual(expected, present)) { System.out.println(String.format("Mismatch for '%s' != '%s' (%d, %.3f, %s). Result: ", expected, present, result.getFoundWordCount(), result.getUnknownPhraseMatchWeight(), result.objectType.toString())); for (SearchResult r : searchResults) { - System.out.println(String.format("\t\"%s\",", r.toString())); -// System.out.println(String.format("\"%s\", (%d, %.3f, %s),", r.toString(), -// r.getFoundWordCount(), r.getUnknownPhraseMatchWeight(), r.objectType.toString())); +// System.out.println(String.format("\t\"%s\",", r.toString())); + System.out.println(String.format("\"%s\", (%d, %.3f, %s),", r.toString(), + r.getFoundWordCount(), r.getUnknownPhraseMatchWeight(), r.objectType.toString())); } } Assert.assertEquals(expected, present); diff --git a/OsmAnd-java/src/test/resources/search/spring_street.json b/OsmAnd-java/src/test/resources/search/spring_street.json index c0c6e4e189..b8f10d139a 100644 --- a/OsmAnd-java/src/test/resources/search/spring_street.json +++ b/OsmAnd-java/src/test/resources/search/spring_street.json @@ -11,11 +11,10 @@ }, "phrase": "spring street", "results": [ - "Spring (Natural)", + "Spring (Natural)", "Spring (Spring / Natural)", "Spring (Ice rink / Sport)", "Spring (Bridge / Transport construction)", - "Spring Street, Cold Spring Harbor", "Spring Street, South Nyack", "Spring Street, Tomkins Cove", "Spring Street, Southfields", @@ -35,6 +34,7 @@ "Spring Street, Montgomery", "Spring Street, Chelsea", "Spring Street, Wappingers Falls", + "Spring Street, Cold Spring Harbor", "Spring Street, Staten Island", "Spring Street, East Meadow", "Spring Street, Inwood", @@ -101,7 +101,71 @@ "Spring Street", "Spring Street", "Spring Street", - "Spring Street" + "Spring Street", + "Academy Street, Cold Spring", + "Bank Street, Cold Spring", + "B Street, Cold Spring", + "Cedar Street, Cold Spring", + "Cherry Street, Cold Spring", + "Chestnut Street, Cold Spring", + "Church Street, Cold Spring", + "Cross Street, Cold Spring", + "East Belvedere Street, Cold Spring", + "Fair Street, Cold Spring", + "Fish Street, Cold Spring", + "Furnace Street, Cold Spring", + "Garden Street, Cold Spring", + "Haldane Street, Cold Spring", + "Hamilton Street, Cold Spring", + "High Street, Cold Spring", + "Main Street, Cold Spring", + "Market Street, Cold Spring", + "New Street, Cold Spring", + "North Street, Cold Spring", + "Oak Street, Cold Spring", + "Orchard Street, Cold Spring", + "Parrot Street, Cold Spring", + "Parsonage Street, Cold Spring", + "Pine Street, Cold Spring", + "Rock Street, Cold Spring", + "Stone Street, Cold Spring", + "Wall Street, Cold Spring", + "West Bank Street, Cold Spring", + "West Belvedere Street, Cold Spring", + "West Street, Cold Spring", + "Chestnut Street, Cold Spring Harbor", + "Flora Street, Cold Spring Harbor", + "Grove Street, Cold Spring Harbor", + "Main Street, Cold Spring Harbor", + "Midland Street, Cold Spring Harbor", + "Rusco Street, Cold Spring Harbor", + "Spring Street, Cold Spring Harbor", + "West Main Street, Cold Spring Harbor", + "Kraw Street, Spring Glen", + "Munro Street, Cold Spring", + "State Street, Cold Spring", + "Spring Street Salt Shed", + "6th Avenue & Spring Street", + "Spring Street Park", + "Broadway & Spring Street", + "Broadway/Spring Street", + "Spring Street Station (6) - Downtown", + "Spring Street Station (6) - Uptown & The Bronx", + "Richmond Road & Spring Street", + "West Spring Street School", + "Spring Street Gallery", + "Spring Street Apartments", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", + "Spring Street", ], "amenities": [ {