Permalink
Browse files

Mapsforge maps v5: variable tag values (#1006)

  • Loading branch information...
Gustl22 authored and devemux86 committed Oct 15, 2017
1 parent b195e86 commit 7a9b1ca4964282a078704cb3d35033aea12b4cda
Showing with 861 additions and 181 deletions.
  1. +2 −2 docs/Specification-Binary-Map-File.md
  2. +45 −21 mapsforge-map-reader/src/main/java/org/mapsforge/map/reader/MapFile.java
  3. +13 −0 mapsforge-map-reader/src/main/java/org/mapsforge/map/reader/ReadBuffer.java
  4. +1 −1 mapsforge-map-reader/src/main/java/org/mapsforge/map/reader/header/RequiredFields.java
  5. +1 −1 mapsforge-map-writer/src/main/config/mapsforge-map.properties
  6. +99 −0 mapsforge-map-writer/src/main/config/tag-mapping.xml
  7. +25 −12 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/BaseTileBasedDataProcessor.java
  8. +103 −38 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/MapFileWriter.java
  9. +153 −32 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/OSMTagMapping.java
  10. +17 −0 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/model/MapWriterConfiguration.java
  11. +12 −10 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/model/TDNode.java
  12. +11 −13 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/model/TDRelation.java
  13. +19 −27 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/model/TDWay.java
  14. +3 −0 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/osmosis/MapFileWriterFactory.java
  15. +13 −4 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/osmosis/MapFileWriterTask.java
  16. +170 −0 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/util/ColorsCSS.java
  17. +170 −20 mapsforge-map-writer/src/main/java/org/mapsforge/map/writer/util/OSMUtils.java
  18. +4 −0 resources/tag-mapping.xsd
@@ -112,7 +112,7 @@ To read the data of a specific tile in the sub-file, the position of the fixed-s
|32|yes|POI signature|If the debug bit in the file header is set:<br />`***POIStartX***` where X defines the OSM-ID of the POI; the text is always padded to 32 bytes by adding whitespaces|
|variable||position|geo coordinate difference to the top-left corner of the current tile as *`VBE-S` INT*, in the order lat-diff, lon-diff|
|1||special byte|<ul><li>1.-4. bit: layer (OSM-Tag: layer=...) + 5 (to avoid negative values)</li><li>5.-8. bit: amount of tags for the POI</li></ul>|
|variable||tag id|for each tag of the POI:<ul><li>tag id as *`VBE-U` INT*</li></ul>|
|variable||tag id|for each tag of the POI:<ul><li>tag id as *`VBE-U` INT*</li><li>variable values as different data types, whose content can be evaluated from tag's wildcard</li></ul>|
|1||flags|<ul><li>1. bit: flag for existence of a POI name</li><li>2. bit: flag for existence of a house number</li><li>3. bit: flag for existence of an elevation</li><li>4.-8. bit: reserved for future use</li></ul>|
|variable|yes|name|name of the POI as a string|
|variable|yes|house number|house number of the POI as a string|
@@ -129,7 +129,7 @@ To read the data of a specific tile in the sub-file, the position of the fixed-s
|variable||way data size|number of bytes that are needed to encode the current way as *`VBE-U` INT*, starting from the sub tile bitmap (i.e. way signature and way size are not counted)|
|2||sub tile bitmap|A tile on zoom level z is made up of exactly 16 sub tiles on zoom level z+2<br />for each sub tile (row-wise, left to right):<ul><li>1 bit that represents a flag whether the way is relevant for the sub tile</li></ul>Special case: coastline ways must always have all 16 bits set.|
|1||special byte|<ul><li>1.-4. bit: layer (OSM-Tag: layer=...) + 5 (to avoid negative values)</li><li>5.-8. bit: amount of tags for the way</li></ul>|
|variable||tag id|for each tag of the way:<ul><li>tag id as *`VBE-U` INT*</li></ul>|
|variable||tag id|for each tag of the way:<ul><li>tag id as *`VBE-U` INT*</li><li>variable values as different data types, whose content can be evaluated from tag's wildcard</li></ul>|
|1||flags|<ul><li>1. bit: flag for existence of a way name</li><li>2. bit: flag for existence of a house number</li><li>3. bit: flag for existence of a reference</li><li>4. bit: flag for existence of a label position</li><li>5. bit: flag for existence of *number of way data blocks* field<ul><li>case 0: field does not exist, number of blocks is one</li><li>case 1: field exists, more than one block</li></ul></li><li>6. bit: flag indicating encoding of way coordinate blocks<ul><li>case 0: single delta encoding</li><li>case 1: double delta encoding</li></ul></li><li>7.-8. bit: reserved for future use</li></ul>|
|variable|yes|name|name of the way as a string|
|variable|yes|house number|house number of the way as a string|
@@ -5,6 +5,7 @@
* Copyright 2015-2016 lincomatic
* Copyright 2016 bvgastel
* Copyright 2017 linuskr
* Copyright 2017 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -638,17 +639,8 @@ private MapReadResult processBlocks(QueryParameters queryParameters, SubFilePara
// bit 5-8 represent the number of tag IDs
byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK);
List<Tag> tags = new ArrayList<>();
// get the tag IDs (VBE-U)
for (byte tagIndex = numberOfTags; tagIndex != 0; --tagIndex) {
int tagId = readBuffer.readUnsignedInt();
if (tagId < 0 || tagId >= poiTags.length) {
LOGGER.warning("invalid POI tag ID: " + tagId);
return null;
}
tags.add(poiTags[tagId]);
}
// get the tags from IDs (VBE-U)
List<Tag> tags = decodeTags(poiTags, numberOfTags, readBuffer);
// get the feature bitmask (1 byte)
byte featureByte = readBuffer.readByte();
@@ -769,16 +761,7 @@ private MapReadResult processBlocks(QueryParameters queryParameters, SubFilePara
// bit 5-8 represent the number of tag IDs
byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK);
List<Tag> tags = new ArrayList<>();
for (byte tagIndex = numberOfTags; tagIndex != 0; --tagIndex) {
int tagId = readBuffer.readUnsignedInt();
if (tagId < 0 || tagId >= wayTags.length) {
LOGGER.warning("invalid way tag ID: " + tagId);
return null;
}
tags.add(wayTags[tagId]);
}
List<Tag> tags = decodeTags(wayTags, numberOfTags, readBuffer);
// get the feature bitmask (1 byte)
byte featureByte = readBuffer.readByte();
@@ -830,6 +813,47 @@ private MapReadResult processBlocks(QueryParameters queryParameters, SubFilePara
return ways;
}
private List<Tag> decodeTags(Tag[] tagArray, byte numberOfTags, ReadBuffer readBuffer) {
List<Integer> ids = new ArrayList<>();
List<Tag> tags = new ArrayList<>();
for (byte tagIndex = numberOfTags; tagIndex != 0; --tagIndex) {
int id = readBuffer.readUnsignedInt();
if (id < 0 || id >= tagArray.length) {
LOGGER.warning("invalid tag ID: " + id);
return null;
}
ids.add(id);
}
for (Integer id : ids) {
Tag tag = tagArray[id];
// Decode variable values of tags
if (tag.value.charAt(0) == '%' && tag.value.length() == 2) {
String value = tag.value;
if (value.charAt(1) == 'b') {
value = String.valueOf(readBuffer.readByte());
} else if (value.charAt(1) == 'i') {
if (tag.key.contains(":colour")) {
value = "#" + Integer.toHexString(readBuffer.readInt());
} else {
value = String.valueOf(readBuffer.readInt());
}
} else if (value.charAt(1) == 'f') {
value = String.valueOf(readBuffer.readFloat());
} else if (value.charAt(1) == 'h') {
value = String.valueOf(readBuffer.readShort());
} else if (value.charAt(1) == 's') {
value = readBuffer.readUTF8EncodedString();
}
tag = new Tag(tag.key, value);
}
tags.add(tag);
}
return tags;
}
/**
* Reads only labels for tile.
*
@@ -3,6 +3,7 @@
* Copyright 2015-2017 devemux86
* Copyright 2016 bvgastel
* Copyright 2017 linuskr
* Copyright 2017 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -52,6 +53,18 @@ public byte readByte() {
return this.bufferData[this.bufferPosition++];
}
/**
* Converts four bytes from the read buffer to a float.
*
* @return the float value.
*/
public float readFloat() {
byte[] bytes = new byte[4];
System.arraycopy(bufferData, bufferPosition, bytes, 0, 4);
this.bufferPosition += 4;
return ByteBuffer.wrap(bytes).getFloat();
}
/**
* Reads the given amount of bytes from the file into the read buffer and resets the internal buffer position. If
* the capacity of the read buffer is too small, a larger one is created automatically.
@@ -51,7 +51,7 @@
/**
* Highest version of the map file format supported by this implementation.
*/
private static final int SUPPORTED_FILE_VERSION_MAX = 4;
private static final int SUPPORTED_FILE_VERSION_MAX = 5;
static void readBoundingBox(ReadBuffer readBuffer, MapFileInfoBuilder mapFileInfoBuilder) {
double minLatitude = LatLongUtils.microdegreesToDegrees(readBuffer.readInt());
@@ -1,3 +1,3 @@
mapfile.specification.version.min=3
mapfile.specification.version.max=4
mapfile.specification.version.max=5
mapfile.writer.version=${mapfile.writer.version}
@@ -368,6 +368,105 @@
<osm-tag key="building" value="yes" zoom-appear="15" />
</ways>
<!-- Building extrusions -->
<ways>
<osm-tag key="building:part" value="arch" zoom-appear="17" />
<osm-tag key="building:part" value="balcony" zoom-appear="17" />
<osm-tag key="building:part" value="base" zoom-appear="17" />
<osm-tag key="building:part" value="column" zoom-appear="17" />
<osm-tag key="building:part" value="elevator" zoom-appear="17" />
<osm-tag key="building:part" value="entrance" zoom-appear="17" />
<osm-tag key="building:part" value="floor" zoom-appear="17" />
<osm-tag key="building:part" value="hall" zoom-appear="17" />
<osm-tag key="building:part" value="main" zoom-appear="17" />
<osm-tag key="building:part" value="passageway" zoom-appear="17" />
<osm-tag key="building:part" value="pillar" zoom-appear="17" />
<osm-tag key="building:part" value="porch" zoom-appear="17" />
<osm-tag key="building:part" value="ramp" zoom-appear="17" />
<osm-tag key="building:part" value="roof" zoom-appear="17" />
<osm-tag key="building:part" value="room" zoom-appear="17" />
<osm-tag key="building:part" value="steps" zoom-appear="17" />
<osm-tag key="building:part" value="stilobate" zoom-appear="17" />
<osm-tag key="building:part" value="tier" zoom-appear="17" />
<osm-tag key="building:part" value="tower" zoom-appear="17" />
<osm-tag key="building:part" value="verticalpassage" zoom-appear="17" />
<osm-tag key="building:part" value="wall" zoom-appear="17" />
<osm-tag key="building:part" value="window" zoom-appear="17" />
<osm-tag key="building:part" value="yes" zoom-appear="17" />
<osm-tag key="height" renderable="false" value="%f" />
<osm-tag key="min-height" renderable="false" value="%f" />
<osm-tag key="building:levels" renderable="false" value="%f" />
<osm-tag key="building:min-levels" renderable="false" value="%f" />
</ways>
<!-- S3DB tags -->
<ways>
<osm-tag key="roof:shape" renderable="false" value="flat" />
<osm-tag key="roof:shape" renderable="false" value="skillion" />
<osm-tag key="roof:shape" renderable="false" value="gabled" />
<osm-tag key="roof:shape" renderable="false" value="half-hipped" />
<osm-tag key="roof:shape" renderable="false" value="hipped" />
<osm-tag key="roof:shape" renderable="false" value="pyramidal" />
<osm-tag key="roof:shape" renderable="false" value="gambrel" />
<osm-tag key="roof:shape" renderable="false" value="mansard" />
<osm-tag key="roof:shape" renderable="false" value="dome" />
<osm-tag key="roof:shape" renderable="false" value="onion" />
<osm-tag key="roof:shape" renderable="false" value="round" />
<osm-tag key="roof:shape" renderable="false" value="saltbox" />
<osm-tag key="roof:orientation" renderable="false" value="along" />
<osm-tag key="roof:orientation" renderable="false" value="across" />
<osm-tag key="roof:height" renderable="false" value="%f" />
<osm-tag key="roof:angle" renderable="false" value="%f" />
<osm-tag key="roof:levels" renderable="false" value="%f" />
<osm-tag key="roof:direction" renderable="false" value="%f" />
<osm-tag key="building:colour" renderable="false" value="%f" />
<!-- Detect unmatched tags -->
<!--<osm-tag key="building:colour" renderable="false" value="%s" />-->
<osm-tag key="roof:colour" renderable="false" value="%f" />
<!-- Detect unmatched tags -->
<!--<osm-tag key="roof:colour" renderable="false" value="%s" />-->
<osm-tag key="building:material" renderable="false" value="plaster" />
<osm-tag key="building:material" renderable="false" value="brick" />
<osm-tag key="building:material" renderable="false" value="wood" />
<osm-tag key="building:material" renderable="false" value="concrete" />
<osm-tag key="building:material" renderable="false" value="glass" />
<osm-tag key="building:material" renderable="false" value="mirror" />
<osm-tag key="building:material" renderable="false" value="stone" />
<osm-tag key="building:material" renderable="false" value="sandstone" />
<osm-tag key="building:material" renderable="false" value="steel" />
<osm-tag key="building:material" renderable="false" value="metal" />
<!--<osm-tag key="building:material" renderable="false" value="limestone" />-->
<!--<osm-tag key="building:material" renderable="false" value="sand_cement_blocks" />-->
<!--<osm-tag key="building:material" renderable="false" value="metal_plates" />-->
<!--<osm-tag key="building:material" renderable="false" value="mdf" />-->
<!--<osm-tag key="building:material" renderable="false" value="timber_framing" />-->
<!--<osm-tag key="building:material" renderable="false" value="plastic" />-->
<!--<osm-tag key="building:material" renderable="false" value="vinyl" />-->
<!--<osm-tag key="building:material" renderable="false" value="tiles" />-->
<!-- Detect unmatched tags -->
<!--<osm-tag key="building:material" renderable="false" value="%s" />-->
<osm-tag key="roof:material" renderable="false" value="acrylic_glass" />
<osm-tag key="roof:material" renderable="false" value="concrete" />
<osm-tag key="roof:material" renderable="false" value="copper" />
<osm-tag key="roof:material" renderable="false" value="eternit" />
<osm-tag key="roof:material" renderable="false" value="plastic" />
<osm-tag key="roof:material" renderable="false" value="asphalt " />
<osm-tag key="roof:material" renderable="false" value="glass" />
<osm-tag key="roof:material" renderable="false" value="grass" />
<osm-tag key="roof:material" renderable="false" value="gravel" />
<osm-tag key="roof:material" renderable="false" value="metal" />
<osm-tag key="roof:material" renderable="false" value="plants" />
<osm-tag key="roof:material" renderable="false" value="roof_tiles" />
<osm-tag key="roof:material" renderable="false" value="slate" />
<osm-tag key="roof:material" renderable="false" value="stone" />
<osm-tag key="roof:material" renderable="false" value="tar_paper" />
<osm-tag key="roof:material" renderable="false" value="thatch" />
<osm-tag key="roof:material" renderable="false" value="wood" />
</ways>
<!-- ADMINISTRATIVE BOUNDARIES -->
<ways>
@@ -1,6 +1,7 @@
/*
* Copyright 2010, 2011, 2012, 2013 mapsforge.org
* Copyright 2015 lincomatic
* Copyright 2017 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -142,7 +143,7 @@ public boolean execute(TDRelation relation) {
addWayToTiles(outerWay, BaseTileBasedDataProcessor.this.bboxEnlargement);
handleVirtualOuterWay(outerWay);
// adjust tag statistics, cannot be omitted!!!
countWayTags(relation.getTags());
countWayTags(relation.getTags().keySet());
}
// the outer way consists of only one segment
@@ -167,7 +168,7 @@ public boolean execute(TDRelation relation) {
// handle relation tags
handleAdditionalRelationTags(outerWay, relation);
addWayToTiles(outerWay, BaseTileBasedDataProcessor.this.bboxEnlargement);
countWayTags(outerWay.getTags());
countWayTags(outerWay.getTags().keySet());
}
}
@@ -192,17 +193,29 @@ private void addInnerWays(TDWay outer) {
if (innerSegments.size() == 1) {
innerWay = innerSegments.getFirst();
if (innerWay.hasTags() && outer.hasTags()) {
short[] iTags = innerWay.getTags();
short[] oTags = outer.getTags();
int contained = 0;
for (short iTagID : iTags) {
for (short oTagID : oTags) {
if (iTagID == oTagID) {
contained++;
for (Entry<Short, Object> innerTag : innerWay.getTags().entrySet()) {
for (Entry<Short, Object> outerTag : outer.getTags().entrySet()) {
if (innerTag.getKey().equals(outerTag.getKey())) {
Object innerValue = innerTag.getValue();
Object outerValue = outerTag.getValue();
if (innerValue != null) {
if (outerValue != null) {
if ((innerValue instanceof Byte && outerValue instanceof Byte && innerValue.equals(outerValue))
|| (innerValue instanceof Integer && outerValue instanceof Integer && innerValue.equals(outerValue))
|| (innerValue instanceof Float && outerValue instanceof Float && innerValue.equals(outerValue))
|| (innerValue instanceof Short && outerValue instanceof Short && innerValue.equals(outerValue))
|| (innerValue instanceof String && outerValue instanceof String && innerValue.equals(outerValue))) {
contained++;
}
}
} else if (outerValue == null) {
contained++;
}
}
}
}
if (contained == iTags.length) {
if (contained == innerWay.getTags().size()) {
BaseTileBasedDataProcessor.this.innerWaysWithoutAdditionalTags.add(innerWay.getId());
}
}
@@ -384,12 +397,12 @@ protected void countPoiTags(TDNode poi) {
if (poi == null || poi.getTags() == null) {
return;
}
for (short tag : poi.getTags()) {
for (short tag : poi.getTags().keySet()) {
this.histogramPoiTags.adjustOrPutValue(tag, 1, 1);
}
}
protected void countWayTags(short[] tags) {
protected void countWayTags(Set<Short> tags) {
if (tags != null) {
for (short tag : tags) {
this.histogramWayTags.adjustOrPutValue(tag, 1, 1);
@@ -399,7 +412,7 @@ protected void countWayTags(short[] tags) {
protected void countWayTags(TDWay way) {
if (way != null) {
countWayTags(way.getTags());
countWayTags(way.getTags().keySet());
}
}
Oops, something went wrong.

0 comments on commit 7a9b1ca

Please sign in to comment.