Fix bug with multipolygons

This commit is contained in:
Victor Shcherb 2012-05-27 12:18:46 +02:00
parent ef7affc671
commit 868786eefd
10 changed files with 105 additions and 95 deletions

View file

@ -285,9 +285,14 @@ public class MapAlgorithms {
}
}
private static long combine2Points(int x, int y) {
return (((long) x ) <<32) | ((long)y );
}
/**
* outx,outy are the coordinates out of the box
* inx,iny are the coordinates from the box
* outx,outy are the coordinates out of the box
* inx,iny are the coordinates from the box (NOT IMPORTANT in/out, just one should be in second out)
* @return -1 if there is no instersection or x<<32 | y
*/
public static long calculateIntersection(int inx, int iny, int outx, int outy, int leftX, int rightX, int bottomY, int topY) {
@ -299,7 +304,7 @@ public class MapAlgorithms {
if (leftX <= tx && tx <= rightX) {
bx = tx;
by = topY;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
if (outy > bottomY && iny <= bottomY) {
@ -307,7 +312,7 @@ public class MapAlgorithms {
if (leftX <= tx && tx <= rightX) {
bx = tx;
by = bottomY;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
if (outx < leftX && inx >= leftX) {
@ -315,7 +320,7 @@ public class MapAlgorithms {
if (ty >= topY && ty <= bottomY) {
by = ty;
bx = leftX;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
@ -324,7 +329,7 @@ public class MapAlgorithms {
if (ty >= topY && ty <= bottomY) {
by = ty;
bx = rightX;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
@ -335,7 +340,7 @@ public class MapAlgorithms {
if (leftX <= tx && tx <= rightX) {
bx = tx;
by = topY;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
if (outy < bottomY && iny >= bottomY) {
@ -343,7 +348,7 @@ public class MapAlgorithms {
if (leftX <= tx && tx <= rightX) {
bx = tx;
by = bottomY;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
if (outx > leftX && inx <= leftX) {
@ -351,7 +356,7 @@ public class MapAlgorithms {
if (ty >= topY && ty <= bottomY) {
by = ty;
bx = leftX;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}
@ -360,7 +365,7 @@ public class MapAlgorithms {
if (ty >= topY && ty <= bottomY) {
by = ty;
bx = rightX;
return (((long) bx) << 32) | ((long) by);
return combine2Points(bx, by);
}
}

View file

@ -359,19 +359,19 @@ public class BinaryMapIndexWriter {
MapData.Builder data = MapData.newBuilder();
// calculate size
mapDataBuf.clear();
int pcalcx = pleft;
int pcalcy = ptop;
int pcalcx = (pleft >> SHIFT_COORDINATES);
int pcalcy = (ptop >> SHIFT_COORDINATES);
for (int i = 0; i < coordinates.length / 8; i++) {
int x = Algoritms.parseIntFromBytes(coordinates, i * 8);
int y = Algoritms.parseIntFromBytes(coordinates, i * 8 + 4);
int tx = (x - pcalcx) >> SHIFT_COORDINATES;
int ty = (y - pcalcy) >> SHIFT_COORDINATES;
int tx = (x >> SHIFT_COORDINATES) - pcalcx;
int ty = (y >> SHIFT_COORDINATES) - pcalcy;
writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(tx));
writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(ty));
pcalcx = pcalcx + (tx << SHIFT_COORDINATES);
pcalcy = pcalcy + (ty << SHIFT_COORDINATES);
pcalcx = pcalcx + tx ;
pcalcy = pcalcy + ty ;
}
COORDINATES_SIZE += CodedOutputStream.computeRawVarint32Size(mapDataBuf.size())
+ CodedOutputStream.computeTagSize(MapData.COORDINATES_FIELD_NUMBER) + mapDataBuf.size();
@ -383,8 +383,8 @@ public class BinaryMapIndexWriter {
if (innerPolygonTypes != null && innerPolygonTypes.length > 0) {
mapDataBuf.clear();
pcalcx = pleft;
pcalcy = ptop;
pcalcx = (pleft >> SHIFT_COORDINATES);
pcalcy = (ptop >> SHIFT_COORDINATES);
for (int i = 0; i < innerPolygonTypes.length / 8; i++) {
int x = Algoritms.parseIntFromBytes(innerPolygonTypes, i * 8);
int y = Algoritms.parseIntFromBytes(innerPolygonTypes, i * 8 + 4);
@ -393,17 +393,17 @@ public class BinaryMapIndexWriter {
data.addPolygonInnerCoordinates(ByteString.copyFrom(mapDataBuf.toArray()));
mapDataBuf.clear();
}
pcalcx = pleft;
pcalcy = ptop;
pcalcx = (pleft >> SHIFT_COORDINATES);
pcalcy = (ptop >> SHIFT_COORDINATES);
} else {
int tx = (x - pcalcx) >> SHIFT_COORDINATES;
int ty = (y - pcalcy) >> SHIFT_COORDINATES;
int tx = (x >> SHIFT_COORDINATES) - pcalcx;
int ty = (y >> SHIFT_COORDINATES) - pcalcy;
writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(tx));
writeRawVarint32(mapDataBuf, CodedOutputStream.encodeZigZag32(ty));
pcalcx = pcalcx + (tx << SHIFT_COORDINATES);
pcalcy = pcalcy + (ty << SHIFT_COORDINATES);
pcalcx = pcalcx + tx ;
pcalcy = pcalcy + ty ;
}
}
}

View file

@ -743,7 +743,6 @@ public class IndexCreator {
public static void main(String[] args) throws IOException, SAXException, SQLException, InterruptedException {
long time = System.currentTimeMillis();
IndexCreator creator = new IndexCreator(new File("/home/victor/projects/OsmAnd/data/osm-gen/")); //$NON-NLS-1$
creator.setIndexMap(true);

View file

@ -96,9 +96,11 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
boolean inner = "inner".equals(entities.get(es)); //$NON-NLS-1$
if (!inner) {
outerFound = true;
for (String t : es.getTagKeySet()) {
e.putTag(t, es.getTag(t));
}
// This is incorrect (it should be intersection of all boundaries)
// Currently it causes an issue with coastline (if one line is coastline)
// for (String t : es.getTagKeySet()) {
// e.putTag(t, es.getTag(t));
// }
break;
}
}
@ -518,7 +520,6 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
if (hasMulti) {
TIntArrayList set = multiPolygonsWays.get(e.getId());
typeUse.removeAll(set);
continue;
}
if (typeUse.isEmpty()) {
continue;

View file

@ -195,8 +195,7 @@
<filter appMode="pedestrian" tag="highway" value="bridleway" order="59"/>
<filter tag="highway" value="bridleway" order="36"/>
<filter tag="natural" value="coastline_broken" order="25"/>
<filter tag="natural" value="coastline_broken" order="35"/>
<filter tag="contour" value="" order="15"/>
</group>

View file

@ -4,7 +4,7 @@
Disclaimer :
If you are going to translate strings, please make sure :
1. There is no duplicate strings by name
2. Every apostrophe is started with quote (look others).
2. Every apostrophe (quote) is preceded by a backslash (see others).
If you are making/correcting english translations make sure :
1. All your modified/created strings are in the top of the file (to make easier find what's translated).
-->

View file

@ -206,10 +206,10 @@ public class LocalIndexHelper {
Map<String, String> loadedMaps = app.getResourceManager().getIndexFileNames();
List<LocalIndexInfo> result = new ArrayList<LocalIndexInfo>();
loadTilesData(settings.extendOsmandPath(ResourceManager.TILES_PATH), result, false, loadTask);
loadTilesData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, false, loadTask);
loadObfData(settings.extendOsmandPath(ResourceManager.MAPS_PATH), result, false, loadTask, loadedMaps);
loadObfData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, true, loadTask, loadedMaps);
loadTilesData(settings.extendOsmandPath(ResourceManager.TILES_PATH), result, false, loadTask);
loadTilesData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, false, loadTask);
loadPoiData(settings.extendOsmandPath(ResourceManager.POI_PATH), result, false, loadTask);
loadPoiData(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), result, true, loadTask);
loadVoiceData(settings.extendOsmandPath(ResourceManager.VOICE_PATH), result, false, loadTask);

View file

@ -401,18 +401,16 @@ public class MapRenderRepositories {
if(!coastLines.isEmpty()) {
long ms = System.currentTimeMillis();
List<BinaryMapDataObject> pcoastlines = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
basemapCoastLines.isEmpty());
addBasemapCoastlines = pcoastlines.isEmpty() || zoom <= BASEMAP_ZOOM;
tempResult.addAll(pcoastlines);
boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
basemapCoastLines.isEmpty(), true, tempResult);
addBasemapCoastlines = !coastlinesWereAdded || zoom <= BASEMAP_ZOOM;
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
}
if(addBasemapCoastlines){
addBasemapCoastlines = false;
long ms = System.currentTimeMillis();
List<BinaryMapDataObject> pcoastlines = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom, true);
addBasemapCoastlines = pcoastlines.isEmpty();
tempResult.addAll(pcoastlines);
boolean coastlinesWereAdded = processCoastlines(basemapCoastLines, leftX, rightX, bottomY, topY, zoom,
true, true, tempResult);
addBasemapCoastlines = !coastlinesWereAdded;
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
}
if(addBasemapCoastlines && mi != null){
@ -673,11 +671,11 @@ public class MapRenderRepositories {
}
/// MULTI POLYGONS (coastline)
private List<BinaryMapDataObject> processCoastlines(List<BinaryMapDataObject> coastLines, int leftX, int rightX,
int bottomY, int topY, int zoom, boolean showIncompleted) {
// returns true if coastlines were added!
private boolean processCoastlines(List<BinaryMapDataObject> coastLines, int leftX, int rightX,
int bottomY, int topY, int zoom, boolean doNotAddIfIncompleted, boolean addDebugIncompleted, List<BinaryMapDataObject> result) {
List<TLongList> completedRings = new ArrayList<TLongList>();
List<TLongList> uncompletedRings = new ArrayList<TLongList>();
List<BinaryMapDataObject> result = new ArrayList<BinaryMapDataObject>(coastLines.size());
MapIndex mapIndex = null;
long dbId = 0;
for (BinaryMapDataObject o : coastLines) {
@ -694,7 +692,7 @@ public class MapRenderRepositories {
int y = py;
boolean pinside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
if (pinside) {
coordinates.add((((long) x) << 32) | ((long) y));
coordinates.add(combine2Points(x, y));
}
for (int i = 1; i < len; i++) {
x = o.getPoint31XTile(i);
@ -713,18 +711,29 @@ public class MapRenderRepositories {
combineMultipolygonLine(completedRings, uncompletedRings, coordinates);
}
if (completedRings.size() == 0 && uncompletedRings.size() == 0) {
return result;
return false;
}
if (uncompletedRings.size() > 0) {
unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom);
}
if(!showIncompleted && uncompletedRings.size() > 0){
result.clear();
return result;
long mask = 0xffffffffl;
// draw uncompleted for debug purpose
for (int i = 0; i < uncompletedRings.size(); i++) {
TLongList ring = uncompletedRings.get(i);
int[] coordinates = new int[ring.size() * 2];
for (int j = 0; j < ring.size(); j++) {
coordinates[j * 2] = (int) (ring.get(j) >> 32);
coordinates[j * 2 + 1] = (int) (ring.get(j) & mask);
}
BinaryMapDataObject o = new BinaryMapDataObject(coordinates, new int[] { mapIndex.coastlineBrokenEncodingType }, null, dbId);
o.setMapIndex(mapIndex);
result.add(o);
}
if(!doNotAddIfIncompleted && uncompletedRings.size() > 0){
return false;
}
boolean clockwiseFound = false;
long mask = 0xffffffffl;
for (int i = 0; i < completedRings.size(); i++) {
TLongList ring = completedRings.get(i);
int[] coordinates = new int[ring.size() * 2];
@ -741,18 +750,6 @@ public class MapRenderRepositories {
result.add(o);
}
// draw uncompleted for debug purpose
for (int i = 0; i < uncompletedRings.size(); i++) {
TLongList ring = uncompletedRings.get(i);
int[] coordinates = new int[ring.size() * 2];
for (int j = 0; j < ring.size(); j++) {
coordinates[j * 2] = (int) (ring.get(j) >> 32);
coordinates[j * 2 + 1] = (int) (ring.get(j) & mask);
}
BinaryMapDataObject o = new BinaryMapDataObject(coordinates, new int[] { mapIndex.coastlineBrokenEncodingType}, null, dbId);
o.setMapIndex(mapIndex);
result.add(o);
}
if (!clockwiseFound && uncompletedRings.size() == 0) {
// add complete water tile
BinaryMapDataObject o = new BinaryMapDataObject(new int[] { leftX, topY, rightX, topY, rightX, bottomY, leftX, bottomY, leftX,
@ -762,23 +759,27 @@ public class MapRenderRepositories {
result.add(o);
}
return result;
return true;
}
private boolean eq(long i1, long i2){
return i1 == i2;
}
private void combineMultipolygonLine(List<TLongList> completedRings, List<TLongList> incompletedRings, TLongList coordinates) {
if (coordinates.size() > 0) {
if (coordinates.get(0) == coordinates.get(coordinates.size() - 1)) {
if (eq(coordinates.get(0), coordinates.get(coordinates.size() - 1))) {
completedRings.add(coordinates);
} else {
boolean add = true;
for (int k = 0; k < incompletedRings.size();) {
boolean remove = false;
TLongList i = incompletedRings.get(k);
if (coordinates.get(0) == i.get(i.size() - 1)) {
if (eq(coordinates.get(0), i.get(i.size() - 1))) {
i.addAll(coordinates.subList(1, coordinates.size()));
remove = true;
coordinates = i;
} else if (coordinates.get(coordinates.size() - 1) == i.get(0)) {
} else if (eq(coordinates.get(coordinates.size() - 1), i.get(0))) {
coordinates.addAll(i.subList(1, i.size()));
remove = true;
}
@ -787,7 +788,7 @@ public class MapRenderRepositories {
} else {
k++;
}
if (coordinates.get(0) == coordinates.get(coordinates.size() - 1)) {
if (eq(coordinates.get(0), coordinates.get(coordinates.size() - 1))) {
completedRings.add(coordinates);
add = false;
break;
@ -958,6 +959,10 @@ public class MapRenderRepositories {
return res;
}
private static long combine2Points(int x, int y) {
return (((long) x ) <<32) | ((long)y );
}
private boolean calculateLineCoordinates(boolean inside, int x, int y, boolean pinside, int px, int py, int leftX, int rightX,
int bottomY, int topY, TLongList coordinates) {
boolean lineEnded = false;
@ -966,19 +971,19 @@ public class MapRenderRepositories {
long is = MapAlgorithms.calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY);
if (is == -1) {
// it is an error (!)
is = (((long) px) << 32) | ((long) py);
is = combine2Points(px, py);
}
coordinates.add(is);
lineEnded = true;
} else {
coordinates.add((((long) x) << 32) | ((long) y));
coordinates.add(combine2Points(x, y));
}
} else {
long is = MapAlgorithms.calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY);
if (inside) {
// assert is != -1;
coordinates.add(is);
coordinates.add((((long) x) << 32) | ((long) y));
coordinates.add(combine2Points(x, y));
} else if (is != -1) {
int bx = (int) (is >> 32);
int by = (int) (is & 0xffffffff);

View file

@ -784,17 +784,15 @@ ResultPublisher* searchObjectsForRendering(SearchQuery* q, bool skipDuplicates,
bool addBasemapCoastlines = true;
bool emptyData = q->zoom > BASEMAP_ZOOM && tempResult.empty() && coastLines.empty();
if (!coastLines.empty()) {
std::vector<MapDataObject*> pcoastlines;
processCoastlines(coastLines, q->left, q->right, q->bottom, q->top, q->zoom, basemapCoastLines.empty(), pcoastlines);
addBasemapCoastlines = pcoastlines.empty() || q->zoom <= BASEMAP_ZOOM;
tempResult.insert(tempResult.end(), pcoastlines.begin(), pcoastlines.end());
bool coastlinesWereAdded = processCoastlines(coastLines, q->left, q->right, q->bottom, q->top, q->zoom,
basemapCoastLines.empty(), true, tempResult);
addBasemapCoastlines = !coastlinesWereAdded || q->zoom <= BASEMAP_ZOOM;
}
if (addBasemapCoastlines) {
addBasemapCoastlines = false;
std::vector<MapDataObject*> pcoastlines;
processCoastlines(basemapCoastLines, q->left, q->right, q->bottom, q->top, q->zoom, true, pcoastlines);
addBasemapCoastlines = pcoastlines.empty();
tempResult.insert(tempResult.end(), pcoastlines.begin(), pcoastlines.end());
bool coastlinesWereAdded = processCoastlines(basemapCoastLines, q->left, q->right, q->bottom, q->top, q->zoom,
true, true, tempResult);
addBasemapCoastlines = !coastlinesWereAdded;
}
// processCoastlines always create new objects
deleteObjects(basemapCoastLines);

View file

@ -4,12 +4,12 @@
#include "multipolygons.h"
#include "osmand_log.h"
void processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom,
bool showIncompleted, std::vector<MapDataObject*>& res) {
// returns true if coastlines were added!
bool processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom,
bool showIfThereIncompleted, bool addDebugIncompleted, std::vector<MapDataObject*>& res) {
std::vector<coordinates> completedRings;
std::vector<coordinates > uncompletedRings;
std::vector<MapDataObject*>::iterator val = coastLines.begin();
res.reserve(coastLines.size());
long long dbId = 0;
for (; val != coastLines.end(); val++) {
MapDataObject* o = *val;
@ -44,14 +44,23 @@ void processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
}
if (completedRings.size() == 0 && uncompletedRings.size() == 0) {
return;
return false;
}
if (uncompletedRings.size() > 0) {
unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom);
}
if (!showIncompleted && uncompletedRings.size() > 0) {
res.clear();
return;
if (addDebugIncompleted) {
// draw uncompleted for debug purpose
for (int i = 0; i < uncompletedRings.size(); i++) {
MapDataObject* o = new MapDataObject();
o->points = uncompletedRings[i];
o->types.push_back(tag_value("natural", "coastline_broken"));
res.push_back(o);
}
}
if (!showIfThereIncompleted && uncompletedRings.size() > 0) {
return false;
}
bool clockwiseFound = false;
for (int i = 0; i < completedRings.size(); i++) {
@ -69,13 +78,6 @@ void processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int
res.push_back(o);
}
// draw uncompleted for debug purpose
for (int i = 0; i < uncompletedRings.size(); i++) {
MapDataObject* o = new MapDataObject();
o->points = uncompletedRings[i];
o->types.push_back(tag_value("natural", "coastline_broken"));
//res.push_back(o);
}
if (!clockwiseFound && uncompletedRings.size() == 0) {
// add complete water tile
MapDataObject* o = new MapDataObject();
@ -90,6 +92,7 @@ void processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int
res.push_back(o);
}
return true;
}
// Copied from MapAlgorithms