Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2023 James Westman <james@jwestman.net>
3 : : *
4 : : * This library is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * This library is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with this library; if not, see <https://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include "shumate-vector-reader-private.h"
19 : : #include "shumate-vector-reader-iter-private.h"
20 : :
21 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
22 : : #include "vector/shumate-vector-utils-private.h"
23 : : #endif
24 : :
25 : : /**
26 : : * ShumateVectorReaderIter:
27 : : *
28 : : * Reads the layers and features of a vector tile.
29 : : *
30 : : * To create a new [class@VectorReaderIter], use [method@VectorReader.iterate].
31 : : *
32 : : * A vector tile consists of named layers, which contain features. Each feature
33 : : * has an ID, a geometry, and a set of key/value tags. The meanings of
34 : : * the IDs and tags depends on the data source that the tile came from. The
35 : : * [OpenMapTiles schema](https://openmaptiles.org/schema/) is a common schema
36 : : * for vector tiles.
37 : : *
38 : : * To read all layers in a tile, use [method@VectorReaderIter.get_layer_count] and
39 : : * [method@VectorReaderIter.read_layer]. If you know the name of the layer you
40 : : * want, you can also use [method@VectorReaderIter.read_layer_by_name].
41 : : * Once the iterator is reading a layer, you can call
42 : : * [method@VectorReaderIter.next_feature] in a loop to read all the features in
43 : : * the layer.
44 : : *
45 : : * A [class@VectorReaderIter] is not thread-safe, but iterators created
46 : : * from the same [class@VectorReader] can be used in different threads.
47 : : *
48 : : * See [the Mapbox Vector Tile specification](https://github.com/mapbox/vector-tile-spec/tree/master/2.1)
49 : : * for more information about the vector tile format.
50 : : *
51 : : * Since: 1.2
52 : : */
53 : :
54 : : struct _ShumateVectorReaderIter
55 : : {
56 : : GObject parent_instance;
57 : :
58 : : ShumateVectorReader *reader;
59 : :
60 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
61 : : VectorTile__Tile__Layer *layer;
62 : : VectorTile__Tile__Feature *feature;
63 : : int feature_index;
64 : : #endif
65 : : };
66 : :
67 : : enum {
68 : : PROP_0,
69 : : PROP_READER,
70 : : N_PROPERTIES
71 : : };
72 : :
73 : : static GParamSpec *properties[N_PROPERTIES];
74 : :
75 [ + + + - ]: 723 : G_DEFINE_TYPE (ShumateVectorReaderIter, shumate_vector_reader_iter, G_TYPE_OBJECT)
76 : :
77 : : static void
78 : 0 : shumate_vector_reader_iter_get_property (GObject *object,
79 : : guint prop_id,
80 : : GValue *value,
81 : : GParamSpec *pspec)
82 : : {
83 : 0 : ShumateVectorReaderIter *self = SHUMATE_VECTOR_READER_ITER (object);
84 : :
85 [ # # ]: 0 : switch (prop_id)
86 : : {
87 : 0 : case PROP_READER:
88 : 0 : g_value_set_object (value, self->reader);
89 : 0 : break;
90 : 0 : default:
91 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 : : }
93 : 0 : }
94 : :
95 : : static void
96 : 39 : shumate_vector_reader_iter_set_property (GObject *object,
97 : : guint prop_id,
98 : : const GValue *value,
99 : : GParamSpec *pspec)
100 : : {
101 : 39 : ShumateVectorReaderIter *self = SHUMATE_VECTOR_READER_ITER (object);
102 : :
103 [ + - ]: 39 : switch (prop_id)
104 : : {
105 : 39 : case PROP_READER:
106 : 39 : self->reader = g_value_dup_object (value);
107 : 39 : break;
108 : 0 : default:
109 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
110 : : }
111 : 39 : }
112 : :
113 : : static void
114 : 39 : shumate_vector_reader_iter_finalize (GObject *object)
115 : : {
116 : 39 : ShumateVectorReaderIter *self = SHUMATE_VECTOR_READER_ITER (object);
117 : :
118 [ + - ]: 39 : g_clear_object (&self->reader);
119 : :
120 : 39 : G_OBJECT_CLASS (shumate_vector_reader_iter_parent_class)->finalize (object);
121 : 39 : }
122 : :
123 : : static void
124 : 13 : shumate_vector_reader_iter_class_init (ShumateVectorReaderIterClass *klass)
125 : : {
126 : 13 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
127 : :
128 : 13 : object_class->finalize = shumate_vector_reader_iter_finalize;
129 : 13 : object_class->get_property = shumate_vector_reader_iter_get_property;
130 : 13 : object_class->set_property = shumate_vector_reader_iter_set_property;
131 : :
132 : : /**
133 : : * VectorReaderIter:reader:
134 : : *
135 : : * The [class@VectorReader] that the iterator is iterating over.
136 : : *
137 : : * Since: 1.2
138 : : */
139 : 26 : properties[PROP_READER] =
140 : 13 : g_param_spec_object ("reader",
141 : : "reader",
142 : : "reader",
143 : : SHUMATE_TYPE_VECTOR_READER,
144 : : G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
145 : :
146 : 13 : g_object_class_install_properties (object_class, N_PROPERTIES, properties);
147 : 13 : }
148 : :
149 : : static void
150 : 39 : shumate_vector_reader_iter_init (ShumateVectorReaderIter *self)
151 : : {
152 : 39 : }
153 : :
154 : : /**
155 : : * shumate_vector_reader_iter_get_reader:
156 : : * @self: A [class@VectorReaderIter]
157 : : *
158 : : * Gets the reader that the iterator is iterating over.
159 : : *
160 : : * Returns: (transfer none): The reader that the iterator is iterating over.
161 : : *
162 : : * Since: 1.2
163 : : */
164 : : ShumateVectorReader *
165 : 0 : shumate_vector_reader_iter_get_reader (ShumateVectorReaderIter *self)
166 : : {
167 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), NULL);
168 : 0 : return self->reader;
169 : : }
170 : :
171 : : /**
172 : : * shumate_vector_reader_iter_get_layer_count:
173 : : * @self: A #ShumateVectorReader.
174 : : *
175 : : * Gets the number of layers in the vector tile.
176 : : *
177 : : * Returns: The number of layers.
178 : : *
179 : : * Since: 1.2
180 : : */
181 : : guint
182 : 3 : shumate_vector_reader_iter_get_layer_count (ShumateVectorReaderIter *self)
183 : : {
184 [ + - ]: 3 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), 0);
185 : :
186 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
187 : 3 : return self->reader->tile->n_layers;
188 : : #else
189 : : return 0;
190 : : #endif
191 : : }
192 : :
193 : : /**
194 : : * shumate_vector_reader_iter_read_layer:
195 : : * @self: A #ShumateVectorReader.
196 : : * @index: The index of the layer to read.
197 : : *
198 : : * Sets the current layer of the reader to the layer at the given index.
199 : : *
200 : : * Since: 1.2
201 : : */
202 : : void
203 : 6 : shumate_vector_reader_iter_read_layer (ShumateVectorReaderIter *self, int index)
204 : : {
205 [ + - ]: 6 : g_return_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self));
206 : :
207 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
208 [ - + ]: 6 : g_return_if_fail (index >= 0);
209 [ - + ]: 6 : g_return_if_fail (index < self->reader->tile->n_layers);
210 : :
211 : 6 : self->layer = self->reader->tile->layers[index];
212 : 6 : self->feature = NULL;
213 : : #endif
214 : : }
215 : :
216 : : /**
217 : : * shumate_vector_reader_iter_read_layer_by_name:
218 : : * @self: A #ShumateVectorReader.
219 : : *
220 : : * Moves the iterator to the layer with the given name, if present.
221 : : *
222 : : * If the layer is not found, the current layer will be set to %NULL and the
223 : : * function will return %FALSE. Layers are typically omitted if they are empty,
224 : : * so don't assume that a layer in the schema will always be present.
225 : : *
226 : : * The iterator's current feature will be %NULL after calling this function;
227 : : * use [method@VectorReaderIter.next_feature] to advance to the first feature
228 : : * in the layer.
229 : : *
230 : : * Returns: %TRUE if the layer was found, %FALSE otherwise.
231 : : *
232 : : * Since: 1.2
233 : : */
234 : : gboolean
235 : 42 : shumate_vector_reader_iter_read_layer_by_name (ShumateVectorReaderIter *self,
236 : : const char *name)
237 : : {
238 [ + - ]: 42 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), FALSE);
239 : :
240 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
241 : 42 : self->layer = NULL;
242 : 42 : self->feature = NULL;
243 : :
244 [ - + ]: 87 : for (int i = 0; i < self->reader->tile->n_layers; i++)
245 : : {
246 [ + + ]: 87 : if (strcmp (self->reader->tile->layers[i]->name, name) == 0)
247 : : {
248 : 42 : self->layer = self->reader->tile->layers[i];
249 : 42 : self->feature = NULL;
250 : 42 : return TRUE;
251 : : }
252 : : }
253 : : #endif
254 : :
255 : : return FALSE;
256 : : }
257 : :
258 : : /*< private >
259 : : * shumate_vector_reader_iter_get_layer_index:
260 : : * @self: A #ShumateVectorReaderIter.
261 : : *
262 : : * Gets the index of the current layer.
263 : : *
264 : : * Returns: The index of the current layer.
265 : : *
266 : : * Since: 1.3
267 : : */
268 : : int
269 : 30 : shumate_vector_reader_iter_get_layer_index (ShumateVectorReaderIter *self)
270 : : {
271 [ - + ]: 30 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), -1);
272 : :
273 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
274 [ - + ]: 75 : for (int i = 0; i < self->reader->tile->n_layers; i++)
275 : : {
276 [ + + ]: 75 : if (self->layer == self->reader->tile->layers[i])
277 : : {
278 : 30 : return i;
279 : : }
280 : : }
281 : : #endif
282 : :
283 : : return -1;
284 : : }
285 : :
286 : : /**
287 : : * shumate_vector_reader_iter_get_layer_name:
288 : : * @self: A #ShumateVectorReader.
289 : : *
290 : : * Gets the name of the current layer.
291 : : *
292 : : * Returns: (transfer none): The name of the current layer.
293 : : *
294 : : * Since: 1.2
295 : : */
296 : : const char *
297 : 27 : shumate_vector_reader_iter_get_layer_name (ShumateVectorReaderIter *self)
298 : : {
299 [ + - ]: 27 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), NULL);
300 : :
301 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
302 [ - + ]: 27 : g_return_val_if_fail (self->layer != NULL, NULL);
303 : 27 : return self->layer->name;
304 : : #else
305 : : return NULL;
306 : : #endif
307 : : }
308 : :
309 : : /**
310 : : * shumate_vector_reader_iter_get_layer_feature_count:
311 : : * @self: A #ShumateVectorReader.
312 : : *
313 : : * Gets the number of features in the current layer.
314 : : *
315 : : * You can loop over all features in the current layer by calling
316 : : * [method@VectorReaderIter.read_feature] with each index from 0 to
317 : : * the feature count, but it might be easier to use
318 : : * [method@VectorReaderIter.next_feature] instead.
319 : : *
320 : : * Returns: The number of features in the current layer.
321 : : *
322 : : * Since: 1.2
323 : : */
324 : : guint
325 : 6 : shumate_vector_reader_iter_get_layer_feature_count (ShumateVectorReaderIter *self)
326 : : {
327 [ + - ]: 6 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), 0);
328 : :
329 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
330 [ - + ]: 6 : g_return_val_if_fail (self->layer != NULL, 0);
331 : 6 : return self->layer->n_features;
332 : : #else
333 : : return 0;
334 : : #endif
335 : : }
336 : :
337 : : /**
338 : : * shumate_vector_reader_iter_get_layer_extent:
339 : : * @self: A [class@VectorReaderIter].
340 : : *
341 : : * Gets the extent for coordinates in the current layer.
342 : : *
343 : : * 0 represents the top and left edges of the tile, and this value
344 : : * represents the bottom and right edges. Feature geometries may extend
345 : : * outside of this range, since tiles often include some margin.
346 : : *
347 : : * Tiles do not contain metadata about the location of the tile within
348 : : * the world, so it is up to the caller to know the tile's coordinates
349 : : * and convert latitude/longitude to tile-space coordinates.
350 : : *
351 : : * Returns: The layer's extent
352 : : *
353 : : * Since: 1.2
354 : : */
355 : : guint
356 : 6 : shumate_vector_reader_iter_get_layer_extent (ShumateVectorReaderIter *self)
357 : : {
358 [ + - ]: 6 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), 0);
359 : :
360 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
361 [ - + ]: 6 : g_return_val_if_fail (self->layer != NULL, 0);
362 : 6 : return self->layer->extent;
363 : : #else
364 : : return 0;
365 : : #endif
366 : : }
367 : :
368 : : /**
369 : : * shumate_vector_reader_iter_read_feature:
370 : : * @self: A #ShumateVectorReader.
371 : : * @index: The index of the feature to read.
372 : : *
373 : : * Moves the iterator to the feature at the given index in the current layer.
374 : : *
375 : : * You can get the number of features in the current layer with
376 : : * [method@VectorReaderIter.get_layer_feature_count].
377 : : *
378 : : * Since: 1.2
379 : : */
380 : : void
381 : 15 : shumate_vector_reader_iter_read_feature (ShumateVectorReaderIter *self,
382 : : int index)
383 : : {
384 [ + - ]: 15 : g_return_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self));
385 : :
386 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
387 [ - + ]: 15 : g_return_if_fail (index >= 0);
388 [ - + ]: 15 : g_return_if_fail (self->layer != NULL);
389 [ - + ]: 15 : g_return_if_fail (index < self->layer->n_features);
390 : :
391 : 15 : self->feature = self->layer->features[index];
392 : 15 : self->feature_index = index;
393 : : #endif
394 : : }
395 : :
396 : : /**
397 : : * shumate_vector_reader_iter_next_feature:
398 : : * @self: A #ShumateVectorReader.
399 : : *
400 : : * Advances the iterator to the next feature in the current layer.
401 : : *
402 : : * Returns: %TRUE if there is a next feature, %FALSE otherwise.
403 : : *
404 : : * Since: 1.2
405 : : */
406 : : gboolean
407 : 93 : shumate_vector_reader_iter_next_feature (ShumateVectorReaderIter *self)
408 : : {
409 : 93 : int next_index = 0;
410 : :
411 [ + - ]: 93 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), FALSE);
412 : :
413 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
414 [ - + ]: 93 : g_return_val_if_fail (self->layer != NULL, FALSE);
415 : :
416 [ + + ]: 93 : if (self->feature == NULL)
417 : : next_index = 0;
418 : : else
419 : 72 : next_index = self->feature_index + 1;
420 : :
421 [ + + ]: 93 : if (next_index < self->layer->n_features)
422 : : {
423 : 69 : self->feature = self->layer->features[next_index];
424 : 69 : self->feature_index = next_index;
425 : 69 : return TRUE;
426 : : }
427 : : else
428 : : return FALSE;
429 : : #else
430 : : return FALSE;
431 : : #endif
432 : : }
433 : :
434 : : /*< private >
435 : : * shumate_vector_reader_iter_get_feature_index:
436 : : * @self: A [class@VectorReaderIter].
437 : : *
438 : : * Gets the index of the current feature.
439 : : *
440 : : * Returns: The index of the current feature.
441 : : *
442 : : * Since: 1.3
443 : : */
444 : : int
445 : 0 : shumate_vector_reader_iter_get_feature_index (ShumateVectorReaderIter *self)
446 : : {
447 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), 0);
448 : :
449 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
450 : 0 : return self->feature_index;
451 : : #else
452 : : return 0;
453 : : #endif
454 : : }
455 : :
456 : : /**
457 : : * shumate_vector_reader_iter_get_feature_id:
458 : : * @self: A [class@VectorReaderIter].
459 : : *
460 : : * Gets the ID of the current feature.
461 : : *
462 : : * Returns: The ID of the current feature.
463 : : *
464 : : * Since: 1.2
465 : : */
466 : : guint64
467 : 3 : shumate_vector_reader_iter_get_feature_id (ShumateVectorReaderIter *self)
468 : : {
469 [ + - ]: 3 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), 0);
470 : :
471 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
472 [ - + ]: 3 : g_return_val_if_fail (self->feature != NULL, 0);
473 : 3 : return self->feature->id;
474 : : #else
475 : : return 0;
476 : : #endif
477 : : }
478 : :
479 : : /**
480 : : * shumate_vector_reader_iter_get_feature_tag:
481 : : * @self: A [class@VectorReaderIter].
482 : : * @key: The key of the tag to get.
483 : : * @value: (out): The value of the tag.
484 : : *
485 : : * Gets the value of the tag with the given key.
486 : : *
487 : : * Returns: %TRUE if the tag was found, %FALSE otherwise.
488 : : *
489 : : * Since: 1.2
490 : : */
491 : : gboolean
492 : 3 : shumate_vector_reader_iter_get_feature_tag (ShumateVectorReaderIter *self,
493 : : const char *key,
494 : : GValue *value)
495 : : {
496 [ + - ]: 3 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), FALSE);
497 : :
498 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
499 [ - + ]: 3 : g_return_val_if_fail (self->feature != NULL, FALSE);
500 : :
501 [ - + ]: 3 : if (key == NULL)
502 : : return FALSE;
503 : :
504 [ - + ]: 3 : for (int i = 0; i + 1 < self->feature->n_tags; i += 2)
505 : : {
506 [ + - ]: 3 : if (strcmp (self->layer->keys[self->feature->tags[i]], key) == 0)
507 : : {
508 : 3 : VectorTile__Tile__Value *v = self->layer->values[self->feature->tags[i + 1]];
509 : :
510 [ - + ]: 3 : if (v->has_int_value)
511 : : {
512 : 0 : g_value_init (value, G_TYPE_INT64);
513 : 0 : g_value_set_int64 (value, v->int_value);
514 : : }
515 [ - + ]: 3 : else if (v->has_uint_value)
516 : : {
517 : 0 : g_value_init (value, G_TYPE_UINT64);
518 : 0 : g_value_set_uint64 (value, v->uint_value);
519 : : }
520 [ - + ]: 3 : else if (v->has_sint_value)
521 : : {
522 : 0 : g_value_init (value, G_TYPE_INT64);
523 : 0 : g_value_set_int64 (value, v->sint_value);
524 : : }
525 [ - + ]: 3 : else if (v->has_float_value)
526 : : {
527 : 0 : g_value_init (value, G_TYPE_FLOAT);
528 : 0 : g_value_set_float (value, v->float_value);
529 : : }
530 [ - + ]: 3 : else if (v->has_double_value)
531 : : {
532 : 0 : g_value_init (value, G_TYPE_DOUBLE);
533 : 0 : g_value_set_double (value, v->double_value);
534 : : }
535 [ - + ]: 3 : else if (v->has_bool_value)
536 : : {
537 : 0 : g_value_init (value, G_TYPE_BOOLEAN);
538 : 0 : g_value_set_boolean (value, v->bool_value);
539 : : }
540 [ + - ]: 3 : else if (v->string_value != NULL)
541 : : {
542 : 3 : g_value_init (value, G_TYPE_STRING);
543 : 3 : g_value_set_string (value, v->string_value);
544 : : }
545 : : else
546 : 0 : g_value_unset (value);
547 : :
548 : 3 : return TRUE;
549 : : }
550 : : }
551 : : #endif
552 : :
553 : : return FALSE;
554 : : }
555 : :
556 : : /**
557 : : * shumate_vector_reader_iter_get_feature_keys:
558 : : * @self: A [class@VectorReaderIter].
559 : : *
560 : : * Gets the keys of the tags of the current feature.
561 : : *
562 : : * Returns: (transfer container) (array zero-terminated=1): The keys of the tags of the current feature.
563 : : *
564 : : * Since: 1.2
565 : : */
566 : : const char **
567 : 3 : shumate_vector_reader_iter_get_feature_keys (ShumateVectorReaderIter *self)
568 : : {
569 [ + - ]: 3 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), NULL);
570 : :
571 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
572 : 3 : const char **keys;
573 : 3 : uint32_t n_keys;
574 : :
575 [ - + ]: 3 : g_return_val_if_fail (self->feature != NULL, NULL);
576 : :
577 : 3 : n_keys = self->feature->n_tags / 2;
578 [ - + ]: 3 : keys = g_new (const char *, n_keys + 1);
579 [ + + ]: 6 : for (int i = 0; i < n_keys; i ++)
580 : 3 : keys[i] = self->layer->keys[self->feature->tags[i * 2]];
581 : 3 : keys[n_keys] = NULL;
582 : :
583 : 3 : return keys;
584 : : #else
585 : : return NULL;
586 : : #endif
587 : : }
588 : :
589 : : /**
590 : : * shumate_vector_reader_iter_get_feature_geometry_type:
591 : : * @self: A [class@VectorReaderIter].
592 : : *
593 : : * Gets the geometry type of the current feature.
594 : : *
595 : : * Returns: The geometry type of the current feature.
596 : : *
597 : : * Since: 1.2
598 : : */
599 : : ShumateGeometryType
600 : 33 : shumate_vector_reader_iter_get_feature_geometry_type (ShumateVectorReaderIter *self)
601 : : {
602 : : /* MVT doesn't distinguish between multi geometries and single geometries, but
603 : : we do, so this function contains a bunch of extra logic to determine whether
604 : : the geometry data contains multiple geometries. */
605 : :
606 [ + - ]: 33 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), SHUMATE_GEOMETRY_TYPE_UNKNOWN);
607 : :
608 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
609 [ - + ]: 33 : g_return_val_if_fail (self->feature != NULL, SHUMATE_GEOMETRY_TYPE_UNKNOWN);
610 : :
611 [ - + + + ]: 33 : switch (self->feature->type)
612 : : {
613 : : case VECTOR_TILE__TILE__GEOM_TYPE__UNKNOWN:
614 : : return SHUMATE_GEOMETRY_TYPE_UNKNOWN;
615 : :
616 : 15 : case VECTOR_TILE__TILE__GEOM_TYPE__POINT:
617 [ + + ]: 15 : if (self->feature->n_geometry == 3)
618 : : return SHUMATE_GEOMETRY_TYPE_POINT;
619 : : else
620 : 3 : return SHUMATE_GEOMETRY_TYPE_MULTIPOINT;
621 : :
622 : 12 : case VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING:
623 : : {
624 : 12 : ShumateVectorGeometryIter iter = { .feature = self->feature };
625 : 12 : int move_tos = 0;
626 [ + + ]: 54 : while (shumate_vector_geometry_iter (&iter))
627 : : {
628 [ + + ]: 45 : if (iter.op == 1)
629 : : {
630 : 15 : move_tos ++;
631 [ + + ]: 15 : if (move_tos > 1)
632 : : return SHUMATE_GEOMETRY_TYPE_MULTILINESTRING;
633 : : }
634 : : }
635 : : return SHUMATE_GEOMETRY_TYPE_LINESTRING;
636 : : }
637 : :
638 : 6 : case VECTOR_TILE__TILE__GEOM_TYPE__POLYGON:
639 : : {
640 : : /* Use the shoelace formula to determine whether each ring is
641 : : exterior or interior. A single polygon can have interior rings
642 : : in addition to its exterior ring; a multipolygon has multiple
643 : : exterior rings. */
644 : :
645 : 6 : ShumateVectorGeometryIter iter = { .feature = self->feature };
646 : 6 : int prev_x = 0, prev_y = 0;
647 : 6 : double area = 0;
648 : 6 : int exterior_rings = 0;
649 : :
650 [ + + ]: 78 : while (shumate_vector_geometry_iter (&iter))
651 : : {
652 : : /* See https://en.wikipedia.org/wiki/Shoelace_formula#Triangle_formula */
653 : 75 : if (iter.op == SHUMATE_VECTOR_GEOMETRY_OP_LINE_TO
654 [ + + ]: 75 : || iter.op == SHUMATE_VECTOR_GEOMETRY_OP_CLOSE_PATH)
655 : 60 : area += (double) prev_x * iter.y - (double) iter.x * prev_y;
656 : :
657 [ + + ]: 75 : if (iter.op == SHUMATE_VECTOR_GEOMETRY_OP_CLOSE_PATH)
658 : : {
659 [ + + ]: 15 : if (area > 0)
660 : 9 : exterior_rings ++;
661 : :
662 [ + + ]: 15 : if (exterior_rings > 1)
663 : 3 : return SHUMATE_GEOMETRY_TYPE_MULTIPOLYGON;
664 : :
665 : : area = 0;
666 : : }
667 : :
668 : 72 : prev_x = iter.x;
669 : 72 : prev_y = iter.y;
670 : : }
671 : : }
672 : 3 : return SHUMATE_GEOMETRY_TYPE_POLYGON;
673 : :
674 : : default:
675 : : return SHUMATE_GEOMETRY_TYPE_UNKNOWN;
676 : : }
677 : : #else
678 : : return SHUMATE_GEOMETRY_TYPE_UNKNOWN;
679 : : #endif
680 : : }
681 : :
682 : : static int
683 : 6 : zigzag (guint value)
684 : : {
685 : 6 : return (value >> 1) ^ (-(value & 1));
686 : : }
687 : :
688 : : /**
689 : : * shumate_vector_reader_iter_get_feature_point:
690 : : * @self: A [class@VectorReaderIter].
691 : : * @x: (out) (optional): The x coordinate of the point.
692 : : * @y: (out) (optional): The y coordinate of the point.
693 : : *
694 : : * Gets the coordinates of the current feature in tile space, if the
695 : : * feature is a single point.
696 : : *
697 : : * See [method@VectorReaderIter.get_layer_extent] to get the range
698 : : * of the coordinates.
699 : : *
700 : : * It is an error to call this function if the feature is not a single point.
701 : : * Use [method@VectorReaderIter.get_feature_geometry_type] to check
702 : : * the feature's geometry type.
703 : : *
704 : : * Returns: %TRUE if the feature is a point, %FALSE otherwise.
705 : : *
706 : : * Since: 1.2
707 : : */
708 : : gboolean
709 : 3 : shumate_vector_reader_iter_get_feature_point (ShumateVectorReaderIter *self,
710 : : double *x,
711 : : double *y)
712 : : {
713 [ + - ]: 3 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), FALSE);
714 : :
715 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
716 [ - + ]: 3 : g_return_val_if_fail (self->feature != NULL, FALSE);
717 [ - + ]: 3 : g_return_val_if_fail (self->feature->type == VECTOR_TILE__TILE__GEOM_TYPE__POINT, FALSE);
718 [ - + ]: 3 : g_return_val_if_fail (self->feature->n_geometry == 3, FALSE);
719 : :
720 [ + - ]: 3 : if (x != NULL)
721 : 3 : *x = zigzag (self->feature->geometry[1]);
722 [ + - ]: 3 : if (y != NULL)
723 : 3 : *y = zigzag (self->feature->geometry[2]);
724 : :
725 : : return TRUE;
726 : : #else
727 : : return FALSE;
728 : : #endif
729 : : }
730 : :
731 : : /**
732 : : * shumate_vector_reader_iter_feature_contains_point:
733 : : * @self: A [class@VectorReaderIter].
734 : : *
735 : : * Determines whether the current feature contains the given point.
736 : : *
737 : : * The point must be specified in tile space. See
738 : : * [method@VectorReaderIter.get_layer_extent] to get the range of the
739 : : * coordinates.
740 : : *
741 : : * Only polygon or multipolygon features can contain a point. For all
742 : : * other feature types, this function returns %FALSE.
743 : : *
744 : : * If the point is on the border of the polygon, this function may return
745 : : * either %TRUE or %FALSE.
746 : : *
747 : : * Returns: %TRUE if the feature contains the point, %FALSE otherwise.
748 : : *
749 : : * Since: 1.2
750 : : */
751 : : gboolean
752 : 48 : shumate_vector_reader_iter_feature_contains_point (ShumateVectorReaderIter *self,
753 : : double x,
754 : : double y)
755 : : {
756 [ + - ]: 48 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), FALSE);
757 : :
758 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
759 : 48 : ShumateVectorGeometryIter iter = {0};
760 : 48 : int prev_x = 0, prev_y = 0;
761 : 48 : int winding_number = 0;
762 : :
763 [ - + ]: 48 : g_return_val_if_fail (self->feature != NULL, FALSE);
764 : :
765 [ - + ]: 48 : if (self->feature->type != VECTOR_TILE__TILE__GEOM_TYPE__POLYGON)
766 : : return FALSE;
767 : :
768 : 48 : iter.feature = self->feature;
769 : :
770 : : /* See <https://web.archive.org/web/20130126163405/http://geomalgorithms.com/a03-_inclusion.html>.
771 : : I chose the winding algorithm because it has fewer edge cases. */
772 : :
773 [ + + ]: 723 : while (shumate_vector_geometry_iter (&iter))
774 : : {
775 [ + + ]: 675 : switch (iter.op)
776 : : {
777 : : case SHUMATE_VECTOR_GEOMETRY_OP_MOVE_TO:
778 : : break;
779 : 540 : case SHUMATE_VECTOR_GEOMETRY_OP_LINE_TO:
780 : : case SHUMATE_VECTOR_GEOMETRY_OP_CLOSE_PATH:
781 [ + + + + ]: 540 : if (prev_y <= y && iter.y > y)
782 : : {
783 [ + + ]: 81 : if ((iter.x - prev_x) * (y - prev_y) > (iter.y - prev_y) * (x - prev_x))
784 : 33 : winding_number ++;
785 : : }
786 [ + + + + ]: 459 : else if (prev_y > y && iter.y <= y)
787 : : {
788 [ + + ]: 81 : if ((iter.x - prev_x) * (y - prev_y) < (iter.y - prev_y) * (x - prev_x))
789 : 15 : winding_number --;
790 : : }
791 : : break;
792 : : }
793 : :
794 : 675 : prev_x = iter.x;
795 : 675 : prev_y = iter.y;
796 : : }
797 : :
798 : 48 : return winding_number != 0;
799 : : #else
800 : : return FALSE;
801 : : #endif
802 : : }
803 : :
804 : : /*< private >
805 : : * shumate_vector_reader_iter_new:
806 : : * @reader: A [class@VectorReader]
807 : : *
808 : : * Creates a new [class@VectorReaderIter] for @reader.
809 : : *
810 : : * The public API is [method@VectorReader.iterate].
811 : : *
812 : : * Returns: (transfer full): A new [class@VectorReaderIter]
813 : : */
814 : : ShumateVectorReaderIter *
815 : 39 : shumate_vector_reader_iter_new (ShumateVectorReader *reader)
816 : : {
817 [ + - ]: 39 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER (reader), NULL);
818 : :
819 : 39 : return g_object_new (SHUMATE_TYPE_VECTOR_READER_ITER,
820 : : "reader", reader,
821 : : NULL);
822 : : }
823 : :
824 : : #ifdef SHUMATE_HAS_VECTOR_RENDERER
825 : :
826 : : /*< private >
827 : : * shumate_vector_reader_iter_get_layer_struct:
828 : : * @self: A [class@VectorReaderIter]
829 : : *
830 : : * Gets the raw protobuf struct for the current layer.
831 : : *
832 : : * Returns: (transfer none): a [struct@VectorTile__Tile__Layer]
833 : : */
834 : : VectorTile__Tile__Layer *
835 : 156 : shumate_vector_reader_iter_get_layer_struct (ShumateVectorReaderIter *self)
836 : : {
837 [ + - ]: 156 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), NULL);
838 : 156 : return self->layer;
839 : : }
840 : :
841 : : /*< private >
842 : : * shumate_vector_reader_iter_get_feature_struct:
843 : : *
844 : : * Gets the raw protobuf struct for the current feature.
845 : : *
846 : : * Returns: (transfer none): a [struct@VectorTile__Tile__Feature]
847 : : */
848 : : VectorTile__Tile__Feature *
849 : 180 : shumate_vector_reader_iter_get_feature_struct (ShumateVectorReaderIter *self)
850 : : {
851 [ + - ]: 180 : g_return_val_if_fail (SHUMATE_IS_VECTOR_READER_ITER (self), NULL);
852 : 180 : return self->feature;
853 : : }
854 : :
855 : : #endif
|