Buildings: handle references with id (OpenStreetMap, Mapzen) (#448)

This commit is contained in:
Gustl22 2017-11-17 20:59:06 +01:00 committed by Emux
parent f884c17195
commit 8f4e9967f0
No known key found for this signature in database
GPG Key ID: 89C6921D7AF2BDD0
2 changed files with 118 additions and 6 deletions

View File

@ -1,6 +1,7 @@
/*
* Copyright 2012 Hannes Janetzek
* Copyright 2016 Andrey Novikov
* Copyright 2017 Gustl22
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
@ -17,6 +18,8 @@
*/
package org.oscim.core;
import java.util.Arrays;
/**
* The MapElement class is a reusable containter for a geometry
* with tags.
@ -65,4 +68,20 @@ public class MapElement extends GeometryBuffer {
return tags.toString() + '\n' + super.toString() + '\n';
}
/**
* @return a deep copy of this MapElement
*/
public MapElement clone() {
MapElement copy = new MapElement();
copy.tags.set(this.tags.asArray());
copy.points = Arrays.copyOf(this.points, this.points.length);
copy.pointPos = this.pointPos;
copy.labelPosition = this.labelPosition;
copy.setLayer(this.layer);
copy.index = Arrays.copyOf(this.index, this.index.length);
copy.indexPos = this.indexPos;
copy.type = this.type;
return copy;
}
}

View File

@ -36,6 +36,12 @@ import org.oscim.theme.styles.ExtrusionStyle;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.utils.pool.Inlist;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class BuildingLayer extends Layer implements TileLoaderThemeHook {
private final static int BUILDING_LEVEL_HEIGHT = 280; // cm
@ -48,6 +54,21 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
private static final Object BUILDING_DATA = BuildingLayer.class.getName();
// Can replace with Multimap in Java 8
private HashMap<Integer, List<BuildingElement>> mBuildings = new HashMap<>();
class BuildingElement {
MapElement element;
ExtrusionStyle style;
boolean isPart;
BuildingElement(MapElement element, ExtrusionStyle style, boolean isPart) {
this.element = element;
this.style = style;
this.isPart = isPart;
}
}
public BuildingLayer(Map map, VectorTileLayer tileLayer) {
this(map, tileLayer, MIN_ZOOM, MAX_ZOOM);
}
@ -77,6 +98,36 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
ExtrusionStyle extrusion = (ExtrusionStyle) style.current();
// Filter all building elements
// TODO #TagFromTheme: load from theme or decode tags to generalize mapsforge tags
boolean isBuildingPart = element.tags.containsKey(Tag.KEY_BUILDING_PART)
|| (element.tags.containsKey("kind") && element.tags.getValue("kind").equals("building_part")); // Mapzen
if (element.tags.containsKey(Tag.KEY_BUILDING) || isBuildingPart
|| (element.tags.containsKey("kind") && element.tags.getValue("kind").equals("building"))) { // Mapzen
List<BuildingElement> buildingElements = mBuildings.get(tile.hashCode());
if (buildingElements == null) {
buildingElements = new ArrayList<>();
mBuildings.put(tile.hashCode(), buildingElements);
}
element = element.clone(); // Deep copy, because element will be cleared
buildingElements.add(new BuildingElement(element, extrusion, isBuildingPart));
return true;
}
// Process other elements immediately
processElement(element, extrusion, tile);
return true;
}
/**
* Process map element.
*
* @param element the map element
* @param extrusion the style of map element
* @param tile the tile which contains map element
*/
private void processElement(MapElement element, ExtrusionStyle extrusion, MapTile tile) {
int height = 0; // cm
int minHeight = 0; // cm
@ -84,7 +135,7 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
if (v != null)
height = (int) (Float.parseFloat(v) * 100);
else {
// FIXME load from theme or decode tags to generalize level/height tags
// #TagFromTheme: generalize level/height tags
if ((v = element.tags.getValue(Tag.KEY_BUILDING_LEVELS)) != null)
height = (int) (Float.parseFloat(v) * BUILDING_LEVEL_HEIGHT);
}
@ -92,9 +143,13 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
v = element.tags.getValue(Tag.KEY_MIN_HEIGHT);
if (v != null)
minHeight = (int) (Float.parseFloat(v) * 100);
else {
// #TagFromTheme: level/height tags
if ((v = element.tags.getValue(Tag.KEY_BUILDING_MIN_LEVEL)) != null)
minHeight = (int) (Float.parseFloat(v) * BUILDING_LEVEL_HEIGHT);
}
if (height == 0)
// FIXME ignore buildings containing building parts
height = extrusion.defaultHeight * 100;
ExtrusionBuckets ebs = get(tile);
@ -102,7 +157,7 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
for (ExtrusionBucket b = ebs.buckets; b != null; b = b.next()) {
if (b.colors == extrusion.colors) {
b.add(element, height, minHeight);
return true;
return;
}
}
@ -115,8 +170,45 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
extrusion.colors));
ebs.buckets.add(element, height, minHeight);
}
return true;
/**
* Process all stored map elements (here only buildings).
*
* @param tile the tile which contains stored map elements
*/
private void processElements(MapTile tile) {
if (!mBuildings.containsKey(tile.hashCode()))
return;
List<BuildingElement> tileBuildings = mBuildings.get(tile.hashCode());
Set<BuildingElement> rootBuildings = new HashSet<>();
for (BuildingElement partBuilding : tileBuildings) {
if (!partBuilding.isPart)
continue;
String refId = partBuilding.element.tags.getValue(Tag.KEY_REF); // #TagFromTheme
refId = refId == null ? partBuilding.element.tags.getValue("root_id") : refId; // Mapzen
if (refId == null)
continue;
// Search buildings which inherit parts
for (BuildingElement rootBuilding : tileBuildings) {
if (rootBuilding.isPart
|| !(refId.equals(rootBuilding.element.tags.getValue(Tag.KEY_ID))))
continue;
rootBuildings.add(rootBuilding);
break;
}
}
tileBuildings.removeAll(rootBuildings); // root buildings aren't rendered
for (BuildingElement buildingElement : tileBuildings) {
processElement(buildingElement.element, buildingElement.style, tile);
}
mBuildings.remove(tile.hashCode());
}
public static ExtrusionBuckets get(MapTile tile) {
@ -130,9 +222,10 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
@Override
public void complete(MapTile tile, boolean success) {
if (success)
if (success) {
processElements(tile);
get(tile).prepare();
else
} else
get(tile).setBuckets(null);
}