source: josm/trunk/test/unit/org/openstreetmap/josm/data/protobuf/ProtobufTest.java@ 17862

Last change on this file since 17862 was 17862, checked in by simon04, 3 years ago

fix #17177 - Add support for Mapbox Vector Tile (patch by taylor.smock)

Signed-off-by: Taylor Smock <tsmock@…>

File size: 9.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.protobuf;
3
4import static org.junit.jupiter.api.Assertions.assertEquals;
5import static org.junit.jupiter.api.Assertions.assertNotNull;
6import static org.junit.jupiter.api.Assertions.fail;
7
8import java.awt.geom.Ellipse2D;
9import java.io.ByteArrayInputStream;
10import java.io.File;
11import java.io.IOException;
12import java.io.InputStream;
13import java.nio.file.Paths;
14import java.text.MessageFormat;
15import java.util.ArrayList;
16import java.util.Collection;
17import java.util.List;
18import java.util.stream.Collectors;
19
20import org.openstreetmap.josm.TestUtils;
21import org.openstreetmap.josm.data.coor.LatLon;
22import org.openstreetmap.josm.data.imagery.ImageryInfo;
23import org.openstreetmap.josm.data.imagery.vectortile.mapbox.Feature;
24import org.openstreetmap.josm.data.imagery.vectortile.mapbox.Layer;
25import org.openstreetmap.josm.data.imagery.vectortile.mapbox.MVTTile;
26import org.openstreetmap.josm.data.imagery.vectortile.mapbox.MapboxVectorTileSource;
27import org.openstreetmap.josm.data.osm.BBox;
28import org.openstreetmap.josm.data.osm.Node;
29import org.openstreetmap.josm.data.osm.Way;
30import org.openstreetmap.josm.data.vector.VectorDataSet;
31import org.openstreetmap.josm.data.vector.VectorNode;
32import org.openstreetmap.josm.data.vector.VectorWay;
33import org.openstreetmap.josm.io.Compression;
34import org.openstreetmap.josm.testutils.JOSMTestRules;
35
36import org.junit.jupiter.api.Test;
37import org.junit.jupiter.api.extension.RegisterExtension;
38
39/**
40 * Test class for {@link ProtobufParser} and {@link ProtobufRecord}
41 *
42 * @author Taylor Smock
43 * @since xxx
44 */
45class ProtobufTest {
46 /**
47 * Convert an int array into a byte array
48 * @param intArray The int array to convert (NOTE: numbers must be below 255)
49 * @return A byte array that can be used
50 */
51 static byte[] toByteArray(int[] intArray) {
52 byte[] byteArray = new byte[intArray.length];
53 for (int i = 0; i < intArray.length; i++) {
54 if (intArray[i] > Byte.MAX_VALUE - Byte.MIN_VALUE) {
55 throw new IllegalArgumentException();
56 }
57 byteArray[i] = Integer.valueOf(intArray[i]).byteValue();
58 }
59 return byteArray;
60 }
61
62 @RegisterExtension
63 JOSMTestRules josmTestRules = new JOSMTestRules().preferences();
64
65 private Number bytesToVarInt(int... bytes) {
66 byte[] byteArray = new byte[bytes.length];
67 for (int i = 0; i < bytes.length; i++) {
68 byteArray[i] = (byte) bytes[i];
69 }
70 return ProtobufParser.convertByteArray(byteArray, ProtobufParser.VAR_INT_BYTE_SIZE);
71 }
72
73 /**
74 * Test reading tile from Mapillary ( 14/3248/6258 )
75 *
76 * @throws IOException if there is a problem reading the file
77 */
78 @Test
79 void testRead_14_3248_6258() throws IOException {
80 File vectorTile = Paths.get(TestUtils.getTestDataRoot(), "pbf", "mapillary", "14", "3248", "6258.mvt").toFile();
81 InputStream inputStream = Compression.getUncompressedFileInputStream(vectorTile);
82 Collection<ProtobufRecord> records = new ProtobufParser(inputStream).allRecords();
83 assertEquals(2, records.size());
84 List<Layer> layers = new ArrayList<>();
85 for (ProtobufRecord record : records) {
86 if (record.getField() == Layer.LAYER_FIELD) {
87 layers.add(new Layer(record.getBytes()));
88 } else {
89 fail(MessageFormat.format("Invalid field {0}", record.getField()));
90 }
91 }
92 Layer mapillarySequences = layers.get(0);
93 Layer mapillaryPictures = layers.get(1);
94 assertEquals("mapillary-sequences", mapillarySequences.getName());
95 assertEquals("mapillary-images", mapillaryPictures.getName());
96 assertEquals(4096, mapillarySequences.getExtent());
97 assertEquals(4096, mapillaryPictures.getExtent());
98
99 assertEquals(1,
100 mapillarySequences.getFeatures().stream().filter(feature -> feature.getId() == 233760500).count());
101 Feature testSequence = mapillarySequences.getFeatures().stream().filter(feature -> feature.getId() == 233760500)
102 .findAny().orElse(null);
103 assertEquals("dpudn262yz6aitu33zh7bl", testSequence.getTags().get("key"));
104 assertEquals("clnaw3kpokIAe_CsN5Qmiw", testSequence.getTags().get("ikey"));
105 assertEquals("B1iNjH4Ohn25cRAGPhetfw", testSequence.getTags().get("userkey"));
106 assertEquals(Long.valueOf(1557535457401L), Long.valueOf(testSequence.getTags().get("captured_at")));
107 assertEquals(0, Integer.parseInt(testSequence.getTags().get("pano")));
108 }
109
110 @Test
111 void testRead_17_26028_50060() throws IOException {
112 File vectorTile = Paths.get(TestUtils.getTestDataRoot(), "pbf", "openinframap", "17", "26028", "50060.pbf")
113 .toFile();
114 InputStream inputStream = Compression.getUncompressedFileInputStream(vectorTile);
115 Collection<ProtobufRecord> records = new ProtobufParser(inputStream).allRecords();
116 List<Layer> layers = new ArrayList<>();
117 for (ProtobufRecord record : records) {
118 if (record.getField() == Layer.LAYER_FIELD) {
119 layers.add(new Layer(record.getBytes()));
120 } else {
121 fail(MessageFormat.format("Invalid field {0}", record.getField()));
122 }
123 }
124 assertEquals(19, layers.size());
125 List<Layer> dataLayers = layers.stream().filter(layer -> !layer.getFeatures().isEmpty())
126 .collect(Collectors.toList());
127 // power_plant, power_plant_point, power_generator, power_heatmap_solar, and power_generator_area
128 assertEquals(5, dataLayers.size());
129
130 // power_generator_area was rendered incorrectly
131 final Layer powerGeneratorArea = dataLayers.stream()
132 .filter(layer -> "power_generator_area".equals(layer.getName())).findAny().orElse(null);
133 assertNotNull(powerGeneratorArea);
134 final int extent = powerGeneratorArea.getExtent();
135 // 17/26028/50060 bounds
136 VectorDataSet vectorDataSet = new VectorDataSet();
137 MVTTile vectorTile1 = new MVTTile(new MapboxVectorTileSource(new ImageryInfo("Test info", "example.org")),
138 26028, 50060, 17);
139 vectorTile1.loadImage(Compression.getUncompressedFileInputStream(vectorTile));
140 vectorDataSet.addTileData(vectorTile1);
141 vectorDataSet.setZoom(17);
142 final Way one = new Way();
143 one.addNode(new Node(new LatLon(39.0687509, -108.5100816)));
144 one.addNode(new Node(new LatLon(39.0687509, -108.5095751)));
145 one.addNode(new Node(new LatLon(39.0687169, -108.5095751)));
146 one.addNode(new Node(new LatLon(39.0687169, -108.5100816)));
147 one.addNode(one.getNode(0));
148 one.setOsmId(666293899, 2);
149 final BBox searchBBox = one.getBBox();
150 searchBBox.addPrimitive(one, 0.00001);
151 final Collection<VectorNode> searchedNodes = vectorDataSet.searchNodes(searchBBox);
152 final Collection<VectorWay> searchedWays = vectorDataSet.searchWays(searchBBox);
153 assertEquals(4, searchedNodes.size());
154 }
155
156 @Test
157 void testReadVarInt() {
158 assertEquals(ProtobufParser.convertLong(0), bytesToVarInt(0x0));
159 assertEquals(ProtobufParser.convertLong(1), bytesToVarInt(0x1));
160 assertEquals(ProtobufParser.convertLong(127), bytesToVarInt(0x7f));
161 // This should b 0xff 0xff 0xff 0xff 0x07, but we drop the leading bit when reading to a byte array
162 Number actual = bytesToVarInt(0x7f, 0x7f, 0x7f, 0x7f, 0x07);
163 assertEquals(ProtobufParser.convertLong(Integer.MAX_VALUE), actual,
164 MessageFormat.format("Expected {0} but got {1}", Integer.toBinaryString(Integer.MAX_VALUE),
165 Long.toBinaryString(actual.longValue())));
166 }
167
168 /**
169 * Test simple message.
170 * Check that a simple message is readable
171 *
172 * @throws IOException - if an IO error occurs
173 */
174 @Test
175 void testSimpleMessage() throws IOException {
176 ProtobufParser parser = new ProtobufParser(new byte[] {(byte) 0x08, (byte) 0x96, (byte) 0x01});
177 ProtobufRecord record = new ProtobufRecord(parser);
178 assertEquals(WireType.VARINT, record.getType());
179 assertEquals(150, record.asUnsignedVarInt().intValue());
180 }
181
182 @Test
183 void testSingletonMultiPoint() throws IOException {
184 Collection<ProtobufRecord> records = new ProtobufParser(new ByteArrayInputStream(toByteArray(
185 new int[] {0x1a, 0x2c, 0x78, 0x02, 0x0a, 0x03, 0x74, 0x6d, 0x70, 0x28, 0x80, 0x20, 0x1a, 0x04, 0x6e,
186 0x61, 0x6d, 0x65, 0x22, 0x0b, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65,
187 0x12, 0x0d, 0x18, 0x01, 0x12, 0x02, 0x00, 0x00, 0x22, 0x05, 0x09, 0xe0, 0x3e, 0x84, 0x27})))
188 .allRecords();
189 List<Layer> layers = new ArrayList<>();
190 for (ProtobufRecord record : records) {
191 if (record.getField() == Layer.LAYER_FIELD) {
192 layers.add(new Layer(record.getBytes()));
193 } else {
194 fail(MessageFormat.format("Invalid field {0}", record.getField()));
195 }
196 }
197 assertEquals(1, layers.size());
198 assertEquals(1, layers.get(0).getGeometry().size());
199 Ellipse2D shape = (Ellipse2D) layers.get(0).getGeometry().iterator().next().getShapes().iterator().next();
200 assertEquals(4016, shape.getCenterX());
201 assertEquals(2498, shape.getCenterY());
202 }
203
204 @Test
205 void testZigZag() {
206 assertEquals(0, ProtobufParser.decodeZigZag(0).intValue());
207 assertEquals(-1, ProtobufParser.decodeZigZag(1).intValue());
208 assertEquals(1, ProtobufParser.decodeZigZag(2).intValue());
209 assertEquals(-2, ProtobufParser.decodeZigZag(3).intValue());
210 }
211}
Note: See TracBrowser for help on using the repository browser.