[libshumate] vector: Add expression system
- From: Marcus Lundblad <mlundblad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] vector: Add expression system
- Date: Mon, 1 Nov 2021 22:00:05 +0000 (UTC)
commit 6e5f7c0ac69eb5c68913f182df5dc9be5ce225f4
Author: James Westman <james jwestman net>
Date: Fri Aug 27 22:46:04 2021 -0500
vector: Add expression system
demos/map-style.json | 11 +-
demos/shumate-demo-window.c | 31 ++-
shumate/meson.build | 8 +
shumate/vector/shumate-vector-background-layer.c | 35 ++-
...shumate-vector-expression-interpolate-private.h | 31 +++
.../vector/shumate-vector-expression-interpolate.c | 248 +++++++++++++++++++++
.../shumate-vector-expression-literal-private.h | 30 +++
shumate/vector/shumate-vector-expression-literal.c | 71 ++++++
shumate/vector/shumate-vector-expression-private.h | 63 ++++++
shumate/vector/shumate-vector-expression.c | 155 +++++++++++++
shumate/vector/shumate-vector-fill-layer.c | 34 ++-
shumate/vector/shumate-vector-line-layer.c | 45 +++-
shumate/vector/shumate-vector-value-private.h | 60 +++++
shumate/vector/shumate-vector-value.c | 206 +++++++++++++++++
tests/meson.build | 3 +
tests/vector-expression.c | 122 ++++++++++
tests/vector-value.c | 184 +++++++++++++++
17 files changed, 1303 insertions(+), 34 deletions(-)
---
diff --git a/demos/map-style.json b/demos/map-style.json
index 453ce79..79d3c2c 100644
--- a/demos/map-style.json
+++ b/demos/map-style.json
@@ -12,13 +12,18 @@
"type": "fill",
"source-layer": "water",
"paint": {
- "fill-color": "#3584e4"
+ "fill-color": {
+ "stops": [
+ [0, "#3584e4"],
+ [5, "#1a5fb4"]
+ ]
+ }
}
},
{
- "id": "boundary",
+ "id": "country_boundary",
"type": "line",
- "source-layer": "boundary",
+ "source-layer": "admin_boundary",
"paint": {
"line-color": "#9a9996",
"line-opacity": 0.5,
diff --git a/demos/shumate-demo-window.c b/demos/shumate-demo-window.c
index 1d24f24..a89369a 100644
--- a/demos/shumate-demo-window.c
+++ b/demos/shumate-demo-window.c
@@ -141,7 +141,7 @@ shumate_demo_window_init (ShumateDemoWindow *self)
g_autoptr(GBytes) bytes = NULL;
const char *style_json;
g_autoptr(ShumateVectorStyle) style = NULL;
- ShumateMapSource *map_source = NULL;
+ GError *error = NULL;
gtk_widget_init_template (GTK_WIDGET (self));
@@ -154,17 +154,24 @@ shumate_demo_window_init (ShumateDemoWindow *self)
bytes = g_resources_lookup_data ("/org/gnome/Shumate/Demo/styles/map-style.json",
G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
style_json = g_bytes_get_data (bytes, NULL);
- style = shumate_vector_style_create (style_json, NULL);
-
- map_source = SHUMATE_MAP_SOURCE (shumate_network_tile_source_new_vector_full (
- "vector-tiles",
- "Vector Tiles",
- "© OpenStreetMap contributors", NULL, 0, 14, 512,
- SHUMATE_MAP_PROJECTION_MERCATOR,
- "https://jwestman.pages.gitlab.gnome.org/vector-tile-test-data/world_overview/#Z#/#X#/#Y#.pbf",
- style
- ));
- shumate_map_source_registry_add (self->registry, map_source);
+
+ if (!(style = shumate_vector_style_create (style_json, &error)))
+ {
+ g_warning ("Failed to create vector map style: %s", error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ ShumateMapSource *map_source = SHUMATE_MAP_SOURCE (shumate_network_tile_source_new_vector_full (
+ "vector-tiles",
+ "Vector Tiles",
+ "© OpenStreetMap contributors", NULL, 0, 5, 512,
+ SHUMATE_MAP_PROJECTION_MERCATOR,
+ "https://jwestman.pages.gitlab.gnome.org/vector-tile-test-data/world_overview/#Z#/#X#/#Y#.pbf",
+ style
+ ));
+ shumate_map_source_registry_add (self->registry, map_source);
+ }
viewport = shumate_map_get_viewport (self->map);
diff --git a/shumate/meson.build b/shumate/meson.build
index 53ce659..e49847f 100644
--- a/shumate/meson.build
+++ b/shumate/meson.build
@@ -27,11 +27,15 @@ libshumate_private_h = [
'shumate-marker-private.h',
'vector/shumate-vector-background-layer-private.h',
+ 'vector/shumate-vector-expression-private.h',
+ 'vector/shumate-vector-expression-interpolate-private.h',
+ 'vector/shumate-vector-expression-literal-private.h',
'vector/shumate-vector-fill-layer-private.h',
'vector/shumate-vector-layer-private.h',
'vector/shumate-vector-line-layer-private.h',
'vector/shumate-vector-render-scope-private.h',
'vector/shumate-vector-utils-private.h',
+ 'vector/shumate-vector-value-private.h',
'vector/vector_tile.pb-c.h',
]
@@ -59,11 +63,15 @@ libshumate_sources = [
'shumate-viewport.c',
'vector/shumate-vector-background-layer.c',
+ 'vector/shumate-vector-expression.c',
+ 'vector/shumate-vector-expression-interpolate.c',
+ 'vector/shumate-vector-expression-literal.c',
'vector/shumate-vector-fill-layer.c',
'vector/shumate-vector-layer.c',
'vector/shumate-vector-line-layer.c',
'vector/shumate-vector-render-scope.c',
'vector/shumate-vector-utils.c',
+ 'vector/shumate-vector-value.c',
'vector/vector_tile.pb-c.c',
]
diff --git a/shumate/vector/shumate-vector-background-layer.c
b/shumate/vector/shumate-vector-background-layer.c
index 462398a..a1b0f7c 100644
--- a/shumate/vector/shumate-vector-background-layer.c
+++ b/shumate/vector/shumate-vector-background-layer.c
@@ -17,14 +17,15 @@
#include <gtk/gtk.h>
#include "shumate-vector-background-layer-private.h"
+#include "shumate-vector-expression-private.h"
#include "shumate-vector-utils-private.h"
struct _ShumateVectorBackgroundLayer
{
ShumateVectorLayer parent_instance;
- GdkRGBA color;
- double opacity;
+ ShumateVectorExpression *color;
+ ShumateVectorExpression *opacity;
};
G_DEFINE_TYPE (ShumateVectorBackgroundLayer, shumate_vector_background_layer, SHUMATE_TYPE_VECTOR_LAYER)
@@ -43,29 +44,51 @@ shumate_vector_background_layer_create_from_json (JsonObject *object, GError **e
if (!shumate_vector_json_get_object (paint_node, &paint, error))
return NULL;
- gdk_rgba_parse (&layer->color, json_object_get_string_member_with_default (paint, "background-color",
"#000000"));
- layer->opacity = json_object_get_double_member_with_default (paint, "background-opacity", 1.0);
+ if (!(layer->color = shumate_vector_expression_from_json (json_object_get_member (paint,
"background-color"), error)))
+ return NULL;
+
+ if (!(layer->opacity = shumate_vector_expression_from_json (json_object_get_member (paint,
"background-opacity"), error)))
+ return NULL;
}
return (ShumateVectorLayer *)layer;
}
+static void
+shumate_vector_background_layer_finalize (GObject *object)
+{
+ ShumateVectorBackgroundLayer *self = SHUMATE_VECTOR_BACKGROUND_LAYER (object);
+
+ g_clear_object (&self->color);
+ g_clear_object (&self->opacity);
+
+ G_OBJECT_CLASS (shumate_vector_background_layer_parent_class)->finalize (object);
+}
+
+
static void
shumate_vector_background_layer_render (ShumateVectorLayer *layer, ShumateVectorRenderScope *scope)
{
ShumateVectorBackgroundLayer *self = SHUMATE_VECTOR_BACKGROUND_LAYER (layer);
+ GdkRGBA color = SHUMATE_VECTOR_COLOR_BLACK;
+ double opacity;
+
+ shumate_vector_expression_eval_color (self->color, scope, &color);
+ opacity = shumate_vector_expression_eval_number (self->opacity, scope, 1.0);
- gdk_cairo_set_source_rgba (scope->cr, &self->color);
- cairo_paint_with_alpha (scope->cr, self->opacity);
+ gdk_cairo_set_source_rgba (scope->cr, &color);
+ cairo_paint_with_alpha (scope->cr, opacity);
}
static void
shumate_vector_background_layer_class_init (ShumateVectorBackgroundLayerClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
ShumateVectorLayerClass *layer_class = SHUMATE_VECTOR_LAYER_CLASS (klass);
+ object_class->finalize = shumate_vector_background_layer_finalize;
layer_class->render = shumate_vector_background_layer_render;
}
diff --git a/shumate/vector/shumate-vector-expression-interpolate-private.h
b/shumate/vector/shumate-vector-expression-interpolate-private.h
new file mode 100644
index 0000000..a7f5d8f
--- /dev/null
+++ b/shumate/vector/shumate-vector-expression-interpolate-private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <json-glib/json-glib.h>
+#include "shumate-vector-expression-private.h"
+
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_EXPRESSION_INTERPOLATE (shumate_vector_expression_interpolate_get_type())
+G_DECLARE_FINAL_TYPE (ShumateVectorExpressionInterpolate, shumate_vector_expression_interpolate, SHUMATE,
VECTOR_EXPRESSION_INTERPOLATE, ShumateVectorExpression)
+
+ShumateVectorExpression *shumate_vector_expression_interpolate_from_json_obj (JsonObject *object, GError
**error);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-expression-interpolate.c
b/shumate/vector/shumate-vector-expression-interpolate.c
new file mode 100644
index 0000000..6597e0e
--- /dev/null
+++ b/shumate/vector/shumate-vector-expression-interpolate.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "shumate-vector-style.h"
+#include "shumate-vector-expression-interpolate-private.h"
+#include "shumate-vector-expression-literal-private.h"
+#include "shumate-vector-utils-private.h"
+
+typedef struct {
+ double point;
+ ShumateVectorExpression *expr;
+} Stop;
+
+struct _ShumateVectorExpressionInterpolate
+{
+ ShumateVectorExpression parent_instance;
+
+ ShumateVectorExpression *input;
+ double base;
+ GPtrArray *stops;
+};
+
+G_DEFINE_TYPE (ShumateVectorExpressionInterpolate, shumate_vector_expression_interpolate,
SHUMATE_TYPE_VECTOR_EXPRESSION)
+
+
+ShumateVectorExpression *
+shumate_vector_expression_interpolate_from_json_obj (JsonObject *object, GError **error)
+{
+ g_autoptr(ShumateVectorExpressionInterpolate) self = g_object_new
(SHUMATE_TYPE_VECTOR_EXPRESSION_INTERPOLATE, NULL);
+ JsonNode *stops_node;
+
+ self->base = json_object_get_double_member_with_default (object, "base", 1.0);
+
+ if ((stops_node = json_object_get_member (object, "stops")))
+ {
+ JsonArray *stops;
+
+ if (!shumate_vector_json_get_array (stops_node, &stops, error))
+ return NULL;
+
+ for (int i = 0, n = json_array_get_length (stops); i < n; i ++)
+ {
+ JsonNode *stop_node = json_array_get_element (stops, i);
+ JsonArray *stop_array;
+ Stop *stop;
+ JsonNode *point_node;
+ JsonNode *value_node;
+ g_auto(GValue) gvalue = G_VALUE_INIT;
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+
+ if (!shumate_vector_json_get_array (stop_node, &stop_array, error))
+ return NULL;
+
+ if (json_array_get_length (stop_array) != 2)
+ {
+ g_set_error (error,
+ SHUMATE_STYLE_ERROR,
+ SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
+ "Expected element of \"stops\" to have exactly 2 elements");
+ return NULL;
+ }
+
+ point_node = json_array_get_element (stop_array, 0);
+ value_node = json_array_get_element (stop_array, 1);
+
+ if (!JSON_NODE_HOLDS_VALUE (point_node)
+ || !g_value_type_transformable (json_node_get_value_type (point_node), G_TYPE_DOUBLE))
+ {
+ g_set_error (error,
+ SHUMATE_STYLE_ERROR,
+ SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
+ "Expected element 1 of \"stops\" to be a number");
+ return NULL;
+ }
+
+ if (!JSON_NODE_HOLDS_VALUE (value_node))
+ {
+ g_set_error (error,
+ SHUMATE_STYLE_ERROR,
+ SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
+ "Expected element 2 of \"stops\" to be a literal value");
+ return NULL;
+ }
+
+ json_node_get_value (value_node, &gvalue);
+
+ if (!shumate_vector_value_set_from_g_value (&value, &gvalue))
+ {
+ g_set_error (error,
+ SHUMATE_STYLE_ERROR,
+ SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
+ "Could not parse literal value");
+ return NULL;
+ }
+
+ stop = g_new0 (Stop, 1);
+ stop->point = json_node_get_double (point_node);
+ stop->expr = shumate_vector_expression_literal_new (&value);
+
+ g_ptr_array_add (self->stops, stop);
+ }
+ }
+
+ return (ShumateVectorExpression *)g_steal_pointer (&self);
+}
+
+
+static void
+stop_free (Stop *stop)
+{
+ g_clear_object (&stop->expr);
+ g_free (stop);
+}
+
+
+static double
+lerp_double (double a, double b, double pos)
+{
+ return (b - a) * pos + a;
+}
+
+
+static void
+lerp (ShumateVectorValue *last_value, ShumateVectorValue *next_value, double pos, ShumateVectorValue *out)
+{
+ gdouble last_double, next_double;
+ GdkRGBA last_color, next_color;
+
+ if (shumate_vector_value_get_number (last_value, &last_double)
+ && shumate_vector_value_get_number (next_value, &next_double))
+ shumate_vector_value_set_number (out, lerp_double (last_double, next_double, pos));
+ else if (shumate_vector_value_get_color (last_value, &last_color)
+ && shumate_vector_value_get_color (next_value, &next_color))
+ {
+ GdkRGBA color = {
+ .red = lerp_double (last_color.red, next_color.red, pos),
+ .green = lerp_double (last_color.green, next_color.green, pos),
+ .blue = lerp_double (last_color.blue, next_color.blue, pos),
+ .alpha = lerp_double (last_color.alpha, next_color.alpha, pos),
+ };
+ shumate_vector_value_set_color (out, &color);
+ }
+ else
+ shumate_vector_value_unset (out);
+}
+
+
+static void
+exp_interp (double last_point,
+ double next_point,
+ ShumateVectorValue *last_value,
+ ShumateVectorValue *next_value,
+ double input,
+ double base,
+ ShumateVectorValue *dest)
+{
+ double diff = next_point - last_point;
+ double pos = input - last_point;
+
+ lerp (last_value, next_value, (pow (base, pos) - 1.0) / (pow (base, diff) - 1.0), dest);
+}
+
+
+static void
+shumate_vector_expression_interpolate_finalize (GObject *object)
+{
+ ShumateVectorExpressionInterpolate *self = (ShumateVectorExpressionInterpolate *)object;
+
+ g_clear_object (&self->input);
+ g_clear_pointer (&self->stops, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (shumate_vector_expression_interpolate_parent_class)->finalize (object);
+}
+
+
+static gboolean
+shumate_vector_expression_interpolate_eval (ShumateVectorExpression *expr,
+ ShumateVectorRenderScope *scope,
+ ShumateVectorValue *out)
+{
+ ShumateVectorExpressionInterpolate *self = (ShumateVectorExpressionInterpolate *)expr;
+ double zoom = scope->zoom_level;
+ Stop **stops = (Stop **)self->stops->pdata;
+ guint n_stops = self->stops->len;
+
+ if (n_stops == 0)
+ return FALSE;
+
+ if (zoom < stops[0]->point)
+ return shumate_vector_expression_eval (stops[0]->expr, scope, out);
+
+ for (int i = 1; i < n_stops; i ++)
+ {
+ Stop *last = stops[i - 1];
+ Stop *next = stops[i];
+ if (last->point <= zoom && zoom < next->point)
+ {
+ double pos_norm = (zoom - last->point) / (next->point - last->point);
+ g_auto(ShumateVectorValue) last_value = SHUMATE_VECTOR_VALUE_INIT;
+ g_auto(ShumateVectorValue) next_value = SHUMATE_VECTOR_VALUE_INIT;
+
+ if (!shumate_vector_expression_eval (last->expr, scope, &last_value))
+ return FALSE;
+ if (!shumate_vector_expression_eval (next->expr, scope, &next_value))
+ return FALSE;
+
+ if (self->base == 1.0)
+ lerp (&last_value, &next_value, pos_norm, out);
+ else
+ exp_interp (last->point, next->point, &last_value, &next_value, zoom, self->base, out);
+
+ return TRUE;
+ }
+ }
+
+ return shumate_vector_expression_eval (stops[n_stops - 1]->expr, scope, out);
+}
+
+
+static void
+shumate_vector_expression_interpolate_class_init (ShumateVectorExpressionInterpolateClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ShumateVectorExpressionClass *expr_class = SHUMATE_VECTOR_EXPRESSION_CLASS (klass);
+
+ object_class->finalize = shumate_vector_expression_interpolate_finalize;
+ expr_class->eval = shumate_vector_expression_interpolate_eval;
+}
+
+static void
+shumate_vector_expression_interpolate_init (ShumateVectorExpressionInterpolate *self)
+{
+ self->stops = g_ptr_array_new_with_free_func ((GDestroyNotify) stop_free);
+}
diff --git a/shumate/vector/shumate-vector-expression-literal-private.h
b/shumate/vector/shumate-vector-expression-literal-private.h
new file mode 100644
index 0000000..46f0847
--- /dev/null
+++ b/shumate/vector/shumate-vector-expression-literal-private.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "shumate-vector-value-private.h"
+#include "shumate-vector-expression-private.h"
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_EXPRESSION_LITERAL (shumate_vector_expression_literal_get_type())
+G_DECLARE_FINAL_TYPE (ShumateVectorExpressionLiteral, shumate_vector_expression_literal, SHUMATE,
VECTOR_EXPRESSION_LITERAL, ShumateVectorExpression)
+
+ShumateVectorExpression *shumate_vector_expression_literal_new (ShumateVectorValue *value);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-expression-literal.c
b/shumate/vector/shumate-vector-expression-literal.c
new file mode 100644
index 0000000..6f7bdbb
--- /dev/null
+++ b/shumate/vector/shumate-vector-expression-literal.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+#include "shumate-vector-expression-literal-private.h"
+
+struct _ShumateVectorExpressionLiteral
+{
+ ShumateVectorExpression parent_instance;
+
+ ShumateVectorValue value;
+};
+
+G_DEFINE_TYPE (ShumateVectorExpressionLiteral, shumate_vector_expression_literal,
SHUMATE_TYPE_VECTOR_EXPRESSION)
+
+ShumateVectorExpression *
+shumate_vector_expression_literal_new (ShumateVectorValue *value)
+{
+ ShumateVectorExpressionLiteral *self = g_object_new (SHUMATE_TYPE_VECTOR_EXPRESSION_LITERAL, NULL);
+ shumate_vector_value_copy (value, &self->value);
+ return (ShumateVectorExpression *)self;
+}
+
+static void
+shumate_vector_expression_literal_finalize (GObject *object)
+{
+ ShumateVectorExpressionLiteral *self = (ShumateVectorExpressionLiteral *)object;
+
+ shumate_vector_value_unset (&self->value);
+
+ G_OBJECT_CLASS (shumate_vector_expression_literal_parent_class)->finalize (object);
+}
+
+static gboolean
+shumate_vector_expression_literal_eval (ShumateVectorExpression *expr,
+ ShumateVectorRenderScope *scope,
+ ShumateVectorValue *out)
+{
+ ShumateVectorExpressionLiteral *self = (ShumateVectorExpressionLiteral *)expr;
+ shumate_vector_value_copy (&self->value, out);
+ return TRUE;
+}
+
+static void
+shumate_vector_expression_literal_class_init (ShumateVectorExpressionLiteralClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ShumateVectorExpressionClass *expr_class = SHUMATE_VECTOR_EXPRESSION_CLASS (klass);
+
+ object_class->finalize = shumate_vector_expression_literal_finalize;
+ expr_class->eval = shumate_vector_expression_literal_eval;
+}
+
+static void
+shumate_vector_expression_literal_init (ShumateVectorExpressionLiteral *self)
+{
+}
diff --git a/shumate/vector/shumate-vector-expression-private.h
b/shumate/vector/shumate-vector-expression-private.h
new file mode 100644
index 0000000..e485bfa
--- /dev/null
+++ b/shumate/vector/shumate-vector-expression-private.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <json-glib/json-glib.h>
+#include "shumate-vector-render-scope-private.h"
+#include "shumate-vector-value-private.h"
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_EXPRESSION (shumate_vector_expression_get_type())
+G_DECLARE_DERIVABLE_TYPE (ShumateVectorExpression, shumate_vector_expression, SHUMATE, VECTOR_EXPRESSION,
GObject)
+
+struct _ShumateVectorExpressionClass
+{
+ GObjectClass parent_class;
+
+ gboolean (*eval) (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ ShumateVectorValue *out);
+};
+
+ShumateVectorExpression *shumate_vector_expression_from_json (JsonNode *json, GError **error);
+
+gboolean shumate_vector_expression_eval (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ ShumateVectorValue *out);
+
+
+
+double shumate_vector_expression_eval_number (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ double default_val);
+
+gboolean shumate_vector_expression_eval_boolean (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ gboolean default_val);
+
+
+char *shumate_vector_expression_eval_string (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ const char *default_val);
+
+
+void shumate_vector_expression_eval_color (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ GdkRGBA *color);
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-expression.c b/shumate/vector/shumate-vector-expression.c
new file mode 100644
index 0000000..14862a2
--- /dev/null
+++ b/shumate/vector/shumate-vector-expression.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+#include "shumate-vector-style.h"
+#include "shumate-vector-expression-private.h"
+#include "shumate-vector-expression-interpolate-private.h"
+#include "shumate-vector-expression-literal-private.h"
+#include "shumate-vector-value-private.h"
+
+
+G_DEFINE_TYPE (ShumateVectorExpression, shumate_vector_expression, G_TYPE_OBJECT)
+
+
+ShumateVectorExpression *
+shumate_vector_expression_from_json (JsonNode *json, GError **error)
+{
+ if (json == NULL || JSON_NODE_HOLDS_NULL (json))
+ return shumate_vector_expression_literal_new (&SHUMATE_VECTOR_VALUE_INIT);
+ else if (JSON_NODE_HOLDS_VALUE (json))
+ {
+ g_auto(GValue) gvalue = G_VALUE_INIT;
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+
+ json_node_get_value (json, &gvalue);
+ if (!shumate_vector_value_set_from_g_value (&value, &gvalue))
+ {
+ g_set_error (error,
+ SHUMATE_STYLE_ERROR,
+ SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
+ "Unsupported literal value in expression");
+ return NULL;
+ }
+
+ return shumate_vector_expression_literal_new (&value);
+ }
+ else if (JSON_NODE_HOLDS_OBJECT (json))
+ return shumate_vector_expression_interpolate_from_json_obj (json_node_get_object (json), error);
+ else
+ {
+ g_set_error (error,
+ SHUMATE_STYLE_ERROR,
+ SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
+ "Unsupported expression type");
+ return NULL;
+ }
+}
+
+
+static gboolean
+shumate_vector_expression_real_eval (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ ShumateVectorValue *out)
+{
+ g_assert_not_reached ();
+}
+
+
+static void
+shumate_vector_expression_class_init (ShumateVectorExpressionClass *klass)
+{
+ klass->eval = shumate_vector_expression_real_eval;
+}
+
+
+static void
+shumate_vector_expression_init (ShumateVectorExpression *self)
+{
+}
+
+
+gboolean
+shumate_vector_expression_eval (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ ShumateVectorValue *out)
+{
+ g_return_val_if_fail (SHUMATE_IS_VECTOR_EXPRESSION (self), FALSE);
+ return SHUMATE_VECTOR_EXPRESSION_GET_CLASS (self)->eval (self, scope, out);
+}
+
+
+double
+shumate_vector_expression_eval_number (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ double default_val)
+{
+ double result;
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+
+ shumate_vector_expression_eval (self, scope, &value);
+
+ if (shumate_vector_value_get_number (&value, &result))
+ return result;
+ else
+ return default_val;
+}
+
+
+gboolean
+shumate_vector_expression_eval_boolean (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ gboolean default_val)
+{
+ gboolean result;
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+
+ shumate_vector_expression_eval (self, scope, &value);
+
+ if (shumate_vector_value_get_boolean (&value, &result))
+ return result;
+ else
+ return default_val;
+}
+
+
+char *
+shumate_vector_expression_eval_string (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ const char *default_val)
+{
+ const char *result;
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+
+ shumate_vector_expression_eval (self, scope, &value);
+
+ if (shumate_vector_value_get_string (&value, &result))
+ return g_strdup (result);
+ else
+ return g_strdup (default_val);
+}
+
+
+void
+shumate_vector_expression_eval_color (ShumateVectorExpression *self,
+ ShumateVectorRenderScope *scope,
+ GdkRGBA *color)
+{
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+ shumate_vector_expression_eval (self, scope, &value);
+ shumate_vector_value_get_color (&value, color);
+}
diff --git a/shumate/vector/shumate-vector-fill-layer.c b/shumate/vector/shumate-vector-fill-layer.c
index b29f6a2..080bb7f 100644
--- a/shumate/vector/shumate-vector-fill-layer.c
+++ b/shumate/vector/shumate-vector-fill-layer.c
@@ -16,15 +16,17 @@
*/
#include <gtk/gtk.h>
+#include "shumate-vector-expression-private.h"
#include "shumate-vector-fill-layer-private.h"
#include "shumate-vector-utils-private.h"
+#include "shumate-vector-value-private.h"
struct _ShumateVectorFillLayer
{
ShumateVectorLayer parent_instance;
- GdkRGBA color;
- double opacity;
+ ShumateVectorExpression *color;
+ ShumateVectorExpression *opacity;
};
G_DEFINE_TYPE (ShumateVectorFillLayer, shumate_vector_fill_layer, SHUMATE_TYPE_VECTOR_LAYER)
@@ -43,8 +45,11 @@ shumate_vector_fill_layer_create_from_json (JsonObject *object, GError **error)
if (!shumate_vector_json_get_object (paint_node, &paint, error))
return NULL;
- gdk_rgba_parse (&layer->color, json_object_get_string_member_with_default (paint, "fill-color",
"#000000"));
- layer->opacity = json_object_get_double_member_with_default (paint, "fill-opacity", 1.0);
+ if (!(layer->color = shumate_vector_expression_from_json (json_object_get_member (paint,
"fill-color"), error)))
+ return NULL;
+
+ if (!(layer->opacity = shumate_vector_expression_from_json (json_object_get_member (paint,
"fill-opacity"), error)))
+ return NULL;
}
return (ShumateVectorLayer *)layer;
@@ -55,19 +60,38 @@ static void
shumate_vector_fill_layer_render (ShumateVectorLayer *layer, ShumateVectorRenderScope *scope)
{
ShumateVectorFillLayer *self = SHUMATE_VECTOR_FILL_LAYER (layer);
+ GdkRGBA color = SHUMATE_VECTOR_COLOR_BLACK;
+ double opacity;
+
+ shumate_vector_expression_eval_color (self->color, scope, &color);
+ opacity = shumate_vector_expression_eval_number (self->opacity, scope, 1.0);
shumate_vector_render_scope_exec_geometry (scope);
- cairo_set_source_rgba (scope->cr, self->color.red, self->color.green, self->color.blue, self->opacity);
+ cairo_set_source_rgba (scope->cr, color.red, color.green, color.blue, opacity);
cairo_fill (scope->cr);
}
+static void
+shumate_vector_fill_layer_finalize (GObject *object)
+{
+ ShumateVectorFillLayer *self = SHUMATE_VECTOR_FILL_LAYER (object);
+
+ g_clear_object (&self->color);
+ g_clear_object (&self->opacity);
+
+ G_OBJECT_CLASS (shumate_vector_fill_layer_parent_class)->finalize (object);
+}
+
+
static void
shumate_vector_fill_layer_class_init (ShumateVectorFillLayerClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
ShumateVectorLayerClass *layer_class = SHUMATE_VECTOR_LAYER_CLASS (klass);
+ object_class->finalize = shumate_vector_fill_layer_finalize;
layer_class->render = shumate_vector_fill_layer_render;
}
diff --git a/shumate/vector/shumate-vector-line-layer.c b/shumate/vector/shumate-vector-line-layer.c
index 0c3ca5c..18fae4b 100644
--- a/shumate/vector/shumate-vector-line-layer.c
+++ b/shumate/vector/shumate-vector-line-layer.c
@@ -16,16 +16,18 @@
*/
#include <gtk/gtk.h>
+#include "shumate-vector-expression-private.h"
#include "shumate-vector-line-layer-private.h"
#include "shumate-vector-utils-private.h"
+#include "shumate-vector-value-private.h"
struct _ShumateVectorLineLayer
{
ShumateVectorLayer parent_instance;
- GdkRGBA color;
- double opacity;
- double width;
+ ShumateVectorExpression *color;
+ ShumateVectorExpression *opacity;
+ ShumateVectorExpression *width;
};
G_DEFINE_TYPE (ShumateVectorLineLayer, shumate_vector_line_layer, SHUMATE_TYPE_VECTOR_LAYER)
@@ -44,24 +46,49 @@ shumate_vector_line_layer_create_from_json (JsonObject *object, GError **error)
if (!shumate_vector_json_get_object (paint_node, &paint, error))
return NULL;
- gdk_rgba_parse (&layer->color, json_object_get_string_member_with_default (paint, "line-color",
"#000000"));
- layer->opacity = json_object_get_double_member_with_default (paint, "line-opacity", 1.0);
- layer->width = json_object_get_double_member_with_default (paint, "line-width", 1.0);
+ if (!(layer->color = shumate_vector_expression_from_json (json_object_get_member (paint,
"line-color"), error)))
+ return NULL;
+
+ if (!(layer->opacity = shumate_vector_expression_from_json (json_object_get_member (paint,
"line-opacity"), error)))
+ return NULL;
+
+ if (!(layer->width = shumate_vector_expression_from_json (json_object_get_member (paint,
"line-width"), error)))
+ return NULL;
}
return (ShumateVectorLayer *)layer;
}
+static void
+shumate_vector_line_layer_finalize (GObject *object)
+{
+ ShumateVectorLineLayer *self = SHUMATE_VECTOR_LINE_LAYER (object);
+
+ g_clear_object (&self->color);
+ g_clear_object (&self->opacity);
+ g_clear_object (&self->width);
+
+ G_OBJECT_CLASS (shumate_vector_line_layer_parent_class)->finalize (object);
+}
+
+
static void
shumate_vector_line_layer_render (ShumateVectorLayer *layer, ShumateVectorRenderScope *scope)
{
ShumateVectorLineLayer *self = SHUMATE_VECTOR_LINE_LAYER (layer);
+ GdkRGBA color = SHUMATE_VECTOR_COLOR_BLACK;
+ double opacity;
+ double width;
+
+ shumate_vector_expression_eval_color (self->color, scope, &color);
+ opacity = shumate_vector_expression_eval_number (self->opacity, scope, 1.0);
+ width = shumate_vector_expression_eval_number (self->width, scope, 1.0);
shumate_vector_render_scope_exec_geometry (scope);
- cairo_set_source_rgba (scope->cr, self->color.red, self->color.green, self->color.blue, self->opacity);
- cairo_set_line_width (scope->cr, self->width * scope->scale);
+ cairo_set_source_rgba (scope->cr, color.red, color.green, color.blue, opacity);
+ cairo_set_line_width (scope->cr, width * scope->scale);
cairo_stroke (scope->cr);
}
@@ -69,8 +96,10 @@ shumate_vector_line_layer_render (ShumateVectorLayer *layer, ShumateVectorRender
static void
shumate_vector_line_layer_class_init (ShumateVectorLineLayerClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
ShumateVectorLayerClass *layer_class = SHUMATE_VECTOR_LAYER_CLASS (klass);
+ object_class->finalize = shumate_vector_line_layer_finalize;
layer_class->render = shumate_vector_line_layer_render;
}
diff --git a/shumate/vector/shumate-vector-value-private.h b/shumate/vector/shumate-vector-value-private.h
new file mode 100644
index 0000000..a0bfb56
--- /dev/null
+++ b/shumate/vector/shumate-vector-value-private.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <json-glib/json-glib.h>
+#include <gtk/gtk.h>
+
+#define SHUMATE_VECTOR_COLOR_BLACK ((GdkRGBA) {.red=0, .green=0, .blue=0, .alpha=1})
+
+typedef struct {
+ int type;
+
+ union {
+ double number;
+ gboolean boolean;
+ struct {
+ char *string;
+ GdkRGBA color;
+ int color_state;
+ };
+ };
+} ShumateVectorValue;
+
+#define SHUMATE_VECTOR_VALUE_INIT ((ShumateVectorValue) {.type = 0})
+
+gboolean shumate_vector_value_set_from_g_value (ShumateVectorValue *self, const GValue *value);
+
+void shumate_vector_value_unset (ShumateVectorValue *self);
+void shumate_vector_value_copy (ShumateVectorValue *self, ShumateVectorValue *out);
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (ShumateVectorValue, shumate_vector_value_unset)
+
+void shumate_vector_value_set_number (ShumateVectorValue *self, double number);
+gboolean shumate_vector_value_get_number (ShumateVectorValue *self, double *number);
+
+void shumate_vector_value_set_string (ShumateVectorValue *self, const char *string);
+gboolean shumate_vector_value_get_string (ShumateVectorValue *self, const char **string);
+
+void shumate_vector_value_set_boolean (ShumateVectorValue *self, gboolean boolean);
+gboolean shumate_vector_value_get_boolean (ShumateVectorValue *self, gboolean *boolean);
+
+void shumate_vector_value_set_color (ShumateVectorValue *self, GdkRGBA *color);
+gboolean shumate_vector_value_get_color (ShumateVectorValue *self, GdkRGBA *color);
+
+gboolean shumate_vector_value_equal (ShumateVectorValue *a, ShumateVectorValue *b);
diff --git a/shumate/vector/shumate-vector-value.c b/shumate/vector/shumate-vector-value.c
new file mode 100644
index 0000000..294dea8
--- /dev/null
+++ b/shumate/vector/shumate-vector-value.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2021 James Westman <james jwestman net>
+ *
+ * This library 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 Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "shumate-vector-value-private.h"
+
+enum {
+ TYPE_NULL,
+ TYPE_NUMBER,
+ TYPE_BOOLEAN,
+ TYPE_STRING,
+ TYPE_COLOR,
+};
+
+enum {
+ COLOR_UNSET,
+ COLOR_SET,
+ COLOR_INVALID,
+};
+
+gboolean
+shumate_vector_value_set_from_g_value (ShumateVectorValue *self, const GValue *value)
+{
+ g_auto(GValue) tmp = G_VALUE_INIT;
+
+ if (value == NULL)
+ shumate_vector_value_unset (self);
+ else if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_DOUBLE))
+ {
+ g_value_init (&tmp, G_TYPE_DOUBLE);
+ g_value_transform (value, &tmp);
+ shumate_vector_value_set_number (self, g_value_get_double (&tmp));
+ }
+ else if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_BOOLEAN))
+ {
+ g_value_init (&tmp, G_TYPE_BOOLEAN);
+ g_value_transform (value, &tmp);
+ shumate_vector_value_set_boolean (self, g_value_get_boolean (&tmp));
+ }
+ else if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING))
+ {
+ g_value_init (&tmp, G_TYPE_STRING);
+ g_value_transform (value, &tmp);
+ shumate_vector_value_set_string (self, g_value_get_string (&tmp));
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+shumate_vector_value_unset (ShumateVectorValue *self)
+{
+ if (self->type == TYPE_STRING)
+ g_clear_pointer (&self->string, g_free);
+ self->type = TYPE_NULL;
+}
+
+
+void
+shumate_vector_value_copy (ShumateVectorValue *self, ShumateVectorValue *out)
+{
+ shumate_vector_value_unset (out);
+ *out = *self;
+
+ if (self->type == TYPE_STRING)
+ out->string = g_strdup (out->string);
+}
+
+
+void
+shumate_vector_value_set_number (ShumateVectorValue *self, double number)
+{
+ shumate_vector_value_unset (self);
+ self->type = TYPE_NUMBER;
+ self->number = number;
+}
+
+
+gboolean
+shumate_vector_value_get_number (ShumateVectorValue *self, double *number)
+{
+ if (self->type != TYPE_NUMBER)
+ return FALSE;
+
+ *number = self->number;
+ return TRUE;
+}
+
+
+void
+shumate_vector_value_set_boolean (ShumateVectorValue *self, gboolean boolean)
+{
+ shumate_vector_value_unset (self);
+ self->type = TYPE_BOOLEAN;
+ self->boolean = boolean;
+}
+
+
+gboolean
+shumate_vector_value_get_boolean (ShumateVectorValue *self, gboolean *boolean)
+{
+ if (self->type != TYPE_BOOLEAN)
+ return FALSE;
+
+ *boolean = self->boolean;
+ return TRUE;
+}
+
+
+
+void
+shumate_vector_value_set_string (ShumateVectorValue *self, const char *string)
+{
+ shumate_vector_value_unset (self);
+ self->type = TYPE_STRING;
+ self->string = g_strdup (string);
+ self->color_state = COLOR_UNSET;
+}
+
+
+gboolean
+shumate_vector_value_get_string (ShumateVectorValue *self, const char **string)
+{
+ if (self->type != TYPE_STRING)
+ return FALSE;
+
+ *string = self->string;
+ return TRUE;
+}
+
+
+void
+shumate_vector_value_set_color (ShumateVectorValue *self, GdkRGBA *color)
+{
+ shumate_vector_value_unset (self);
+ self->type = TYPE_COLOR;
+ self->color = *color;
+}
+
+
+gboolean
+shumate_vector_value_get_color (ShumateVectorValue *self, GdkRGBA *color)
+{
+ if (self->type == TYPE_STRING)
+ {
+ if (self->color_state == COLOR_UNSET)
+ {
+ if (gdk_rgba_parse (&self->color, self->string))
+ self->color_state = COLOR_SET;
+ else
+ self->color_state = COLOR_INVALID;
+ }
+
+ if (self->color_state == COLOR_SET)
+ {
+ *color = self->color;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ if (self->type != TYPE_COLOR)
+ return FALSE;
+
+ *color = self->color;
+ return TRUE;
+}
+
+gboolean
+shumate_vector_value_equal (ShumateVectorValue *a, ShumateVectorValue *b)
+{
+ if (a->type != b->type)
+ return FALSE;
+
+ switch (a->type)
+ {
+ case TYPE_NULL:
+ return TRUE;
+ case TYPE_NUMBER:
+ return a->number == b->number;
+ case TYPE_BOOLEAN:
+ return a->boolean == b->boolean;
+ case TYPE_STRING:
+ return g_strcmp0 (a->string, b->string) == 0;
+ case TYPE_COLOR:
+ return gdk_rgba_equal (&a->color, &b->color);
+ default:
+ g_assert_not_reached ();
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index a12e451..20b9dfb 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -14,7 +14,9 @@ tests = [
'marker-layer',
'memory-cache',
'network-tile-source',
+ 'vector-expression',
'vector-style',
+ 'vector-value',
'viewport',
]
@@ -32,6 +34,7 @@ testutils_dep = declare_dependency(
link_with: testutils_lib,
dependencies: libshumate_deps,
sources: test_utils_sources,
+ include_directories: include_directories('../shumate')
)
foreach test : tests
diff --git a/tests/vector-expression.c b/tests/vector-expression.c
new file mode 100644
index 0000000..837881e
--- /dev/null
+++ b/tests/vector-expression.c
@@ -0,0 +1,122 @@
+#include <gtk/gtk.h>
+#include <shumate/shumate.h>
+#include "shumate/vector/shumate-vector-expression-literal-private.h"
+#include "shumate/vector/shumate-vector-expression-interpolate-private.h"
+
+
+static void
+test_vector_expression_parse (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(JsonNode) node1 = json_from_string ("{\"stops\": [[12, 1], [13, 2], [14, 5], [16, 9]]}", NULL);
+ g_autoptr(JsonNode) node2 = json_from_string ("1.0", NULL);
+ g_autoptr(ShumateVectorExpression) expr1 = NULL;
+ g_autoptr(ShumateVectorExpression) expr2 = NULL;
+ g_autoptr(ShumateVectorExpression) expr3 = NULL;
+
+ expr1 = shumate_vector_expression_from_json (node1, &error);
+ g_assert_no_error (error);
+ g_assert_true (SHUMATE_IS_VECTOR_EXPRESSION_INTERPOLATE (expr1));
+
+ expr2 = shumate_vector_expression_from_json (node2, &error);
+ g_assert_no_error (error);
+ g_assert_true (SHUMATE_IS_VECTOR_EXPRESSION_LITERAL (expr2));
+
+ expr3 = shumate_vector_expression_from_json (NULL, &error);
+ g_assert_no_error (error);
+ g_assert_true (SHUMATE_IS_VECTOR_EXPRESSION_LITERAL (expr3));
+}
+
+
+static void
+test_vector_expression_literal (void)
+{
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+ g_autoptr(ShumateVectorExpression) expr = NULL;
+ double result;
+
+ shumate_vector_value_set_number (&value, 3.1415);
+ expr = shumate_vector_expression_literal_new (&value);
+
+ result = shumate_vector_expression_eval_number (expr, NULL, -10);
+ g_assert_cmpfloat (3.1415, ==, result);
+}
+
+
+static void
+test_vector_expression_interpolate (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(JsonNode) node = json_from_string ("{\"stops\": [[12, 1], [13, 2], [14, 5], [16, 9]]}", NULL);
+ g_autoptr(ShumateVectorExpression) expression;
+ ShumateVectorRenderScope scope;
+
+ expression = shumate_vector_expression_from_json (node, &error);
+ g_assert_no_error (error);
+
+ /* Test that exact stop values work */
+ scope.zoom_level = 12;
+ g_assert_cmpfloat (1.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+ scope.zoom_level = 13;
+ g_assert_cmpfloat (2.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+ scope.zoom_level = 14;
+ g_assert_cmpfloat (5.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+ scope.zoom_level = 16;
+ g_assert_cmpfloat (9.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+
+ /* Test that outlier values work */
+ scope.zoom_level = 1;
+ g_assert_cmpfloat (1.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+ scope.zoom_level = 100;
+ g_assert_cmpfloat (9.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+
+ /* Test that in-between values work */
+ scope.zoom_level = 12.5;
+ g_assert_cmpfloat (1.5, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+ scope.zoom_level = 15;
+ g_assert_cmpfloat (7.0, ==, shumate_vector_expression_eval_number (expression, &scope, -10000.0));
+}
+
+
+static void
+test_vector_expression_interpolate_color (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(JsonNode) node = json_from_string ("{\"stops\": [[12, \"#00224466\"], [13, \"#88AACCEE\"]]}",
NULL);
+ g_autoptr(ShumateVectorExpression) expression;
+ ShumateVectorRenderScope scope;
+ GdkRGBA color, correct_color;
+
+ expression = shumate_vector_expression_from_json (node, &error);
+ g_assert_no_error (error);
+
+ /* Test that exact stop values work */
+ scope.zoom_level = 12;
+ shumate_vector_expression_eval_color (expression, &scope, &color);
+ gdk_rgba_parse (&correct_color, "#00224466");
+ g_assert_true (gdk_rgba_equal (&color, &correct_color));
+
+ scope.zoom_level = 12.5;
+ shumate_vector_expression_eval_color (expression, &scope, &color);
+ gdk_rgba_parse (&correct_color, "#446688AA");
+ g_assert_true (gdk_rgba_equal (&color, &correct_color));
+
+ scope.zoom_level = 13;
+ shumate_vector_expression_eval_color (expression, &scope, &color);
+ gdk_rgba_parse (&correct_color, "#88AACCEE");
+ g_assert_true (gdk_rgba_equal (&color, &correct_color));
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/vector/expression/parse", test_vector_expression_parse);
+ g_test_add_func ("/vector/expression/literal", test_vector_expression_literal);
+ g_test_add_func ("/vector/expression/interpolate", test_vector_expression_interpolate);
+ g_test_add_func ("/vector/expression/interpolate-color", test_vector_expression_interpolate_color);
+
+ return g_test_run ();
+}
diff --git a/tests/vector-value.c b/tests/vector-value.c
new file mode 100644
index 0000000..1a5880c
--- /dev/null
+++ b/tests/vector-value.c
@@ -0,0 +1,184 @@
+#include <gtk/gtk.h>
+#include <shumate/shumate.h>
+#include "shumate/vector/shumate-vector-value-private.h"
+
+static void
+test_vector_value_literal (void)
+{
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+ double number;
+ gboolean boolean;
+ const char *string;
+
+ shumate_vector_value_unset (&value);
+
+ shumate_vector_value_set_number (&value, 3.1415);
+ g_assert_true (shumate_vector_value_get_number (&value, &number));
+ g_assert_cmpfloat (3.1415, ==, number);
+
+ shumate_vector_value_set_boolean (&value, TRUE);
+ g_assert_true (shumate_vector_value_get_boolean (&value, &boolean));
+ g_assert_true (boolean);
+
+ shumate_vector_value_set_boolean (&value, FALSE);
+ g_assert_true (shumate_vector_value_get_boolean (&value, &boolean));
+ g_assert_false (boolean);
+
+ shumate_vector_value_set_string (&value, "Hello, world!");
+ g_assert_true (shumate_vector_value_get_string (&value, &string));
+ g_assert_cmpstr ("Hello, world!", ==, string);
+}
+
+
+static void
+test_vector_value_from_gvalue (void)
+{
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+ g_auto(GValue) gvalue = G_VALUE_INIT;
+ double number;
+ gboolean boolean;
+ const char *string;
+
+ shumate_vector_value_unset (&value);
+
+ g_value_init (&gvalue, G_TYPE_DOUBLE);
+ g_value_set_double (&gvalue, 3.1415);
+ g_assert_true (shumate_vector_value_set_from_g_value (&value, &gvalue));
+ g_assert_true (shumate_vector_value_get_number (&value, &number));
+ g_assert_cmpfloat (3.1415, ==, number);
+ g_value_unset (&gvalue);
+
+ g_value_init (&gvalue, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&gvalue, TRUE);
+ g_assert_true (shumate_vector_value_set_from_g_value (&value, &gvalue));
+ g_assert_true (shumate_vector_value_get_boolean (&value, &boolean));
+ g_assert_true (boolean);
+
+ g_value_set_boolean (&gvalue, FALSE);
+ shumate_vector_value_set_from_g_value (&value, &gvalue);
+ g_assert_true (shumate_vector_value_get_boolean (&value, &boolean));
+ g_assert_false (boolean);
+ g_value_unset (&gvalue);
+
+ g_value_init (&gvalue, G_TYPE_STRING);
+ g_value_set_string (&gvalue, "Hello, world!");
+ g_assert_true (shumate_vector_value_set_from_g_value (&value, &gvalue));
+ g_assert_true (shumate_vector_value_get_string (&value, &string));
+ g_assert_cmpstr ("Hello, world!", ==, string);
+ g_value_unset (&gvalue);
+}
+
+static void
+test_vector_value_get_color (void)
+{
+ g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
+ GdkRGBA color, correct_color;
+
+ gdk_rgba_parse (&correct_color, "goldenrod");
+ shumate_vector_value_set_string (&value, "goldenrod");
+
+ g_assert_true (shumate_vector_value_get_color (&value, &color));
+ g_assert_true (gdk_rgba_equal (&color, &correct_color));
+
+ /* Try again to make sure caching works */
+ g_assert_true (shumate_vector_value_get_color (&value, &color));
+ g_assert_true (gdk_rgba_equal (&color, &correct_color));
+
+ shumate_vector_value_set_string (&value, "not a real color");
+ g_assert_false (shumate_vector_value_get_color (&value, &color));
+ /* Try again to make sure caching works */
+ g_assert_false (shumate_vector_value_get_color (&value, &color));
+}
+
+
+static void
+test_vector_value_equal (void)
+{
+ g_auto(ShumateVectorValue) value1 = SHUMATE_VECTOR_VALUE_INIT;
+ g_auto(ShumateVectorValue) value2 = SHUMATE_VECTOR_VALUE_INIT;
+ GdkRGBA color;
+
+ /* Both are initialized to NULL so they should be equal */
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_number (&value1, 1.0);
+ shumate_vector_value_set_number (&value2, 1.0);
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_number (&value1, 1.0);
+ shumate_vector_value_set_number (&value2, 2.0);
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_boolean (&value1, TRUE);
+ shumate_vector_value_set_boolean (&value2, TRUE);
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_number (&value1, FALSE);
+ shumate_vector_value_set_number (&value2, TRUE);
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_string (&value1, "Hello, world!");
+ shumate_vector_value_set_string (&value2, "Hello, world!");
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_string (&value1, "Hello, world!");
+ shumate_vector_value_set_string (&value2, "Goodbye, world!");
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+
+ gdk_rgba_parse (&color, "magenta");
+ shumate_vector_value_set_color (&value1, &color);
+ shumate_vector_value_set_color (&value2, &color);
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_color (&value1, &color);
+ gdk_rgba_parse (&color, "purple");
+ shumate_vector_value_set_color (&value2, &color);
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_string (&value1, "Hello, world!");
+ shumate_vector_value_set_number (&value2, 1.0);
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_number (&value1, TRUE);
+ shumate_vector_value_set_boolean (&value2, 1.0);
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_unset (&value1);
+ shumate_vector_value_set_number (&value2, 0.0);
+ g_assert_false (shumate_vector_value_equal (&value1, &value2));
+}
+
+
+static void
+test_vector_value_copy (void)
+{
+ g_auto(ShumateVectorValue) value1 = SHUMATE_VECTOR_VALUE_INIT;
+ g_auto(ShumateVectorValue) value2 = SHUMATE_VECTOR_VALUE_INIT;
+ GdkRGBA color;
+
+ shumate_vector_value_copy (&value1, &value2);
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ gdk_rgba_parse (&color, "red");
+ shumate_vector_value_set_color (&value1, &color);
+ shumate_vector_value_copy (&value1, &value2);
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+
+ shumate_vector_value_set_string (&value1, "Hello, world!");
+ shumate_vector_value_copy (&value1, &value2);
+ g_assert_true (shumate_vector_value_equal (&value1, &value2));
+}
+
+int
+main (int argc, char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/vector/value/literal", test_vector_value_literal);
+ g_test_add_func ("/vector/value/from-gvalue", test_vector_value_from_gvalue);
+ g_test_add_func ("/vector/value/get-color", test_vector_value_get_color);
+ g_test_add_func ("/vector/value/equal", test_vector_value_equal);
+ g_test_add_func ("/vector/value/copy", test_vector_value_copy);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]