Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2021 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 : :
19 : : #include "shumate-vector-renderer.h"
20 : : #include "shumate-vector-expression-private.h"
21 : : #include "shumate-vector-expression-filter-private.h"
22 : : #include "shumate-vector-expression-interpolate-private.h"
23 : : #include "shumate-vector-value-private.h"
24 : :
25 : :
26 [ + + + - ]: 2979 : G_DEFINE_TYPE (ShumateVectorExpression, shumate_vector_expression, G_TYPE_OBJECT)
27 : :
28 : :
29 : : ShumateVectorExpression *
30 : 825 : shumate_vector_expression_from_json (JsonNode *json,
31 : : GError **error)
32 : : {
33 [ + + - + ]: 825 : if (json == NULL || JSON_NODE_HOLDS_NULL (json))
34 : 159 : return shumate_vector_expression_filter_from_literal (&SHUMATE_VECTOR_VALUE_INIT);
35 [ + + ]: 666 : else if (JSON_NODE_HOLDS_VALUE (json))
36 : : {
37 : 54 : g_auto(GValue) gvalue = G_VALUE_INIT;
38 : 54 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
39 : 54 : const char *string;
40 : :
41 : 54 : json_node_get_value (json, &gvalue);
42 [ - + ]: 54 : if (!shumate_vector_value_set_from_g_value (&value, &gvalue))
43 : : {
44 : 0 : g_set_error (error,
45 : : SHUMATE_STYLE_ERROR,
46 : : SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
47 : : "Unsupported literal value in expression");
48 : 0 : return NULL;
49 : : }
50 : :
51 [ + + ]: 54 : if (shumate_vector_value_get_string (&value, &string))
52 : 27 : return shumate_vector_expression_filter_from_format (string, error);
53 : : else
54 : 27 : return shumate_vector_expression_filter_from_literal (&value);
55 : : }
56 [ + + ]: 612 : else if (JSON_NODE_HOLDS_OBJECT (json))
57 : 9 : return shumate_vector_expression_interpolate_from_json_obj (json_node_get_object (json), error);
58 [ + - ]: 603 : else if (JSON_NODE_HOLDS_ARRAY (json))
59 : : {
60 : 603 : JsonArray *array = json_node_get_array (json);
61 [ + + ]: 603 : if (json_array_get_length (array) > 1)
62 : : {
63 : 579 : JsonNode *first = json_array_get_element (array, 0);
64 [ + - + + ]: 579 : if (JSON_NODE_HOLDS_VALUE (first) && json_node_get_value_type (first) != G_TYPE_STRING)
65 : : {
66 : : /* If it's an array of numbers, return it as a literal */
67 : 3 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
68 : 3 : shumate_vector_value_start_array (&value);
69 [ + + ]: 18 : for (guint i = 0; i < json_array_get_length (array); i++)
70 : : {
71 : 15 : g_auto(ShumateVectorValue) element = SHUMATE_VECTOR_VALUE_INIT;
72 [ - + ]: 15 : if (!shumate_vector_value_set_from_json_literal (&element, json_array_get_element (array, i), error))
73 : 0 : return NULL;
74 : 15 : shumate_vector_value_array_append (&value, &element);
75 : : }
76 : :
77 : 3 : return shumate_vector_expression_filter_from_literal (&value);
78 : : }
79 : : }
80 : :
81 : 600 : return shumate_vector_expression_filter_from_json_array (json_node_get_array (json), NULL, error);
82 : : }
83 : : else
84 : 0 : g_assert_not_reached ();
85 : : }
86 : :
87 : :
88 : : static gboolean
89 : 0 : shumate_vector_expression_real_eval (ShumateVectorExpression *self,
90 : : ShumateVectorRenderScope *scope,
91 : : ShumateVectorValue *out)
92 : : {
93 : 0 : g_assert_not_reached ();
94 : : }
95 : :
96 : : /* A default implementation for eval_bitset() that calls the regular eval() method for each
97 : : feature. The mask parameter allows it to skip features that don't need to be calculated
98 : : (e.g. they have been excluded by a previous child of an ALL expression). */
99 : : static ShumateVectorIndexBitset *
100 : 3 : shumate_vector_expression_real_eval_bitset (ShumateVectorExpression *self,
101 : : ShumateVectorRenderScope *scope,
102 : : ShumateVectorIndexBitset *mask)
103 : : {
104 : 3 : VectorTile__Tile__Layer *layer = shumate_vector_reader_iter_get_layer_struct (scope->reader);
105 : 3 : ShumateVectorIndexBitset *result = shumate_vector_index_bitset_new (layer->n_features);
106 : 3 : int feature_idx = 0;
107 : :
108 [ - + ]: 3 : if (mask != NULL)
109 : : {
110 : : feature_idx = -1;
111 [ # # ]: 0 : while ((feature_idx = shumate_vector_index_bitset_next (mask, feature_idx)) != -1)
112 : : {
113 : 0 : shumate_vector_reader_iter_read_feature (scope->reader, feature_idx);
114 [ # # ]: 0 : if (shumate_vector_expression_eval_boolean (self, scope, FALSE))
115 : 0 : shumate_vector_index_bitset_set (result, feature_idx);
116 : : }
117 : : }
118 : : else
119 : : {
120 : 3 : shumate_vector_reader_iter_read_feature (scope->reader, 0);
121 : 9 : while (TRUE)
122 : : {
123 [ + + ]: 6 : if (shumate_vector_expression_eval_boolean (self, scope, FALSE))
124 : 3 : shumate_vector_index_bitset_set (result, feature_idx);
125 : :
126 [ + + ]: 6 : if (!shumate_vector_reader_iter_next_feature (scope->reader))
127 : : break;
128 : :
129 : 3 : feature_idx ++;
130 : : }
131 : : }
132 : :
133 : 3 : return result;
134 : : }
135 : :
136 : :
137 : : static void
138 : 12 : shumate_vector_expression_class_init (ShumateVectorExpressionClass *klass)
139 : : {
140 : 12 : klass->eval = shumate_vector_expression_real_eval;
141 : 12 : klass->eval_bitset = shumate_vector_expression_real_eval_bitset;
142 : 12 : klass->collect_indexes = NULL;
143 : : }
144 : :
145 : :
146 : : static void
147 : 2742 : shumate_vector_expression_init (ShumateVectorExpression *self)
148 : : {
149 : 2742 : }
150 : :
151 : :
152 : : gboolean
153 : 3003 : shumate_vector_expression_eval (ShumateVectorExpression *self,
154 : : ShumateVectorRenderScope *scope,
155 : : ShumateVectorValue *out)
156 : : {
157 [ + + + - ]: 3003 : g_assert (self == NULL || SHUMATE_IS_VECTOR_EXPRESSION (self));
158 : :
159 [ + + ]: 3003 : if (self == NULL)
160 : : return FALSE;
161 : : else
162 : 2886 : return SHUMATE_VECTOR_EXPRESSION_GET_CLASS (self)->eval (self, scope, out);
163 : : }
164 : :
165 : :
166 : : /* Evaluates the expression as a boolean for every feature in the scope's current layer and
167 : : returns the result in a bitset. If the mask parameter is provided, only those features
168 : : need to be calculated. */
169 : : ShumateVectorIndexBitset *
170 : 21 : shumate_vector_expression_eval_bitset (ShumateVectorExpression *self,
171 : : ShumateVectorRenderScope *scope,
172 : : ShumateVectorIndexBitset *mask)
173 : : {
174 [ + - ]: 21 : g_assert (SHUMATE_IS_VECTOR_EXPRESSION (self));
175 : 21 : return SHUMATE_VECTOR_EXPRESSION_GET_CLASS (self)->eval_bitset (self, scope, mask);
176 : : }
177 : :
178 : :
179 : : /* Adds any indexes this expression uses to the index description. Indexes can only be used
180 : : in eval_bitset() implementations, not eval(). */
181 : : void
182 : 33 : shumate_vector_expression_collect_indexes (ShumateVectorExpression *self,
183 : : const char *layer_name,
184 : : ShumateVectorIndexDescription *index_description)
185 : : {
186 [ + - ]: 33 : g_assert (SHUMATE_IS_VECTOR_EXPRESSION (self));
187 [ + - ]: 33 : if (SHUMATE_VECTOR_EXPRESSION_GET_CLASS (self)->collect_indexes != NULL)
188 : 33 : SHUMATE_VECTOR_EXPRESSION_GET_CLASS (self)->collect_indexes (self, layer_name, index_description);
189 : 33 : }
190 : :
191 : :
192 : : double
193 : 237 : shumate_vector_expression_eval_number (ShumateVectorExpression *self,
194 : : ShumateVectorRenderScope *scope,
195 : : double default_val)
196 : : {
197 : 237 : double result;
198 : 474 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
199 : :
200 : 237 : shumate_vector_expression_eval (self, scope, &value);
201 : :
202 [ + + ]: 237 : if (shumate_vector_value_get_number (&value, &result))
203 : 66 : return result;
204 : : else
205 : : return default_val;
206 : : }
207 : :
208 : :
209 : : gboolean
210 : 669 : shumate_vector_expression_eval_boolean (ShumateVectorExpression *self,
211 : : ShumateVectorRenderScope *scope,
212 : : gboolean default_val)
213 : : {
214 : 669 : gboolean result;
215 : 1338 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
216 : :
217 : 669 : shumate_vector_expression_eval (self, scope, &value);
218 : :
219 [ + + ]: 669 : if (shumate_vector_value_get_boolean (&value, &result))
220 : 546 : return result;
221 : : else
222 : : return default_val;
223 : : }
224 : :
225 : :
226 : : char *
227 : 66 : shumate_vector_expression_eval_string (ShumateVectorExpression *self,
228 : : ShumateVectorRenderScope *scope,
229 : : const char *default_val)
230 : : {
231 : 66 : const char *result;
232 : 132 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
233 : :
234 : 66 : shumate_vector_expression_eval (self, scope, &value);
235 : :
236 [ + + ]: 66 : if (shumate_vector_value_get_string (&value, &result))
237 [ - + ]: 48 : return g_strdup (result);
238 : : else
239 [ - + ]: 84 : return g_strdup (default_val);
240 : : }
241 : :
242 : :
243 : : void
244 : 63 : shumate_vector_expression_eval_color (ShumateVectorExpression *self,
245 : : ShumateVectorRenderScope *scope,
246 : : GdkRGBA *color)
247 : : {
248 : 126 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
249 : 63 : shumate_vector_expression_eval (self, scope, &value);
250 : 63 : shumate_vector_value_get_color (&value, color);
251 : 63 : }
252 : :
253 : : ShumateVectorSprite *
254 : 21 : shumate_vector_expression_eval_image (ShumateVectorExpression *self,
255 : : ShumateVectorRenderScope *scope)
256 : : {
257 : 42 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
258 : 21 : shumate_vector_expression_eval (self, scope, &value);
259 [ - + ]: 21 : if (value.type == SHUMATE_VECTOR_VALUE_TYPE_STRING)
260 : : {
261 : 0 : const char *name;
262 : 0 : shumate_vector_value_get_string (&value, &name);
263 : 0 : return shumate_vector_sprite_sheet_get_sprite (scope->sprites, name, scope->scale_factor);
264 : : }
265 [ - + ]: 21 : else if (value.type == SHUMATE_VECTOR_VALUE_TYPE_RESOLVED_IMAGE)
266 : : {
267 : 0 : ShumateVectorSprite *sprite;
268 : 0 : shumate_vector_value_get_image (&value, &sprite);
269 : 0 : return g_object_ref (sprite);
270 : : }
271 : : else
272 : : return NULL;
273 : : }
274 : :
275 : : ShumateVectorAlignment
276 : 30 : shumate_vector_expression_eval_alignment (ShumateVectorExpression *self,
277 : : ShumateVectorRenderScope *scope)
278 : : {
279 : 60 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
280 : 30 : const char *string;
281 : :
282 : 30 : shumate_vector_expression_eval (self, scope, &value);
283 : :
284 [ - + ]: 30 : if (shumate_vector_value_get_string (&value, &string))
285 : : {
286 [ # # ]: 0 : if (g_strcmp0 (string, "map") == 0)
287 : : return SHUMATE_VECTOR_ALIGNMENT_MAP;
288 [ # # ]: 0 : else if (g_strcmp0 (string, "viewport") == 0)
289 : : return SHUMATE_VECTOR_ALIGNMENT_VIEWPORT;
290 [ # # ]: 0 : else if (g_strcmp0 (string, "viewport-glyph") == 0)
291 : : return SHUMATE_VECTOR_ALIGNMENT_VIEWPORT_GLYPH;
292 : : }
293 : :
294 : : return SHUMATE_VECTOR_ALIGNMENT_AUTO;
295 : : }
296 : :
297 : : ShumateVectorPlacement
298 : 15 : shumate_vector_expression_eval_placement (ShumateVectorExpression *self,
299 : : ShumateVectorRenderScope *scope)
300 : : {
301 : 30 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
302 : 15 : const char *string;
303 : :
304 : 15 : shumate_vector_expression_eval (self, scope, &value);
305 : :
306 [ - + ]: 15 : if (shumate_vector_value_get_string (&value, &string))
307 : : {
308 [ # # ]: 0 : if (g_strcmp0 (string, "line") == 0)
309 : : return SHUMATE_VECTOR_PLACEMENT_LINE;
310 [ # # ]: 0 : else if (g_strcmp0 (string, "line-center") == 0)
311 : : return SHUMATE_VECTOR_PLACEMENT_LINE_CENTER;
312 : : }
313 : :
314 : : return SHUMATE_VECTOR_PLACEMENT_POINT;
315 : : }
316 : :
317 : : ShumateVectorAnchor
318 : 30 : shumate_vector_expression_eval_anchor (ShumateVectorExpression *self,
319 : : ShumateVectorRenderScope *scope)
320 : : {
321 : 60 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
322 : 30 : const char *string;
323 : :
324 : 30 : shumate_vector_expression_eval (self, scope, &value);
325 : :
326 [ - + ]: 30 : if (shumate_vector_value_get_string (&value, &string))
327 : : {
328 [ # # ]: 0 : if (g_strcmp0 (string, "top") == 0)
329 : : return SHUMATE_VECTOR_ANCHOR_TOP;
330 [ # # ]: 0 : else if (g_strcmp0 (string, "bottom") == 0)
331 : : return SHUMATE_VECTOR_ANCHOR_BOTTOM;
332 [ # # ]: 0 : else if (g_strcmp0 (string, "left") == 0)
333 : : return SHUMATE_VECTOR_ANCHOR_LEFT;
334 [ # # ]: 0 : else if (g_strcmp0 (string, "right") == 0)
335 : : return SHUMATE_VECTOR_ANCHOR_RIGHT;
336 [ # # ]: 0 : else if (g_strcmp0 (string, "top-left") == 0)
337 : : return SHUMATE_VECTOR_ANCHOR_TOP_LEFT;
338 [ # # ]: 0 : else if (g_strcmp0 (string, "top-right") == 0)
339 : : return SHUMATE_VECTOR_ANCHOR_TOP_RIGHT;
340 [ # # ]: 0 : else if (g_strcmp0 (string, "bottom-left") == 0)
341 : : return SHUMATE_VECTOR_ANCHOR_BOTTOM_LEFT;
342 [ # # ]: 0 : else if (g_strcmp0 (string, "bottom-right") == 0)
343 : : return SHUMATE_VECTOR_ANCHOR_BOTTOM_RIGHT;
344 : : }
345 : :
346 : : return SHUMATE_VECTOR_ANCHOR_CENTER;
347 : : }
348 : :
349 : : ShumateVectorOverlap
350 : 30 : shumate_vector_expression_eval_overlap (ShumateVectorExpression *self,
351 : : ShumateVectorExpression *allow_overlap,
352 : : ShumateVectorRenderScope *scope)
353 : : {
354 : 60 : g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
355 : 30 : const char *string;
356 : :
357 : 30 : shumate_vector_expression_eval (self, scope, &value);
358 : :
359 [ - + ]: 30 : if (shumate_vector_value_get_string (&value, &string))
360 : : {
361 [ # # ]: 0 : if (g_strcmp0 (string, "always") == 0)
362 : : return SHUMATE_VECTOR_OVERLAP_ALWAYS;
363 [ # # ]: 0 : else if (g_strcmp0 (string, "never") == 0)
364 : : return SHUMATE_VECTOR_OVERLAP_NEVER;
365 [ # # ]: 0 : else if (g_strcmp0 (string, "cooperative") == 0)
366 : : return SHUMATE_VECTOR_OVERLAP_COOPERATIVE;
367 : : }
368 : :
369 [ + - ]: 30 : if (shumate_vector_expression_eval_boolean (allow_overlap, scope, FALSE))
370 : : return SHUMATE_VECTOR_OVERLAP_ALWAYS;
371 : : else
372 : : return SHUMATE_VECTOR_OVERLAP_NEVER;
373 : : }
374 : :
375 : : void
376 : 9 : shumate_vector_expression_context_clear (ShumateVectorExpressionContext *ctx)
377 : : {
378 [ + - ]: 9 : g_clear_pointer (&ctx->variables, g_hash_table_unref);
379 : 9 : }
380 : :
|