Skip to content

Commit

Permalink
Merge branch 'osmandapp:master' into hardy_Afa
Browse files Browse the repository at this point in the history
  • Loading branch information
sonora authored Sep 14, 2024
2 parents ffc2886 + c5b7622 commit aa86f43
Show file tree
Hide file tree
Showing 315 changed files with 6,004 additions and 3,042 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
package net.osmand.binary;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;

import com.google.protobuf.CodedInputStream;
import com.google.protobuf.WireFormat;

import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntLongHashMap;
import gnu.trove.set.hash.TLongHashSet;
Expand All @@ -24,14 +12,21 @@
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
import net.osmand.binary.OsmandOdb.OsmAndPoiNameIndex.OsmAndPoiNameIndexData;
import net.osmand.data.Amenity;
import net.osmand.data.Amenity.AmenityRoutePoint;
import net.osmand.data.LatLon;
import net.osmand.data.QuadRect;
import net.osmand.data.QuadTree;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;

import java.io.IOException;
import java.util.*;

public class BinaryMapPoiReaderAdapter {
private static final Log LOG = PlatformUtil.getLog(BinaryMapPoiReaderAdapter.class);
Expand Down Expand Up @@ -60,6 +55,10 @@ public static class PoiRegion extends BinaryIndexPart {
List<List<String>> subcategories = new ArrayList<List<String>>();
List<PoiSubType> subTypes = new ArrayList<PoiSubType>();
List<PoiSubType> topIndexSubTypes = new ArrayList<PoiSubType>();
Map<Integer, List<TagValuePair>> tagGroups = new HashMap<>();
QuadTree<Void> bboxIndexCache = new QuadTree<Void>(new QuadRect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE),
8, 0.55f);
static boolean MAP_HAS_TAG_GROUPS = false;

int left31;
int right31;
Expand Down Expand Up @@ -129,6 +128,10 @@ public PoiSubType getSubtypeFromId(int id, StringBuilder returnValue) {
return null;
}

public List<TagValuePair> getTagValues(int id) {
return tagGroups.getOrDefault(id, new ArrayList<>());
}

}

private CodedInputStream codedIS;
Expand Down Expand Up @@ -312,8 +315,10 @@ protected void searchPoiByName(PoiRegion region, SearchRequest<Amenity> req) thr
String query = normalizeSearchPoiByNameQuery(req.nameQuery);
CollatorStringMatcher matcher = new CollatorStringMatcher(query,
StringMatcherMode.CHECK_STARTS_FROM_SPACE);
long time = System.currentTimeMillis();
long indexOffset = codedIS.getTotalBytesRead();
TIntLongHashMap offsetsMap = new TIntLongHashMap();
List<Integer> nameIndexCoordinates = new ArrayList<>();
QuadTree<Void> nameIndexTree = null;
while (true) {
if (req.isCancelled()) {
return;
Expand All @@ -327,7 +332,25 @@ protected void searchPoiByName(PoiRegion region, SearchRequest<Amenity> req) thr
long length = readInt();
long oldLimit = codedIS.pushLimitLong((long) length);
// here offsets are sorted by distance
offsets = readPoiNameIndex(matcher.getCollator(), query, req);
offsets = readPoiNameIndex(matcher.getCollator(), query, req, region, nameIndexCoordinates);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER:
length = readInt();
oldLimit = codedIS.pushLimitLong((long) length);
if (nameIndexCoordinates.size() > 0 && nameIndexTree == null) {
nameIndexTree = new QuadTree<Void>(new QuadRect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE),
8, 0.55f);
for (int i = 0; i < nameIndexCoordinates.size(); i = i + 2) {
int x = nameIndexCoordinates.get(i);
int y = nameIndexCoordinates.get(i + 1);
nameIndexTree.insert(null, new QuadRect(x, y, x, y));
}
}
BinaryMapIndexReader.SearchPoiTypeFilter filter = req.poiTypeFilter;
req.poiTypeFilter = null;//init for all categories
readBoxField(0, 0, 0, 0, 0, 0, 0, offsetsMap, null, req, region, nameIndexTree);
req.poiTypeFilter = filter;
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER:
Expand Down Expand Up @@ -382,7 +405,7 @@ public int compare(Integer object1, Integer object2) {
}
}

private TIntLongHashMap readPoiNameIndex(Collator instance, String query, SearchRequest<Amenity> req) throws IOException {
private TIntLongHashMap readPoiNameIndex(Collator instance, String query, SearchRequest<Amenity> req, PoiRegion region, List<Integer> nameIndexCoordinates) throws IOException {
TIntLongHashMap offsets = new TIntLongHashMap();
List<TIntArrayList> listOffsets = null;
List<TIntLongHashMap> listOfSepOffsets = new ArrayList<TIntLongHashMap>();
Expand Down Expand Up @@ -418,7 +441,7 @@ private TIntLongHashMap readPoiNameIndex(Collator instance, String query, Search
codedIS.seek(dataOffsets.get(i) + offset);
int len = codedIS.readRawVarint32();
long oldLim = codedIS.pushLimitLong((long) len);
readPoiNameIndexData(offsetMap, req);
readPoiNameIndexData(offsetMap, req, region, nameIndexCoordinates);
codedIS.popLimit(oldLim);
if (req.isCancelled()) {
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
Expand Down Expand Up @@ -450,7 +473,7 @@ private TIntLongHashMap readPoiNameIndex(Collator instance, String query, Search

}

private void readPoiNameIndexData(TIntLongHashMap offsets, SearchRequest<Amenity> req) throws IOException {
private void readPoiNameIndexData(TIntLongHashMap offsets, SearchRequest<Amenity> req, PoiRegion region, List<Integer> nameIndexCoordinates) throws IOException {
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
Expand All @@ -460,7 +483,7 @@ private void readPoiNameIndexData(TIntLongHashMap offsets, SearchRequest<Amenity
case OsmAndPoiNameIndexData.ATOMS_FIELD_NUMBER:
int len = codedIS.readRawVarint32();
long oldLim = codedIS.pushLimitLong((long) len);
readPoiNameIndexDataAtom(offsets, req);
readPoiNameIndexDataAtom(offsets, req, region, nameIndexCoordinates);
codedIS.popLimit(oldLim);
break;
default:
Expand All @@ -470,7 +493,7 @@ private void readPoiNameIndexData(TIntLongHashMap offsets, SearchRequest<Amenity
}
}

private void readPoiNameIndexDataAtom(TIntLongHashMap offsets, SearchRequest<Amenity> req) throws IOException {
private void readPoiNameIndexDataAtom(TIntLongHashMap offsets, SearchRequest<Amenity> req, PoiRegion region, List<Integer> nameIndexCoordinates) throws IOException {
int x = 0;
int y = 0;
int zoom = 15;
Expand Down Expand Up @@ -501,6 +524,13 @@ private void readPoiNameIndexDataAtom(TIntLongHashMap offsets, SearchRequest<Ame
long d = Math.abs(req.x - x31) + Math.abs(req.y - y31);
offsets.put(shift, d);
}

List<Void> bboxResult = new ArrayList<>();
region.bboxIndexCache.queryInBox(new QuadRect(x31, y31, x31, y31), bboxResult);
if (bboxResult.size() == 0) {
nameIndexCoordinates.add(x31);
nameIndexCoordinates.add(y31);
}
break;
default:
skipUnknownField(t);
Expand Down Expand Up @@ -532,7 +562,7 @@ protected void searchPoiIndex(int left31, int right31, int top31, int bottom31,
case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER:
length = readInt();
oldLimit = codedIS.pushLimitLong((long) length);
readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsetsMap, skipTiles, req, region);
readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsetsMap, skipTiles, req, region, null);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER:
Expand Down Expand Up @@ -889,6 +919,19 @@ private Amenity readPoiPoint(int left31, int right31, int top31, int bottom31,
precisionXY = codedIS.readInt32();
}
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.TAGGROUPS_FIELD_NUMBER:
PoiRegion.MAP_HAS_TAG_GROUPS = true;
long sz = codedIS.readRawVarint32();
long old = codedIS.pushLimitLong((long) sz);
while (codedIS.getBytesUntilLimit() > 0) {
int tagGroupId = codedIS.readUInt32();
List<TagValuePair> list = region.getTagValues(tagGroupId);
if (list.size() > 0) {
am.addTagGroup(tagGroupId, list);
}
}
codedIS.popLimit(old);
break;
default:
skipUnknownField(t);
break;
Expand Down Expand Up @@ -943,7 +986,7 @@ private boolean checkCategories(SearchRequest<Amenity> req, PoiRegion region) th

private boolean readBoxField(int left31, int right31, int top31, int bottom31,
int px, int py, int pzoom, TIntLongHashMap offsetsMap, TLongHashSet skipTiles,
SearchRequest<Amenity> req, PoiRegion region) throws IOException {
SearchRequest<Amenity> req, PoiRegion region, QuadTree<Void> nameIndexTree) throws IOException {
req.numberOfReadSubtrees++;
int zoomToSkip = req.zoom == -1 ? 31 : req.zoom + ZOOM_TO_SKIP_FILTER_READ;
boolean checkBox = true;
Expand Down Expand Up @@ -984,6 +1027,13 @@ private boolean readBoxField(int left31, int right31, int top31, int bottom31,
existsCategories = true;
}
break;
case OsmandOdb.OsmAndPoiBox.TAGGROUPS_FIELD_NUMBER:
PoiRegion.MAP_HAS_TAG_GROUPS = true;
int tagGroupLength = codedIS.readRawVarint32();
long old = codedIS.pushLimitLong((long) tagGroupLength);
readTagGroups(region.tagGroups, req);
codedIS.popLimit(old);
break;
case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER: {
int x = dx + (px << (zoom - pzoom));
int y = dy + (py << (zoom - pzoom));
Expand All @@ -992,18 +1042,31 @@ private boolean readBoxField(int left31, int right31, int top31, int bottom31,
int xR = ((x + 1) << (31 - zoom)) - 1;
int yT = y << (31 - zoom);
int yB = ((y + 1) << (31 - zoom)) - 1;

boolean intersectWithNameIndex = false;
QuadRect rect = new QuadRect(xL, yT, xR, yB);
if (PoiRegion.MAP_HAS_TAG_GROUPS && nameIndexTree != null) {
List<Void> resCache = new ArrayList<>();
region.bboxIndexCache.queryInBox(rect, resCache);
if (resCache.size() == 0) {
List<Void> res = new ArrayList<>();
nameIndexTree.queryInBox(rect, res);
intersectWithNameIndex = res.size() > 0;
}
}
// check intersection
if (left31 > xR || xL > right31 || bottom31 < yT || yB < top31) {
if ((left31 > xR || xL > right31 || bottom31 < yT || yB < top31) && !intersectWithNameIndex) {
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
return false;
}
req.numberOfAcceptedSubtrees++;
checkBox = false;
region.bboxIndexCache.insert(null, rect);
}

long length = readInt();
long oldLimit = codedIS.pushLimitLong((long) length);
boolean exists = readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsetsMap, skipTiles, req, region);
boolean exists = readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsetsMap, skipTiles, req, region, nameIndexTree);
codedIS.popLimit(oldLimit);

if (skipTiles != null && zoom >= zoomToSkip && exists) {
Expand Down Expand Up @@ -1048,4 +1111,58 @@ private boolean readBoxField(int left31, int right31, int top31, int bottom31,
}
}

private void readTagGroups(Map<Integer, List<TagValuePair>> tagGroups, SearchRequest<Amenity> req) throws IOException {
while (true) {
if (req.isCancelled()) {
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return;
case OsmandOdb.OsmAndPoiTagGroups.GROUPS_FIELD_NUMBER:
int length = codedIS.readRawVarint32();
long oldLimit = codedIS.pushLimitLong((long) length);
readTagGroup(tagGroups, req);
codedIS.popLimit(oldLimit);
break;
default:
skipUnknownField(t);
break;
}
}
}

private void readTagGroup(Map<Integer, List<TagValuePair>> tagGroups, SearchRequest<Amenity> req) throws IOException {
List<String> tagValues = new ArrayList<>();
int id = -1;
while (true) {
if (req.isCancelled()) {
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
if (id > 0 && tagValues.size() > 1 && tagValues.size() % 2 == 0) {
List<TagValuePair> tagValuePairs = new ArrayList<>();
for (int i = 0; i < tagValues.size(); i = i + 2) {
tagValuePairs.add(new TagValuePair(tagValues.get(i), tagValues.get(i + 1), -1));
}
tagGroups.put(id, tagValuePairs);
}
return;
case OsmandOdb.OsmAndPoiTagGroup.ID_FIELD_NUMBER:
id = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndPoiTagGroup.TAGVALUES_FIELD_NUMBER:
tagValues.add(codedIS.readString().intern());
break;
default:
skipUnknownField(t);
break;
}
}
}
}
39 changes: 39 additions & 0 deletions OsmAnd-java/src/main/java/net/osmand/data/Amenity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static net.osmand.gpx.GPXUtilities.OSM_PREFIX;

import net.osmand.Location;
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
Expand Down Expand Up @@ -80,6 +81,7 @@ public class Amenity extends MapObject {
private TIntArrayList x;
private String mapIconName;
private int order;
private Map<Integer, List<TagValuePair>> tagGroups;

public int getOrder() {
return order;
Expand All @@ -89,6 +91,20 @@ public void setOrder(int order) {
this.order = order;
}

public Map<Integer, List<TagValuePair>> getTagGroups() {
return tagGroups;
}

public void addTagGroup(int id, List<TagValuePair> tagValues) {
if (tagGroups == null) {
tagGroups = new HashMap<Integer, List<TagValuePair>>();
}
tagGroups.put(id, tagValues);
}
public void setTagGroups(Map<Integer, List<TagValuePair>> tagGroups) {
this.tagGroups = tagGroups;
}

public static class AmenityRoutePoint {
public double deviateDistance;
public boolean deviationDirectionRight;
Expand Down Expand Up @@ -673,4 +689,27 @@ public String getTranslation(MapPoiTypes mapPoiTypes, String alternateName) {
}
return alternateName;
}

public String getCityFromTagGroups(String lang) {
if (tagGroups == null) {
return null;
}
String result = null;
for (Map.Entry<Integer, List<TagValuePair>> entry : tagGroups.entrySet()) {
for (TagValuePair tagValue : entry.getValue()) {
if (tagValue.tag.endsWith("city:" + lang)) {
if (result == null) {
result = tagValue.value;
} else {
result += ", " + tagValue.value;
}
break;
}
if (tagValue.tag.endsWith("city")) {
result = tagValue.value;
}
}
}
return result;
}
}
6 changes: 5 additions & 1 deletion OsmAnd-java/src/main/java/net/osmand/osm/MapPoiTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,11 @@ public void initFromInputStream(InputStream is) {
lastCategory = null;
}
case "poi_additional_category" -> lastPoiAdditionalCategory = null;
default -> log.warn("Unknown end tag encountered: " + name);
default -> {
if (!name.equals("poi_additional") && !name.equals("poi_reference")) {
log.warn("Unknown end tag encountered: " + name);
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@ private void wrapupRoute(List<GpxPoint> gpxPoints, RouteSegmentAppr bestRoute) {
System.out.println(" " + r);
}
}
for (RouteSegmentResult r : res) {
r.setGpxPointIndex(startInd); // required for reconstructFinalPointsFromFullRoute()
}
gpxPoints.get(startInd).routeToTarget = res;
gpxPoints.get(startInd).targetInd = last;
}
Expand Down
Loading

0 comments on commit aa86f43

Please sign in to comment.