Fix basemap rendering

This commit is contained in:
Victor Shcherb 2012-04-10 00:40:09 +02:00
parent 3867c3ef57
commit 4367dda5a4
7 changed files with 245 additions and 153 deletions

View file

@ -46,7 +46,7 @@ public class BinaryInspector {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
inspector(args); inspector(args);
// test cases show info // test cases show info
inspector(new String[]{"/home/victor/projects/OsmAnd/data/osm-gen/basemap_coastlines.obf"}); inspector(new String[]{"-vmap", "-zoom=3","/home/victor/projects/OsmAnd/data/osm-gen/basemap_all.obf"});
// test case extract parts // test case extract parts

View file

@ -8,6 +8,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -15,6 +16,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import net.osmand.Algoritms; import net.osmand.Algoritms;
import net.osmand.binary.OsmandOdb.MapData; import net.osmand.binary.OsmandOdb.MapData;
import net.osmand.binary.OsmandOdb.MapDataBlock; import net.osmand.binary.OsmandOdb.MapDataBlock;
@ -26,7 +28,7 @@ import net.osmand.osm.MapUtils;
import net.osmand.osm.Node; import net.osmand.osm.Node;
import net.osmand.osm.Way; import net.osmand.osm.Way;
import net.osmand.osm.WayChain; import net.osmand.osm.WayChain;
import net.osmand.osm.OSMSettings.OSMTagKey; import net.osmand.osm.MapRenderingTypes.MapRulType;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.tools.bzip2.CBZip2InputStream; import org.apache.tools.bzip2.CBZip2InputStream;
@ -46,6 +48,10 @@ public class BasemapProcessor {
private static final int BITS_COUNT = (1 << TILE_ZOOMLEVEL) * (1 << TILE_ZOOMLEVEL); private static final int BITS_COUNT = (1 << TILE_ZOOMLEVEL) * (1 << TILE_ZOOMLEVEL);
private BitSet seaTileInfo = new BitSet(BITS_COUNT); private BitSet seaTileInfo = new BitSet(BITS_COUNT);
private BitSet landTileInfo = new BitSet(BITS_COUNT); private BitSet landTileInfo = new BitSet(BITS_COUNT);
private TIntArrayList typeUse = new TIntArrayList();
List<MapRulType> tempNameUse = new ArrayList<MapRenderingTypes.MapRulType>();
TIntArrayList addtypeUse = new TIntArrayList(8);
Map<MapRulType, String> namesUse = new LinkedHashMap<MapRenderingTypes.MapRulType, String>();
private final int zoomWaySmothness; private final int zoomWaySmothness;
private final MapRenderingTypes renderingTypes; private final MapRenderingTypes renderingTypes;
@ -67,7 +73,7 @@ public class BasemapProcessor {
} }
SimplisticQuadTree[] children = null; SimplisticQuadTree[] children = null;
Map<MapZoomPair,List<Way>> coastlines = null; Map<MapZoomPair,List<SimplisticBinaryData>> dataObjects = null;
public SimplisticQuadTree[] getAllChildren(){ public SimplisticQuadTree[] getAllChildren(){
@ -79,23 +85,23 @@ public class BasemapProcessor {
return children != null; return children != null;
} }
public void addCoastline(MapZoomPair p, Way w){ public void addQuadData(MapZoomPair p, SimplisticBinaryData w){
if(coastlines == null) { if(dataObjects == null) {
coastlines = new LinkedHashMap<MapZooms.MapZoomPair, List<Way>>(); dataObjects = new LinkedHashMap<MapZooms.MapZoomPair, List<SimplisticBinaryData>>();
} }
if(!coastlines.containsKey(p)){ if(!dataObjects.containsKey(p)){
coastlines.put(p, new ArrayList<Way>()); dataObjects.put(p, new ArrayList<SimplisticBinaryData>());
} }
coastlines.get(p).add(w); dataObjects.get(p).add(w);
} }
public boolean coastlinesDefined(MapZoomPair p){ public boolean dataIsDefined(MapZoomPair p){
return coastlines != null && coastlines.get(p) != null; return dataObjects != null && dataObjects.get(p) != null;
} }
public List<Way> getCoastlines(MapZoomPair p) { public List<SimplisticBinaryData> getData(MapZoomPair p) {
return coastlines.get(p); return dataObjects.get(p);
} }
public SimplisticQuadTree getOrCreateSubTree(int x, int y, int zm) { public SimplisticQuadTree getOrCreateSubTree(int x, int y, int zm) {
@ -122,7 +128,15 @@ public class BasemapProcessor {
} }
} }
} }
}
private static class SimplisticBinaryData {
// consequent 31 coordinates
public byte[] coordinates;
public int[] types;
public int[] addTypes;
public long id = -500;
public Map<MapRulType, String> names;
} }
@ -265,7 +279,7 @@ public class BasemapProcessor {
public void writeCoastlinesFile(BinaryMapIndexWriter writer, String regionName) throws IOException { public void writeBasemapFile(BinaryMapIndexWriter writer, String regionName) throws IOException {
writer.startWriteMapIndex(regionName); writer.startWriteMapIndex(regionName);
// write map encoding rules // write map encoding rules
writer.writeMapEncodingRules(renderingTypes.getEncodingRuleTypes()); writer.writeMapEncodingRules(renderingTypes.getEncodingRuleTypes());
@ -292,36 +306,37 @@ public class BasemapProcessor {
private void writeBinaryMapBlock(SimplisticQuadTree simplisticQuadTree, BinaryMapIndexWriter writer, private void writeBinaryMapBlock(SimplisticQuadTree simplisticQuadTree, BinaryMapIndexWriter writer,
Map<SimplisticQuadTree, BinaryFileReference> refs, MapZoomPair p) throws IOException { Map<SimplisticQuadTree, BinaryFileReference> refs, MapZoomPair p) throws IOException {
Iterator<Entry<SimplisticQuadTree, BinaryFileReference>> it = refs.entrySet().iterator(); Iterator<Entry<SimplisticQuadTree, BinaryFileReference>> it = refs.entrySet().iterator();
TIntArrayList type = new TIntArrayList();
type.add(renderingTypes.getCoastlineRuleType().getTargetId());
while(it.hasNext()) { while(it.hasNext()) {
Entry<SimplisticQuadTree, BinaryFileReference> e = it.next(); Entry<SimplisticQuadTree, BinaryFileReference> e = it.next();
MapDataBlock.Builder dataBlock = MapDataBlock.newBuilder(); MapDataBlock.Builder dataBlock = MapDataBlock.newBuilder();
SimplisticQuadTree quad = e.getKey(); SimplisticQuadTree quad = e.getKey();
Map<String, Integer> stringTable = new LinkedHashMap<String, Integer> ();
for (Way w : quad.getCoastlines(p)) { for (SimplisticBinaryData w : quad.getData(p)) {
dataBlock.setBaseId(w.getId()); dataBlock.setBaseId(w.id);
List<Node> res = new ArrayList<Node>(); int[] wts = null;
MapAlgorithms.simplifyDouglasPeucker(w.getNodes(), p.getMaxZoom() - 1 + 8 + zoomWaySmothness, 3, res); int[] wats = null;
ByteArrayOutputStream bcoordinates = new ByteArrayOutputStream(); if(w.types != null ){
for (Node n : res) { wts = new int[w.types.length];
if (n != null) { for (int j = 0; j < w.types.length; j ++) {
int y = MapUtils.get31TileNumberY(n.getLatitude()); wts[j] = renderingTypes.getTypeByInternalId(w.types[j]).getTargetId();
int x = MapUtils.get31TileNumberX(n.getLongitude()); }
Algoritms.writeInt(bcoordinates, x); }
Algoritms.writeInt(bcoordinates, y); if(w.addTypes != null){
wats = new int[w.addTypes.length];
for (int j = 0; j < w.addTypes.length; j ++) {
wats[j] = renderingTypes.getTypeByInternalId(w.addTypes[j]).getTargetId();
} }
} }
MapData mapData = writer.writeMapData(0, MapData mapData = writer.writeMapData(0,
quad.x << (31 - quad.zoom), quad.y << (31 - quad.zoom), false, quad.x << (31 - quad.zoom), quad.y << (31 - quad.zoom), false,
bcoordinates.toByteArray(), null, type, null, null, null, dataBlock); w.coordinates, null, wts, wats, w.names, stringTable, dataBlock);
if (mapData != null) { if (mapData != null) {
dataBlock.addDataObjects(mapData); dataBlock.addDataObjects(mapData);
} }
} }
writer.writeMapDataBlock(dataBlock, null, e.getValue()); writer.writeMapDataBlock(dataBlock, stringTable, e.getValue());
} }
} }
@ -331,7 +346,7 @@ public class BasemapProcessor {
int xR = ((quadTree.x + 1) << (31 - quadTree.zoom)) - 1; int xR = ((quadTree.x + 1) << (31 - quadTree.zoom)) - 1;
int yT = (quadTree.y) << (31 - quadTree.zoom); int yT = (quadTree.y) << (31 - quadTree.zoom);
int yB = ((quadTree.y + 1) << (31 - quadTree.zoom)) - 1; int yB = ((quadTree.y + 1) << (31 - quadTree.zoom)) - 1;
boolean defined = quadTree.coastlinesDefined(p); boolean defined = quadTree.dataIsDefined(p);
boolean ocean = false; boolean ocean = false;
boolean land = false; boolean land = false;
if (!defined) { if (!defined) {
@ -355,88 +370,158 @@ public class BasemapProcessor {
} }
public void processEntity(Entity e) { public void processEntity(Entity e) {
if(e instanceof Way && "coastline".equals(e.getTag(OSMTagKey.NATURAL))) { if (e instanceof Way || e instanceof Node) {
processCoastline((Way) e); for (int level = 0; level < mapZooms.getLevels().size(); level++) {
renderingTypes.encodeEntityWithType(e, mapZooms.getLevel(level).getMaxZoom(), typeUse, addtypeUse, namesUse, tempNameUse);
if (typeUse.isEmpty()) {
continue;
}
MapZoomPair zoomPair = mapZooms.getLevel(level);
if (e instanceof Way) {
if(((Way) e).getNodes().size() < 2){
continue;
}
if ("coastline".equals(e.getTag("natural")) || !Algoritms.isEmpty(e.getTag("admin_level"))) {
splitContinuousWay(((Way) e).getNodes(), typeUse.toArray(), !addtypeUse.isEmpty() ? addtypeUse.toArray() : null,
zoomPair, quadTrees[level]);
} else {
List<Node> ns = ((Way) e).getNodes();
int z = getViewZoom(zoomPair);
int tilex = 0;
int tiley = 0;
boolean sameTile = false;
while (!sameTile) {
tilex = (int) MapUtils.getTileNumberX(z, ns.get(0).getLongitude());
tiley = (int) MapUtils.getTileNumberY(z, ns.get(0).getLatitude());
sameTile = true;
for (int i = 1; i < ns.size(); i++) {
int tx = (int) MapUtils.getTileNumberX(z, ns.get(i).getLongitude());
int ty = (int) MapUtils.getTileNumberY(z, ns.get(i).getLatitude());
if (tx != tilex || ty != tiley) {
sameTile = false;
break;
}
}
if (!sameTile) {
z--;
}
}
List<Node> res = new ArrayList<Node>();
MapAlgorithms.simplifyDouglasPeucker(ns, zoomPair.getMaxZoom() - 1 + 8 + zoomWaySmothness, 3, res);
addSimplisticData(res, typeUse.toArray(), !addtypeUse.isEmpty() ? addtypeUse.toArray() : null, zoomPair,
quadTrees[level], z, tilex, tiley, namesUse.isEmpty() ? null : new LinkedHashMap<MapRenderingTypes.MapRulType, String>(namesUse));
}
} else {
int z = getViewZoom(zoomPair);
int tilex = (int) MapUtils.getTileNumberX(z, ((Node) e).getLongitude());
int tiley = (int) MapUtils.getTileNumberY(z, ((Node) e).getLatitude());
addSimplisticData(Collections.singletonList((Node)e), typeUse.toArray(), !addtypeUse.isEmpty() ? addtypeUse.toArray() : null, zoomPair,
quadTrees[level], z, tilex, tiley, namesUse.isEmpty() ? null : new LinkedHashMap<MapRenderingTypes.MapRulType, String>(namesUse));
}
}
} }
} }
public void processCoastline(Way e) { public void splitContinuousWay(List<Node> ns, int[] types, int[] addTypes, MapZoomPair zoomPair, SimplisticQuadTree quadTree) {
renderingTypes.getCoastlineRuleType().updateFreq(); int z = getViewZoom(zoomPair);
int ij = 0; int i = 1;
for(MapZoomPair zoomPair : mapZooms.getLevels()) { Node prevNode = ns.get(0);
SimplisticQuadTree quadTree = quadTrees[ij++]; int px31 = MapUtils.get31TileNumberX(prevNode.getLongitude());
int z = Math.min((zoomPair.getMinZoom() + zoomPair.getMaxZoom()) / 2 - 1, zoomPair.getMinZoom() + 1); int py31 = MapUtils.get31TileNumberY(prevNode.getLatitude());
List<Node> ns = e.getNodes(); while (i < ns.size()) {
if(ns.size() < 2) { List<Node> w = new ArrayList<Node>();
return; w.add(prevNode);
} int tilex = px31 >> (31 - z);
int i = 1; int tiley = py31 >> (31 - z);
Node prevNode = ns.get(0); boolean sameTile = true;
int px31 = MapUtils.get31TileNumberX(prevNode.getLongitude()); wayConstruct: while (sameTile && i < ns.size()) {
int py31 = MapUtils.get31TileNumberY(prevNode.getLatitude()); Node next = ns.get(i);
while(i<ns.size()) { int ntilex = (int) MapUtils.getTileNumberX(z, next.getLongitude());
Way w = new Way(-1000); int ntiley = (int) MapUtils.getTileNumberY(z, next.getLatitude());
w.addNode(prevNode); if (ntilex == tilex && tiley == ntiley) {
int tilex = px31 >> (31 - z); sameTile = true;
int tiley = py31 >> (31 - z); w.add(next);
boolean sameTile = true; prevNode = next;
wayConstruct : while(sameTile && i<ns.size()) { px31 = MapUtils.get31TileNumberX(prevNode.getLongitude());
Node next = ns.get(i); py31 = MapUtils.get31TileNumberY(prevNode.getLatitude());
int ntilex = (int) MapUtils.getTileNumberX(z, next.getLongitude()); i++;
int ntiley = (int) MapUtils.getTileNumberY(z, next.getLatitude()); } else {
if(ntilex == tilex && tiley == ntiley) { int nx31 = MapUtils.get31TileNumberX(next.getLongitude());
sameTile = true; int ny31 = MapUtils.get31TileNumberY(next.getLatitude());
w.addNode(next); // increase boundaries to drop into another tile
prevNode = next; int leftX = (tilex << (31 - z)) - 1;
px31 = MapUtils.get31TileNumberX(prevNode.getLongitude()); int rightX = (tilex + 1) << (31 - z);
py31 = MapUtils.get31TileNumberY(prevNode.getLatitude()); if (rightX < 0) {
rightX = Integer.MAX_VALUE;
}
int topY = (tiley << (31 - z)) - 1;
int bottomY = (tiley + 1) << (31 - z);
if (bottomY < 0) {
bottomY = Integer.MAX_VALUE;
}
long inter = MapAlgorithms.calculateIntersection(px31, py31, nx31, ny31, leftX, rightX, bottomY, topY);
int cy31 = (int) inter;
int cx31 = (int) (inter >> 32l);
if (inter == -1) {
cx31 = nx31;
cy31 = ny31;
i++; i++;
} else { logMapDataWarn.warn("Can't find intersection for " + MapUtils.get31LongitudeX(px31) + ","
int nx31 = MapUtils.get31TileNumberX(next.getLongitude()); + MapUtils.get31LatitudeY(py31) + " - " + MapUtils.get31LongitudeX(nx31) + ","
int ny31 = MapUtils.get31TileNumberY(next.getLatitude()); + MapUtils.get31LatitudeY(ny31));
// increase boundaries to drop into another tile
int leftX = (tilex << (31 - z)) - 1;
int rightX = (tilex + 1) << (31 - z);
if (rightX < 0) {
rightX = Integer.MAX_VALUE;
}
int topY = (tiley << (31 - z)) - 1;
int bottomY = (tiley + 1) << (31 - z);
if (bottomY < 0) {
bottomY = Integer.MAX_VALUE;
}
long inter = MapAlgorithms.calculateIntersection(px31, py31, nx31, ny31, leftX, rightX, bottomY, topY);
int cy31 = (int) inter;
int cx31 = (int) (inter >> 32l);
if (inter == -1) {
cx31 = nx31;
cy31 = ny31;
i++;
logMapDataWarn.warn("Can't find intersection for " + MapUtils.get31LongitudeX(px31) + ","
+ MapUtils.get31LatitudeY(py31) + " - " + +MapUtils.get31LongitudeX(nx31) + ","
+ MapUtils.get31LatitudeY(ny31));
}
prevNode = new Node(MapUtils.get31LatitudeY(cy31), MapUtils.get31LongitudeX(cx31), -1000);
px31 = cx31;
py31 = cy31;
w.addNode(prevNode);
break wayConstruct;
} }
}
SimplisticQuadTree quad = quadTree.getOrCreateSubTree(tilex, tiley, z);
if (quad == null) {
if (logMapDataWarn != null) {
logMapDataWarn.error("Tile " + tilex + " / " + tiley + " at " + z + " can not be found");
} else {
System.err.println("Tile " + tilex + " / " + tiley + " at " + z + " can not be found");
}
}
quad.addCoastline(zoomPair, w);
prevNode = new Node(MapUtils.get31LatitudeY(cy31), MapUtils.get31LongitudeX(cx31), -1000);
px31 = cx31;
py31 = cy31;
w.add(prevNode);
break wayConstruct;
}
}
List<Node> res = new ArrayList<Node>();
MapAlgorithms.simplifyDouglasPeucker(w, zoomPair.getMaxZoom() - 1 + 8 + zoomWaySmothness, 3, res);
addSimplisticData(res, types, addTypes, zoomPair, quadTree, z, tilex, tiley, null);
}
}
private void addSimplisticData(List<Node> res, int[] types, int[] addTypes, MapZoomPair zoomPair, SimplisticQuadTree quadTree, int z, int tilex,
int tiley, Map<MapRulType, String> names) {
SimplisticQuadTree quad = quadTree.getOrCreateSubTree(tilex, tiley, z);
if (quad == null) {
if (logMapDataWarn != null) {
logMapDataWarn.error("Tile " + tilex + " / " + tiley + " at " + z + " can not be found");
} else {
System.err.println("Tile " + tilex + " / " + tiley + " at " + z + " can not be found");
} }
} }
ByteArrayOutputStream bcoordinates = new ByteArrayOutputStream();
for (Node n : res) {
if (n != null) {
int y = MapUtils.get31TileNumberY(n.getLatitude());
int x = MapUtils.get31TileNumberX(n.getLongitude());
try {
Algoritms.writeInt(bcoordinates, x);
Algoritms.writeInt(bcoordinates, y);
} catch (IOException e1) {
throw new IllegalStateException(e1);
}
}
}
SimplisticBinaryData data = new SimplisticBinaryData();
// not needed
// data.id = w.getId();
data.coordinates = bcoordinates.toByteArray();
data.types = types;
data.addTypes = addTypes;
data.names = names;
quad.addQuadData(zoomPair, data);
}
private int getViewZoom(MapZoomPair zoomPair) {
return Math.min((zoomPair.getMinZoom() + zoomPair.getMaxZoom()) / 2 - 1, zoomPair.getMinZoom() + 1);
} }

View file

@ -352,8 +352,8 @@ public class BinaryMapIndexWriter {
private TByteArrayList mapDataBuf = new TByteArrayList(); private TByteArrayList mapDataBuf = new TByteArrayList();
public MapData writeMapData(long diffId, int pleft, int ptop, boolean area, byte[] coordinates, byte[] innerPolygonTypes, TIntArrayList typeUse, public MapData writeMapData(long diffId, int pleft, int ptop, boolean area, byte[] coordinates, byte[] innerPolygonTypes, int[] typeUse,
TIntArrayList addtypeUse, Map<MapRulType, String> names, Map<String, Integer> stringTable, MapDataBlock.Builder dataBlock) int[] addtypeUse, Map<MapRulType, String> names, Map<String, Integer> stringTable, MapDataBlock.Builder dataBlock)
throws IOException { throws IOException {
MapData.Builder data = MapData.newBuilder(); MapData.Builder data = MapData.newBuilder();
@ -409,16 +409,16 @@ public class BinaryMapIndexWriter {
} }
mapDataBuf.clear(); mapDataBuf.clear();
for (int i = 0; i < typeUse.size() ; i++) { for (int i = 0; i < typeUse.length ; i++) {
writeRawVarint32(mapDataBuf, typeUse.get(i));; writeRawVarint32(mapDataBuf, typeUse[i]);
} }
data.setTypes(ByteString.copyFrom(mapDataBuf.toArray())); data.setTypes(ByteString.copyFrom(mapDataBuf.toArray()));
TYPES_SIZE += CodedOutputStream.computeTagSize(OsmandOdb.MapData.TYPES_FIELD_NUMBER) TYPES_SIZE += CodedOutputStream.computeTagSize(OsmandOdb.MapData.TYPES_FIELD_NUMBER)
+ CodedOutputStream.computeRawVarint32Size(mapDataBuf.size()) + mapDataBuf.size(); + CodedOutputStream.computeRawVarint32Size(mapDataBuf.size()) + mapDataBuf.size();
if (addtypeUse != null && addtypeUse.size() > 0) { if (addtypeUse != null && addtypeUse.length > 0) {
mapDataBuf.clear(); mapDataBuf.clear();
for (int i = 0; i < addtypeUse.size() ; i++) { for (int i = 0; i < addtypeUse.length ; i++) {
writeRawVarint32(mapDataBuf, addtypeUse.get(i));; writeRawVarint32(mapDataBuf, addtypeUse[i]);
} }
data.setAdditionalTypes(ByteString.copyFrom(mapDataBuf.toArray())); data.setAdditionalTypes(ByteString.copyFrom(mapDataBuf.toArray()));
TYPES_SIZE += CodedOutputStream.computeTagSize(OsmandOdb.MapData.ADDITIONALTYPES_FIELD_NUMBER); TYPES_SIZE += CodedOutputStream.computeTagSize(OsmandOdb.MapData.ADDITIONALTYPES_FIELD_NUMBER);

View file

@ -241,7 +241,9 @@ public class IndexCreator {
@Override @Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity entity) { public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity entity) {
indexAddressCreator.registerCityIfNeeded(entity); if(indexAddressCreator != null) {
indexAddressCreator.registerCityIfNeeded(entity);
}
// accept to allow db creator parse it // accept to allow db creator parse it
return true; return true;
} }
@ -275,11 +277,11 @@ public class IndexCreator {
} }
} }
private boolean createPlainOsmDb(IProgress progress, File readFile, IOsmStorageFilter addFilter) throws SQLException, FileNotFoundException, IOException, SAXException{ private boolean createPlainOsmDb(IProgress progress, File readFile, IOsmStorageFilter addFilter, boolean deletePrevious) throws SQLException, FileNotFoundException, IOException, SAXException{
// dbFile = new File(workingDir, TEMP_NODES_DB); // dbFile = new File(workingDir, TEMP_NODES_DB);
// initialize db file // initialize db file
boolean loadFromExistingFile = dbFile != null && dialect.databaseFileExists(dbFile); boolean loadFromExistingFile = dbFile != null && dialect.databaseFileExists(dbFile) && !deletePrevious;
if (dbFile == null) { if (dbFile == null || deletePrevious) {
dbFile = new File(workingDir, TEMP_NODES_DB); dbFile = new File(workingDir, TEMP_NODES_DB);
// to save space // to save space
if (dialect.databaseFileExists(dbFile)) { if (dialect.databaseFileExists(dbFile)) {
@ -362,7 +364,7 @@ public class IndexCreator {
for (File readFile : readFiles) { for (File readFile : readFiles) {
this.accessor = new OsmDbAccessor(); this.accessor = new OsmDbAccessor();
createPlainOsmDb(progress, readFile, addFilter); createPlainOsmDb(progress, readFile, addFilter, true);
// 2. Create index connections and index structure // 2. Create index connections and index structure
progress.setGeneralProgress("[50 / 100]"); progress.setGeneralProgress("[50 / 100]");
@ -398,7 +400,7 @@ public class IndexCreator {
progress.setGeneralProgress("[95 of 100]"); progress.setGeneralProgress("[95 of 100]");
progress.startTask("Writing map index to binary file...", -1); progress.startTask("Writing map index to binary file...", -1);
processor.writeCoastlinesFile(writer, regionName); processor.writeBasemapFile(writer, regionName);
progress.finishTask(); progress.finishTask();
writer.close(); writer.close();
mapRAFile.close(); mapRAFile.close();
@ -460,7 +462,7 @@ public class IndexCreator {
try { try {
// //////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////
// 1. creating nodes db to fast access for all nodes and simply import all relations, ways, nodes to it // 1. creating nodes db to fast access for all nodes and simply import all relations, ways, nodes to it
boolean loadFromExistingFile = createPlainOsmDb(progress, readFile, addFilter); boolean loadFromExistingFile = createPlainOsmDb(progress, readFile, addFilter, false);
// do not create temp map file and rtree files // do not create temp map file and rtree files
if (recreateOnlyBinaryFile) { if (recreateOnlyBinaryFile) {
@ -715,18 +717,24 @@ public class IndexCreator {
creator.setZoomWaySmothness(2); creator.setZoomWaySmothness(2);
MapRenderingTypes rt = MapRenderingTypes.getDefault();// new MapRenderingTypes("/home/victor/projects/OsmAnd/data/testdata/roads_rendering_types.xml"); MapRenderingTypes rt = MapRenderingTypes.getDefault();// new MapRenderingTypes("/home/victor/projects/OsmAnd/data/testdata/roads_rendering_types.xml");
MapZooms zooms = MapZooms.getDefault(); // MapZooms.parseZooms("15-"); MapZooms zooms = MapZooms.getDefault(); // MapZooms.parseZooms("15-");
creator.setNodesDBFile(new File("/home/victor/projects/OsmAnd/data/osm-gen/nodes.tmp.odb")); // creator.setNodesDBFile(new File("/home/victor/projects/OsmAnd/data/osm-gen/nodes.tmp.odb"));
// creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/luxembourg.osm.pbf"), // creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/luxembourg.osm.pbf"),
// creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/cuba2.osm.bz2"), // creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/cuba2.osm.bz2"),
// new ConsoleProgressImplementation(1), null, zooms, rt, log); // new ConsoleProgressImplementation(1), null, zooms, rt, log);
// ;6-8;9-14
zooms = MapZooms.parseZooms("1-3;4-6;7-9;10-"); // zooms = MapZooms.parseZooms("1-3;4-6;7-9;10-");
creator.setMapFileName("basemap_coastlines.obf"); // creator.setMapFileName("basemap_coastlines.obf");
zooms = MapZooms.parseZooms("1-3;4-5;6-7;8-9;10-");
creator.setMapFileName("basemap_a.obf");
File basemapParent = new File("/home/victor/projects/OsmAnd/data/basemap");
creator.generateBasemapIndex(new ConsoleProgressImplementation(1), null, zooms, rt, log, "basemap", creator.generateBasemapIndex(new ConsoleProgressImplementation(1), null, zooms, rt, log, "basemap",
new File("/home/victor/projects/OsmAnd/data/basemap/10m_coastline_out.osm")); new File(basemapParent, "10m_coastline_out.osm"),
new File(basemapParent, "10m_admin_level_out.osm"),
new File(basemapParent, "10m_rivers.osm"),
new File(basemapParent, "10m_lakes_out.osm"),
new File(basemapParent, "10m_populated_places_out.osm")
);
// world generation // world generation
// MapZooms mapZooms = new MapZooms(); // MapZooms mapZooms = new MapZooms();
// MapZoomPair pair1 = new MapZooms.MapZoomPair(1, 3); // MapZoomPair pair1 = new MapZooms.MapZoomPair(1, 3);

View file

@ -2,7 +2,6 @@ package net.osmand.data.preparation;
import gnu.trove.list.array.TIntArrayList; import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.procedure.TObjectProcedure;
import gnu.trove.set.hash.TLongHashSet; import gnu.trove.set.hash.TLongHashSet;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -27,7 +26,6 @@ import net.osmand.binary.OsmandOdb.MapData;
import net.osmand.binary.OsmandOdb.MapDataBlock; import net.osmand.binary.OsmandOdb.MapDataBlock;
import net.osmand.data.Boundary; import net.osmand.data.Boundary;
import net.osmand.data.MapAlgorithms; import net.osmand.data.MapAlgorithms;
import net.osmand.data.WayBoundary;
import net.osmand.osm.Entity; import net.osmand.osm.Entity;
import net.osmand.osm.Entity.EntityId; import net.osmand.osm.Entity.EntityId;
import net.osmand.osm.Entity.EntityType; import net.osmand.osm.Entity.EntityType;
@ -35,7 +33,6 @@ import net.osmand.osm.MapRenderingTypes;
import net.osmand.osm.MapRenderingTypes.MapRulType; import net.osmand.osm.MapRenderingTypes.MapRulType;
import net.osmand.osm.MapUtils; import net.osmand.osm.MapUtils;
import net.osmand.osm.Node; import net.osmand.osm.Node;
import net.osmand.osm.WayChain;
import net.osmand.osm.OSMSettings.OSMTagKey; import net.osmand.osm.OSMSettings.OSMTagKey;
import net.osmand.osm.Relation; import net.osmand.osm.Relation;
import net.osmand.osm.Way; import net.osmand.osm.Way;
@ -72,9 +69,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
List<MapRulType> tempNameUse = new ArrayList<MapRenderingTypes.MapRulType>(); List<MapRulType> tempNameUse = new ArrayList<MapRenderingTypes.MapRulType>();
Map<MapRulType, String> namesUse = new LinkedHashMap<MapRenderingTypes.MapRulType, String>(); Map<MapRulType, String> namesUse = new LinkedHashMap<MapRenderingTypes.MapRulType, String>();
TIntArrayList addtypeUse = new TIntArrayList(8); TIntArrayList addtypeUse = new TIntArrayList(8);
List<Long> restrictionsUse = new ArrayList<Long>(8);
private BasemapProcessor basemapProcessor;
private PreparedStatement mapBinaryStat; private PreparedStatement mapBinaryStat;
private PreparedStatement mapLowLevelBinaryStat; private PreparedStatement mapLowLevelBinaryStat;
private int lowLevelWays = -1; private int lowLevelWays = -1;
@ -91,7 +86,6 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
this.mapZooms = mapZooms; this.mapZooms = mapZooms;
this.zoomWaySmothness = zoomWaySmothness; this.zoomWaySmothness = zoomWaySmothness;
this.renderingTypes = renderingTypes; this.renderingTypes = renderingTypes;
this.basemapProcessor = new BasemapProcessor(logMapDataWarn, mapZooms, renderingTypes, zoomWaySmothness);
lowLevelWays = -1; lowLevelWays = -1;
} }
@ -208,13 +202,13 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
List<Node> outerWay = outerWaySrc; List<Node> outerWay = outerWaySrc;
int zoomToSimplify = mapZooms.getLevel(level).getMaxZoom() - 1; int zoomToSimplify = mapZooms.getLevel(level).getMaxZoom() - 1;
if (zoomToSimplify < 15) { if (zoomToSimplify < 15) {
outerWay = simplifyCycleWay(outerWay, zoomToSimplify); outerWay = simplifyCycleWay(outerWay, zoomToSimplify, zoomWaySmothness);
if (outerWay == null) { if (outerWay == null) {
continue nextZoom; continue nextZoom;
} }
List<List<Node>> newinnerWays = new ArrayList<List<Node>>(); List<List<Node>> newinnerWays = new ArrayList<List<Node>>();
for (List<Node> ls : innerWays) { for (List<Node> ls : innerWays) {
ls = simplifyCycleWay(ls, zoomToSimplify); ls = simplifyCycleWay(ls, zoomToSimplify, zoomWaySmothness);
if (ls != null) { if (ls != null) {
newinnerWays.add(ls); newinnerWays.add(ls);
} }
@ -299,7 +293,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
} }
} }
protected List<Node> simplifyCycleWay(List<Node> ns, int zoom) throws SQLException { public static List<Node> simplifyCycleWay(List<Node> ns, int zoom, int zoomWaySmothness) throws SQLException {
if (checkForSmallAreas(ns, zoom + Math.min(zoomWaySmothness / 2, 3), 2, 4)) { if (checkForSmallAreas(ns, zoom + Math.min(zoomWaySmothness / 2, 3), 2, 4)) {
return null; return null;
} }
@ -339,7 +333,6 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
} }
public void processingLowLevelWays(IProgress progress) throws SQLException { public void processingLowLevelWays(IProgress progress) throws SQLException {
restrictionsUse.clear();
mapLowLevelBinaryStat.executeBatch(); mapLowLevelBinaryStat.executeBatch();
mapLowLevelBinaryStat.close(); mapLowLevelBinaryStat.close();
pStatements.remove(mapLowLevelBinaryStat); pStatements.remove(mapLowLevelBinaryStat);
@ -473,7 +466,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
} }
private boolean checkForSmallAreas(List<Node> nodes, int zoom, int minz, int maxz) { private static boolean checkForSmallAreas(List<Node> nodes, int zoom, int minz, int maxz) {
int minX = Integer.MAX_VALUE; int minX = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE; int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE; int minY = Integer.MAX_VALUE;
@ -529,7 +522,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
if (zoomToSimplify < 15) { if (zoomToSimplify < 15) {
boolean cycle = ((Way) e).getFirstNodeId() == ((Way) e).getLastNodeId(); boolean cycle = ((Way) e).getFirstNodeId() == ((Way) e).getLastNodeId();
if (cycle) { if (cycle) {
res = simplifyCycleWay(((Way) e).getNodes(), zoomToSimplify); res = simplifyCycleWay(((Way) e).getNodes(), zoomToSimplify, zoomWaySmothness);
} else { } else {
String ename = namesUse.get(renderingTypes.getNameRuleType()); String ename = namesUse.get(renderingTypes.getNameRuleType());
insertLowLevelMapBinaryObject(level, zoomToSimplify, typeUse, addtypeUse, id, ((Way) e).getNodes(), ename); insertLowLevelMapBinaryObject(level, zoomToSimplify, typeUse, addtypeUse, id, ((Way) e).getNodes(), ename);
@ -652,17 +645,17 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
tempNames.clear(); tempNames.clear();
decodeNames(rs.getString(6), tempNames); decodeNames(rs.getString(6), tempNames);
byte[] types = rs.getBytes(4); byte[] types = rs.getBytes(4);
typeUse.clear(); int[] typeUse = new int[types.length / 2];
for (int j = 0; j < types.length; j += 2) { for (int j = 0; j < types.length; j += 2) {
int ids = Algoritms.parseSmallIntFromBytes(types, j); int ids = Algoritms.parseSmallIntFromBytes(types, j);
typeUse.add(renderingTypes.getTypeByInternalId(ids).getTargetId()); typeUse[j / 2] = renderingTypes.getTypeByInternalId(ids).getTargetId();
} }
byte[] addTypes = rs.getBytes(5); byte[] addTypes = rs.getBytes(5);
addtypeUse.clear(); int[] addtypeUse = new int[addTypes.length / 2];
if (addTypes != null) { if (addTypes != null) {
for (int j = 0; j < addTypes.length; j += 2) { for (int j = 0; j < addTypes.length; j += 2) {
int ids = Algoritms.parseSmallIntFromBytes(addTypes, j); int ids = Algoritms.parseSmallIntFromBytes(addTypes, j);
addtypeUse.add(renderingTypes.getTypeByInternalId(ids).getTargetId()); addtypeUse[j / 2] = renderingTypes.getTypeByInternalId(ids).getTargetId();
} }
} }

View file

@ -81,8 +81,8 @@
<!-- point has order 128 --> <!-- point has order 128 -->
<filter tag="" value="" point="true" order="128" objectType="1"/> <filter tag="" value="" point="true" order="128" objectType="1"/>
<!-- default polygon --> <!-- default polygon -->
<filter cycle="true" layer="-1" tag="" value="" order="1" objectType="3"/> <filter cycle="true" layer="-1" tag="" value="" order="3" objectType="3"/>
<filter area="true" layer="-1" tag="" value="" order="1" objectType="3"/> <filter area="true" layer="-1" tag="" value="" order="3" objectType="3"/>
<!-- default line --> <!-- default line -->
<filter layer="-1" tag="" value="" order="10" objectType="2"/> <filter layer="-1" tag="" value="" order="10" objectType="2"/>
<filter tag="" value="" order="11" objectType="2"/> <filter tag="" value="" order="11" objectType="2"/>
@ -229,13 +229,13 @@
<filter tag="landuse" value="reservoir" order="5"/> <filter tag="landuse" value="reservoir" order="5"/>
<filter tag="landuse" value="water" order="5"/> <filter tag="landuse" value="water" order="5"/>
<filter tag="landuse" value="" order="1"/> <filter tag="landuse" value="" order="3"/>
<filter tag="natural" value="water" order="5"/> <filter tag="natural" value="water" order="5"/>
<filter tag="natural" value="bay" order="5"/> <filter tag="natural" value="bay" order="5"/>
<filter tag="natural" value="land" order="6"/> <filter tag="natural" value="land" order="2"/>
<filter tag="natural" value="coastline" order="1"/> <filter tag="natural" value="coastline" order="1"/>
<filter tag="natural" value="" order="1"/> <filter tag="natural" value="" order="3"/>
</group> </group>

View file

@ -374,14 +374,14 @@ public class MapRenderRepositories {
} }
String coastlineTime = ""; String coastlineTime = "";
boolean addBasemapCoastlines = zoom <= BASEMAP_ZOOM; boolean addBasemapCoastlines = true;
boolean emptyData = zoom > BASEMAP_ZOOM && tempResult.isEmpty() && coastLines.isEmpty() ; boolean emptyData = zoom > BASEMAP_ZOOM && tempResult.isEmpty() && coastLines.isEmpty() ;
if(!coastLines.isEmpty()) { if(!coastLines.isEmpty()) {
long ms = System.currentTimeMillis(); long ms = System.currentTimeMillis();
List<BinaryMapDataObject> pcoastlines = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom, List<BinaryMapDataObject> pcoastlines = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
basemapCoastLines.isEmpty()); basemapCoastLines.isEmpty());
addBasemapCoastlines = pcoastlines.isEmpty() || addBasemapCoastlines; addBasemapCoastlines = pcoastlines.isEmpty() || zoom <= BASEMAP_ZOOM;
tempResult.addAll(pcoastlines); tempResult.addAll(pcoastlines);
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )"; coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
} else if(basemapCoastLines.isEmpty() && mi != null){ } else if(basemapCoastLines.isEmpty() && mi != null){
@ -397,10 +397,16 @@ public class MapRenderRepositories {
coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )"; coastlineTime = "(coastline " + (System.currentTimeMillis() - ms) + " ms )";
} }
if(emptyData && tempResult.size() > 0){ if(emptyData && tempResult.size() > 0){
BinaryMapDataObject o = tempResult.get(0); // message
BinaryMapDataObject p = tempResult.get(0);
// avoid overflow int errors
BinaryMapDataObject o = new BinaryMapDataObject(new int[] { leftX + (rightX - leftX) / 2, topY + (bottomY - topY) / 2 },
new int[] { p.getMapIndex().coastlineEncodingType }, null, -1);
o.setMapIndex(p.getMapIndex());
o.putObjectName(o.getMapIndex().nameEncodingType, context.getString(R.string.switch_to_raster_map_to_see)); o.putObjectName(o.getMapIndex().nameEncodingType, context.getString(R.string.switch_to_raster_map_to_see));
tempResult.add(o);
} }
if(zoom <= BASEMAP_ZOOM || tempResult.isEmpty()) { if(zoom <= BASEMAP_ZOOM || emptyData) {
tempResult.addAll(basemapResult); tempResult.addAll(basemapResult);
} }