[libshumate] vector: Add symbol layer
- From: Marcus Lundblad <mlundblad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] vector: Add symbol layer
- Date: Thu, 23 Jun 2022 21:16:33 +0000 (UTC)
commit a2b1cc14f682ae5408329bf4cfb56213a0a7249a
Author: James Westman <james jwestman net>
Date: Fri Jan 7 00:38:25 2022 -0600
vector: Add symbol layer
demos/map-style.json | 11 +
shumate/meson.build | 9 +
shumate/shumate-map-layer.c | 101 ++++++-
shumate/shumate-memory-cache.c | 28 +-
shumate/shumate-memory-cache.h | 7 +-
shumate/shumate-tile-private.h | 25 ++
shumate/shumate-tile.c | 26 ++
shumate/shumate-vector-renderer.c | 28 +-
shumate/vector/shumate-vector-expression.c | 8 +-
shumate/vector/shumate-vector-layer.c | 3 +
.../vector/shumate-vector-render-scope-private.h | 9 +
shumate/vector/shumate-vector-render-scope.c | 64 +++++
.../shumate-vector-symbol-container-private.h | 43 +++
shumate/vector/shumate-vector-symbol-container.c | 318 +++++++++++++++++++++
.../vector/shumate-vector-symbol-info-private.h | 60 ++++
shumate/vector/shumate-vector-symbol-info.c | 85 ++++++
.../vector/shumate-vector-symbol-layer-private.h | 31 ++
shumate/vector/shumate-vector-symbol-layer.c | 151 ++++++++++
shumate/vector/shumate-vector-symbol-private.h | 32 +++
shumate/vector/shumate-vector-symbol.c | 177 ++++++++++++
tests/memory-cache.c | 38 +--
21 files changed, 1196 insertions(+), 58 deletions(-)
---
diff --git a/demos/map-style.json b/demos/map-style.json
index 76a09dc..08ef218 100644
--- a/demos/map-style.json
+++ b/demos/map-style.json
@@ -53,6 +53,17 @@
"line-opacity": 0.5,
"line-width": 0.9
}
+ },
+ {
+ "id": "cities",
+ "type": "symbol",
+ "source-layer": "city",
+ "layout": {
+ "text-field": "{name}"
+ },
+ "paint": {
+ "text-color": "#000000"
+ }
}
]
}
diff --git a/shumate/meson.build b/shumate/meson.build
index 7f387fd..c39e64e 100644
--- a/shumate/meson.build
+++ b/shumate/meson.build
@@ -29,6 +29,7 @@ libshumate_public_h = [
libshumate_private_h = [
'shumate-kinetic-scrolling-private.h',
'shumate-marker-private.h',
+ 'shumate-tile-private.h',
'shumate-viewport-private.h',
'vector/shumate-vector-background-layer-private.h',
@@ -41,6 +42,10 @@ libshumate_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-symbol-private.h',
+ 'vector/shumate-vector-symbol-container-private.h',
+ 'vector/shumate-vector-symbol-info-private.h',
+ 'vector/shumate-vector-symbol-layer-private.h',
'vector/shumate-vector-utils-private.h',
'vector/shumate-vector-value-private.h',
'vector/vector_tile.pb-c.h',
@@ -163,6 +168,10 @@ if get_option('vector_renderer')
'vector/shumate-vector-layer.c',
'vector/shumate-vector-line-layer.c',
'vector/shumate-vector-render-scope.c',
+ 'vector/shumate-vector-symbol.c',
+ 'vector/shumate-vector-symbol-container.c',
+ 'vector/shumate-vector-symbol-info.c',
+ 'vector/shumate-vector-symbol-layer.c',
'vector/shumate-vector-utils.c',
'vector/shumate-vector-value.c',
'vector/vector_tile.pb-c.c',
diff --git a/shumate/shumate-map-layer.c b/shumate/shumate-map-layer.c
index 800105d..4b581c7 100644
--- a/shumate/shumate-map-layer.c
+++ b/shumate/shumate-map-layer.c
@@ -19,6 +19,11 @@
#include "shumate-map-layer.h"
#include "shumate-memory-cache.h"
+#include "shumate-tile-private.h"
+
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+# include "vector/shumate-vector-symbol-container-private.h"
+#endif
/**
* ShumateMapLayer:
@@ -43,6 +48,10 @@ struct _ShumateMapLayer
guint recompute_grid_idle_id;
ShumateMemoryCache *memcache;
+
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+ ShumateVectorSymbolContainer *symbols;
+#endif
};
G_DEFINE_TYPE (ShumateMapLayer, shumate_map_layer, SHUMATE_TYPE_LAYER)
@@ -127,6 +136,7 @@ typedef struct {
ShumateMapLayer *self;
ShumateTile *tile;
char *source_id;
+ TileGridPosition pos;
} TileFilledData;
static void
@@ -139,8 +149,31 @@ tile_filled_data_free (TileFilledData *data)
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TileFilledData, tile_filled_data_free);
+
+static void
+add_symbols (ShumateMapLayer *self,
+ ShumateTile *tile,
+ TileGridPosition *pos)
+{
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+ GPtrArray *symbols;
+
+ g_assert (SHUMATE_IS_MAP_LAYER (self));
+ g_assert (SHUMATE_IS_TILE (tile));
+
+ if ((symbols = shumate_tile_get_symbols (tile)))
+ shumate_vector_symbol_container_add_symbols (self->symbols,
+ symbols,
+ pos->x,
+ pos->y,
+ pos->zoom);
+#endif
+}
+
static void
-on_tile_filled (GObject *source_object, GAsyncResult *res, gpointer user_data)
+on_tile_filled (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
g_autoptr(TileFilledData) data = user_data;
g_autoptr(GError) error = NULL;
@@ -152,25 +185,32 @@ on_tile_filled (GObject *source_object, GAsyncResult *res, gpointer user_data)
if (!success)
return;
- shumate_memory_cache_store_texture (data->self->memcache,
- data->tile,
- shumate_tile_get_texture (data->tile),
- data->source_id);
+ add_symbols (data->self, data->tile, &data->pos);
+
+ shumate_memory_cache_store_tile (data->self->memcache,
+ data->tile,
+ data->source_id);
}
static void
-add_tile (ShumateMapLayer *self,
- ShumateTile *tile)
+add_tile (ShumateMapLayer *self,
+ ShumateTile *tile,
+ TileGridPosition *pos)
{
const char *source_id = shumate_map_source_get_id (self->map_source);
- if (!shumate_memory_cache_try_fill_tile (self->memcache, tile, source_id))
+ if (shumate_memory_cache_try_fill_tile (self->memcache, tile, source_id))
+ {
+ add_symbols (self, tile, pos);
+ }
+ else
{
GCancellable *cancellable = g_cancellable_new ();
TileFilledData *data = g_new0 (TileFilledData, 1);
data->self = g_object_ref (self);
data->tile = g_object_ref (tile);
data->source_id = g_strdup (source_id);
+ data->pos = *pos;
shumate_tile_set_texture (tile, NULL);
shumate_map_source_fill_tile_async (self->map_source, tile, cancellable, on_tile_filled, data);
@@ -178,11 +218,13 @@ add_tile (ShumateMapLayer *self,
}
gtk_widget_insert_before (GTK_WIDGET (tile), GTK_WIDGET (self), NULL);
+ g_hash_table_insert (self->tile_children, pos, g_object_ref (tile));
}
static void
-remove_tile (ShumateMapLayer *self,
- ShumateTile *tile)
+remove_tile (ShumateMapLayer *self,
+ ShumateTile *tile,
+ TileGridPosition *pos)
{
GCancellable *cancellable = g_hash_table_lookup (self->tile_fill, tile);
if (cancellable)
@@ -191,6 +233,10 @@ remove_tile (ShumateMapLayer *self,
g_hash_table_remove (self->tile_fill, tile);
}
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+ shumate_vector_symbol_container_remove_symbols (self->symbols, pos->x, pos->y, pos->zoom);
+#endif
+
gtk_widget_unparent (GTK_WIDGET (tile));
}
@@ -251,7 +297,7 @@ recompute_grid (ShumateMapLayer *self)
|| pos->y >= tile_initial_row + required_rows)
&& pos->zoom == zoom_level)
{
- remove_tile (self, tile);
+ remove_tile (self, tile, pos);
g_hash_table_iter_remove (&iter);
}
}
@@ -268,8 +314,7 @@ recompute_grid (ShumateMapLayer *self)
if (!tile)
{
tile = shumate_tile_new_full (positive_mod (x, source_columns), positive_mod (y, source_rows),
tile_size, zoom_level);
- g_hash_table_insert (self->tile_children, g_steal_pointer (&pos), g_object_ref (tile));
- add_tile (self, tile);
+ add_tile (self, tile, g_steal_pointer (&pos));
}
if (shumate_tile_get_state (tile) != SHUMATE_STATE_DONE)
@@ -289,7 +334,7 @@ recompute_grid (ShumateMapLayer *self)
if (pos->zoom != zoom_level)
{
- remove_tile (self, tile);
+ remove_tile (self, tile, pos);
g_hash_table_iter_remove (&iter);
}
}
@@ -444,6 +489,10 @@ shumate_map_layer_constructed (GObject *object)
g_signal_connect_swapped (viewport, "notify::zoom-level", G_CALLBACK (on_view_zoom_level_changed), self);
g_signal_connect_swapped (viewport, "notify::rotation", G_CALLBACK (on_view_rotation_changed), self);
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+ self->symbols = shumate_vector_symbol_container_new (self->map_source, viewport);
+ gtk_widget_set_parent (GTK_WIDGET (self->symbols), GTK_WIDGET (self));
+#endif
}
static void
@@ -484,6 +533,14 @@ shumate_map_layer_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (GTK_WIDGET (tile), &child_allocation, baseline);
}
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+ child_allocation.x = 0;
+ child_allocation.y = 0;
+ child_allocation.width = width;
+ child_allocation.height = height;
+ gtk_widget_size_allocate (GTK_WIDGET (self->symbols), &child_allocation, baseline);
+#endif
+
/* We can't recompute while allocating, so queue an idle callback to run
* the recomputation outside the allocation cycle.
*/
@@ -533,14 +590,28 @@ shumate_map_layer_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
int width = gtk_widget_get_width (GTK_WIDGET (self));
int height = gtk_widget_get_height (GTK_WIDGET (self));
double rotation = shumate_viewport_get_rotation (viewport);
+ GtkWidget *child;
/* Scale and rotate around the center of the view */
+ gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2.0, height / 2.0));
gtk_snapshot_scale (snapshot, extra_zoom, extra_zoom);
gtk_snapshot_rotate (snapshot, rotation * 180 / G_PI);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-width / 2.0, -height / 2.0));
- GTK_WIDGET_CLASS (shumate_map_layer_parent_class)->snapshot (widget, snapshot);
+ for (child = gtk_widget_get_first_child (widget);
+ child != NULL;
+ child = gtk_widget_get_next_sibling (child))
+ {
+ if (SHUMATE_IS_TILE (child))
+ gtk_widget_snapshot_child (widget, child, snapshot);
+ }
+
+ gtk_snapshot_restore (snapshot);
+
+#ifdef SHUMATE_HAS_VECTOR_RENDERER
+ gtk_widget_snapshot_child (widget, GTK_WIDGET (self->symbols), snapshot);
+#endif
}
static void
diff --git a/shumate/shumate-memory-cache.c b/shumate/shumate-memory-cache.c
index af49816..d5b86ef 100644
--- a/shumate/shumate-memory-cache.c
+++ b/shumate/shumate-memory-cache.c
@@ -26,6 +26,7 @@
*/
#include "shumate-memory-cache.h"
+#include "shumate-tile-private.h"
#include <glib.h>
#include <string.h>
@@ -49,6 +50,7 @@ typedef struct
{
char *key;
GdkTexture *texture;
+ GPtrArray *symbols;
} QueueMember;
@@ -145,8 +147,8 @@ shumate_memory_cache_new_full (guint size_limit)
ShumateMemoryCache *cache;
cache = g_object_new (SHUMATE_TYPE_MEMORY_CACHE,
- "size-limit", size_limit,
- NULL);
+ "size-limit", size_limit,
+ NULL);
return cache;
}
@@ -234,7 +236,8 @@ delete_queue_member (QueueMember *member, gpointer user_data)
if (member)
{
g_clear_object (&member->texture);
- g_free (member->key);
+ g_clear_pointer (&member->symbols, g_ptr_array_unref);
+ g_clear_pointer (&member->key, g_free);
g_free (member);
}
}
@@ -259,7 +262,9 @@ shumate_memory_cache_clean (ShumateMemoryCache *memory_cache)
gboolean
-shumate_memory_cache_try_fill_tile (ShumateMemoryCache *self, ShumateTile *tile, const char *source_id)
+shumate_memory_cache_try_fill_tile (ShumateMemoryCache *self,
+ ShumateTile *tile,
+ const char *source_id)
{
ShumateMemoryCache *memory_cache = (ShumateMemoryCache *) self;
ShumateMemoryCachePrivate *priv = shumate_memory_cache_get_instance_private (memory_cache);
@@ -280,17 +285,17 @@ shumate_memory_cache_try_fill_tile (ShumateMemoryCache *self, ShumateTile *tile,
move_queue_member_to_head (priv->queue, link);
- if (!member->texture)
- return FALSE;
-
shumate_tile_set_texture (tile, member->texture);
+ shumate_tile_set_symbols (tile, member->symbols);
shumate_tile_set_fade_in (tile, FALSE);
shumate_tile_set_state (tile, SHUMATE_STATE_DONE);
return TRUE;
}
void
-shumate_memory_cache_store_texture (ShumateMemoryCache *self, ShumateTile *tile, GdkTexture *texture, const
char *source_id)
+shumate_memory_cache_store_tile (ShumateMemoryCache *self,
+ ShumateTile *tile,
+ const char *source_id)
{
ShumateMemoryCachePrivate *priv = shumate_memory_cache_get_instance_private (self);
GList *link;
@@ -309,6 +314,8 @@ shumate_memory_cache_store_texture (ShumateMemoryCache *self, ShumateTile *tile,
else
{
QueueMember *member;
+ GdkTexture *texture;
+ GPtrArray *symbols;
if (priv->queue->length >= priv->size_limit)
{
@@ -319,7 +326,10 @@ shumate_memory_cache_store_texture (ShumateMemoryCache *self, ShumateTile *tile,
member = g_new0 (QueueMember, 1);
member->key = key;
- member->texture = g_object_ref (texture);
+ if ((texture = shumate_tile_get_texture (tile)))
+ member->texture = g_object_ref (texture);
+ if ((symbols = shumate_tile_get_symbols (tile)))
+ member->symbols = g_ptr_array_ref (symbols);
g_queue_push_head (priv->queue, member);
g_hash_table_insert (priv->hash_table, g_strdup (key), g_queue_peek_head_link (priv->queue));
diff --git a/shumate/shumate-memory-cache.h b/shumate/shumate-memory-cache.h
index 835115f..ff14da1 100644
--- a/shumate/shumate-memory-cache.h
+++ b/shumate/shumate-memory-cache.h
@@ -48,10 +48,9 @@ void shumate_memory_cache_clean (ShumateMemoryCache *memory_cache);
gboolean shumate_memory_cache_try_fill_tile (ShumateMemoryCache *self,
ShumateTile *tile,
const char *source_id);
-void shumate_memory_cache_store_texture (ShumateMemoryCache *self,
- ShumateTile *tile,
- GdkTexture *texture,
- const char *source_id);
+void shumate_memory_cache_store_tile (ShumateMemoryCache *self,
+ ShumateTile *tile,
+ const char *source_id);
G_END_DECLS
diff --git a/shumate/shumate-tile-private.h b/shumate/shumate-tile-private.h
new file mode 100644
index 0000000..9253ca4
--- /dev/null
+++ b/shumate/shumate-tile-private.h
@@ -0,0 +1,25 @@
+/*
+ * 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-tile.h"
+
+void shumate_tile_set_symbols (ShumateTile *self,
+ GPtrArray *symbols);
+
+GPtrArray *shumate_tile_get_symbols (ShumateTile *self);
diff --git a/shumate/shumate-tile.c b/shumate/shumate-tile.c
index 4c2a60b..4f8f7e4 100644
--- a/shumate/shumate-tile.c
+++ b/shumate/shumate-tile.c
@@ -46,6 +46,7 @@ typedef struct
gboolean fade_in;
GdkTexture *texture;
+ GPtrArray *symbols;
} ShumateTilePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ShumateTile, shumate_tile, GTK_TYPE_WIDGET);
@@ -204,6 +205,7 @@ shumate_tile_dispose (GObject *object)
ShumateTilePrivate *priv = shumate_tile_get_instance_private (self);
g_clear_object (&priv->texture);
+ g_clear_pointer (&priv->symbols, g_ptr_array_unref);
G_OBJECT_CLASS (shumate_tile_parent_class)->dispose (object);
}
@@ -662,3 +664,27 @@ shumate_tile_set_texture (ShumateTile *self,
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
+
+
+void
+shumate_tile_set_symbols (ShumateTile *self, GPtrArray *symbols)
+{
+ ShumateTilePrivate *priv = shumate_tile_get_instance_private (self);
+
+ g_return_if_fail (SHUMATE_IS_TILE (self));
+
+ g_clear_pointer (&priv->symbols, g_ptr_array_unref);
+ if (symbols != NULL)
+ priv->symbols = g_ptr_array_ref (symbols);
+}
+
+
+GPtrArray *
+shumate_tile_get_symbols (ShumateTile *self)
+{
+ ShumateTilePrivate *priv = shumate_tile_get_instance_private (self);
+
+ g_return_val_if_fail (SHUMATE_IS_TILE (self), NULL);
+
+ return priv->symbols;
+}
diff --git a/shumate/shumate-vector-renderer.c b/shumate/shumate-vector-renderer.c
index 1b9046a..357ee44 100644
--- a/shumate/shumate-vector-renderer.c
+++ b/shumate/shumate-vector-renderer.c
@@ -17,6 +17,7 @@
#include "shumate-vector-renderer.h"
#include "shumate-tile-downloader.h"
+#include "shumate-tile-private.h"
/**
* ShumateVectorRenderer:
@@ -517,20 +518,28 @@ on_data_source_done (GObject *object, GAsyncResult *res, gpointer user_data)
}
}
-static GdkTexture *
-render (ShumateVectorRenderer *self, int texture_size, GBytes *tile_data, double zoom_level)
+static void
+render (ShumateVectorRenderer *self,
+ ShumateTile *tile,
+ GBytes *tile_data,
+ double zoom_level)
{
#ifdef SHUMATE_HAS_VECTOR_RENDERER
ShumateVectorRenderScope scope;
- GdkTexture *texture;
+ g_autoptr(GdkTexture) texture = NULL;
cairo_surface_t *surface;
gconstpointer data;
gsize len;
+ g_autoptr(GPtrArray) symbols = g_ptr_array_new ();
+ int texture_size;
- g_return_val_if_fail (SHUMATE_IS_VECTOR_RENDERER (self), NULL);
+ g_assert (SHUMATE_IS_VECTOR_RENDERER (self));
+ g_assert (SHUMATE_IS_TILE (tile));
+ texture_size = shumate_tile_get_size (tile);
scope.target_size = texture_size;
scope.zoom_level = zoom_level;
+ scope.symbols = symbols;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, texture_size, texture_size);
scope.cr = cairo_create (surface);
@@ -543,14 +552,14 @@ render (ShumateVectorRenderer *self, int texture_size, GBytes *tile_data, double
shumate_vector_layer_render ((ShumateVectorLayer *)self->layers->pdata[i], &scope);
texture = texture_new_for_surface (surface);
+ shumate_tile_set_texture (tile, texture);
+ shumate_tile_set_symbols (tile, symbols);
cairo_destroy (scope.cr);
cairo_surface_destroy (surface);
vector_tile__tile__free_unpacked (scope.tile, NULL);
-
- return texture;
#else
- g_return_val_if_reached (NULL);
+ g_return_if_reached ();
#endif
}
@@ -575,10 +584,7 @@ on_data_source_received_data (ShumateVectorRenderer *self,
if (shumate_tile_get_x (tile) == x
&& shumate_tile_get_y (tile) == y
&& shumate_tile_get_zoom_level (tile) == zoom_level)
- {
- g_autoptr(GdkTexture) texture = render (self, shumate_tile_get_size (tile), bytes, zoom_level);
- shumate_tile_set_texture (tile, texture);
- }
+ render (self, tile, bytes, zoom_level);
}
}
diff --git a/shumate/vector/shumate-vector-expression.c b/shumate/vector/shumate-vector-expression.c
index b31ac54..5f6fe13 100644
--- a/shumate/vector/shumate-vector-expression.c
+++ b/shumate/vector/shumate-vector-expression.c
@@ -90,8 +90,12 @@ 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);
+ g_return_val_if_fail (self == NULL || SHUMATE_IS_VECTOR_EXPRESSION (self), FALSE);
+
+ if (self == NULL)
+ return FALSE;
+ else
+ return SHUMATE_VECTOR_EXPRESSION_GET_CLASS (self)->eval (self, scope, out);
}
diff --git a/shumate/vector/shumate-vector-layer.c b/shumate/vector/shumate-vector-layer.c
index f665e79..bd653dc 100644
--- a/shumate/vector/shumate-vector-layer.c
+++ b/shumate/vector/shumate-vector-layer.c
@@ -21,6 +21,7 @@
#include "shumate-vector-fill-layer-private.h"
#include "shumate-vector-layer-private.h"
#include "shumate-vector-line-layer-private.h"
+#include "shumate-vector-symbol-layer-private.h"
typedef struct
{
@@ -56,6 +57,8 @@ shumate_vector_layer_create_from_json (JsonObject *object, GError **error)
layer = shumate_vector_fill_layer_create_from_json (object, error);
else if (g_strcmp0 (type, "line") == 0)
layer = shumate_vector_line_layer_create_from_json (object, error);
+ else if (g_strcmp0 (type, "symbol") == 0)
+ layer = shumate_vector_symbol_layer_create_from_json (object, error);
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unsupported layer type \"%s\"", type);
diff --git a/shumate/vector/shumate-vector-render-scope-private.h
b/shumate/vector/shumate-vector-render-scope-private.h
index 52242f5..ac728a0 100644
--- a/shumate/vector/shumate-vector-render-scope-private.h
+++ b/shumate/vector/shumate-vector-render-scope-private.h
@@ -28,6 +28,8 @@ typedef struct {
double scale;
double zoom_level;
+ GPtrArray *symbols;
+
VectorTile__Tile *tile;
VectorTile__Tile__Layer *layer;
VectorTile__Tile__Feature *feature;
@@ -36,4 +38,11 @@ typedef struct {
gboolean shumate_vector_render_scope_find_layer (ShumateVectorRenderScope *self, const char *layer_name);
void shumate_vector_render_scope_exec_geometry (ShumateVectorRenderScope *self);
+void shumate_vector_render_scope_get_geometry_center (ShumateVectorRenderScope *self, double *x, double *y);
+void shumate_vector_render_scope_get_bounds (ShumateVectorRenderScope *self,
+ double *min_x,
+ double *min_y,
+ double *max_x,
+ double *max_y);
+
void shumate_vector_render_scope_get_variable (ShumateVectorRenderScope *self, const char *variable,
ShumateVectorValue *value);
diff --git a/shumate/vector/shumate-vector-render-scope.c b/shumate/vector/shumate-vector-render-scope.c
index e544b4e..14e7644 100644
--- a/shumate/vector/shumate-vector-render-scope.c
+++ b/shumate/vector/shumate-vector-render-scope.c
@@ -87,6 +87,70 @@ shumate_vector_render_scope_exec_geometry (ShumateVectorRenderScope *self)
}
+void
+shumate_vector_render_scope_get_bounds (ShumateVectorRenderScope *self,
+ double *min_x,
+ double *min_y,
+ double *max_x,
+ double *max_y)
+{
+ double x = 0, y = 0;
+
+ *min_x = self->layer->extent;
+ *min_y = self->layer->extent;
+ *max_x = 0;
+ *max_y = 0;
+
+ g_return_if_fail (self->feature != NULL);
+
+ for (int i = 0; i < self->feature->n_geometry; i ++)
+ {
+ int cmd = self->feature->geometry[i];
+
+ /* See https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding */
+ int op = cmd & 0x7;
+ int repeat = cmd >> 3;
+
+ for (int j = 0; j < repeat; j ++)
+ {
+ switch (op) {
+ case 1:
+ g_return_if_fail (i + 2 < self->feature->n_geometry);
+ x += zigzag (self->feature->geometry[++i]);
+ y += zigzag (self->feature->geometry[++i]);
+ break;
+ case 2:
+ g_return_if_fail (i + 2 < self->feature->n_geometry);
+ x += zigzag (self->feature->geometry[++i]);
+ y += zigzag (self->feature->geometry[++i]);
+ break;
+ case 7:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ *min_x = MIN (*min_x, x);
+ *min_y = MIN (*min_y, y);
+ *max_x = MAX (*max_x, x);
+ *max_y = MAX (*max_y, y);
+ }
+ }
+}
+
+
+void
+shumate_vector_render_scope_get_geometry_center (ShumateVectorRenderScope *self,
+ double *x,
+ double *y)
+{
+ double min_x, min_y, max_x, max_y;
+ shumate_vector_render_scope_get_bounds (self, &min_x, &min_y, &max_x, &max_y);
+ *x = (min_x + max_x) / 2.0 / self->layer->extent;
+ *y = (min_y + max_y) / 2.0 / self->layer->extent;
+}
+
+
void
shumate_vector_render_scope_get_variable (ShumateVectorRenderScope *self, const char *variable,
ShumateVectorValue *value)
{
diff --git a/shumate/vector/shumate-vector-symbol-container-private.h
b/shumate/vector/shumate-vector-symbol-container-private.h
new file mode 100644
index 0000000..33f752e
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-container-private.h
@@ -0,0 +1,43 @@
+/*
+ * 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-map-source.h"
+#include "shumate-layer.h"
+
+G_BEGIN_DECLS
+
+
+#define SHUMATE_TYPE_VECTOR_SYMBOL_CONTAINER (shumate_vector_symbol_container_get_type())
+G_DECLARE_FINAL_TYPE (ShumateVectorSymbolContainer, shumate_vector_symbol_container, SHUMATE,
VECTOR_SYMBOL_CONTAINER, ShumateLayer)
+
+ShumateVectorSymbolContainer *shumate_vector_symbol_container_new (ShumateMapSource *map_source,
+ ShumateViewport *viewport);
+
+void shumate_vector_symbol_container_add_symbols (ShumateVectorSymbolContainer *self,
+ GPtrArray *symbol_infos,
+ int tile_x,
+ int tile_y,
+ int zoom);
+
+void shumate_vector_symbol_container_remove_symbols (ShumateVectorSymbolContainer *self,
+ int tile_x,
+ int tile_y,
+ int zoom);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-symbol-container.c
b/shumate/vector/shumate-vector-symbol-container.c
new file mode 100644
index 0000000..2616c97
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-container.c
@@ -0,0 +1,318 @@
+/*
+ * 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-symbol-container-private.h"
+#include "shumate-vector-symbol-private.h"
+
+
+struct _ShumateVectorSymbolContainer
+{
+ ShumateLayer parent_instance;
+
+ ShumateMapSource *map_source;
+
+ GList *children;
+};
+
+G_DEFINE_TYPE (ShumateVectorSymbolContainer, shumate_vector_symbol_container, SHUMATE_TYPE_LAYER)
+
+enum {
+ PROP_0,
+ PROP_MAP_SOURCE,
+ N_PROPS,
+};
+
+static GParamSpec *obj_properties[N_PROPS] = { NULL, };
+
+
+typedef struct {
+ // does not need to be freed because it's owned by the widget
+ ShumateVectorSymbol *symbol;
+
+ // These are coordinates [0, 1) within the tile
+ float x;
+ float y;
+
+ // We assume these don't change so we don't have to measure them again
+ // every time. We can do this because children are all created internally
+ int width;
+ int height;
+
+ int tile_x;
+ int tile_y;
+ int zoom;
+} ChildInfo;
+
+
+ShumateVectorSymbolContainer *
+shumate_vector_symbol_container_new (ShumateMapSource *map_source,
+ ShumateViewport *viewport)
+{
+ return g_object_new (SHUMATE_TYPE_VECTOR_SYMBOL_CONTAINER,
+ "map-source", map_source,
+ "viewport", viewport,
+ NULL);
+}
+
+
+static void
+on_viewport_changed (ShumateVectorSymbolContainer *self,
+ G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED ShumateViewport *view)
+{
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+}
+
+
+static void
+shumate_vector_symbol_container_constructed (GObject *object)
+{
+ ShumateVectorSymbolContainer *self = (ShumateVectorSymbolContainer *)object;
+ ShumateViewport *viewport;
+
+ G_OBJECT_CLASS (shumate_vector_symbol_container_parent_class)->constructed (object);
+
+ viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
+
+ g_signal_connect_swapped (viewport, "notify::longitude", G_CALLBACK (on_viewport_changed), self);
+ g_signal_connect_swapped (viewport, "notify::latitude", G_CALLBACK (on_viewport_changed), self);
+ g_signal_connect_swapped (viewport, "notify::zoom-level", G_CALLBACK (on_viewport_changed), self);
+ g_signal_connect_swapped (viewport, "notify::rotation", G_CALLBACK (on_viewport_changed), self);
+}
+
+
+static void
+shumate_vector_symbol_container_finalize (GObject *object)
+{
+ ShumateVectorSymbolContainer *self = (ShumateVectorSymbolContainer *)object;
+
+ g_list_free_full (self->children, (GDestroyNotify) g_free);
+
+ G_OBJECT_CLASS (shumate_vector_symbol_container_parent_class)->finalize (object);
+}
+
+
+static void
+shumate_vector_symbol_container_dispose (GObject *object)
+{
+ ShumateVectorSymbolContainer *self = (ShumateVectorSymbolContainer *)object;
+ ShumateViewport *viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
+ GtkWidget *child;
+
+ g_signal_handlers_disconnect_by_data (viewport, self);
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))))
+ gtk_widget_unparent (child);
+
+ G_OBJECT_CLASS (shumate_vector_symbol_container_parent_class)->dispose (object);
+}
+
+
+static void
+shumate_vector_symbol_container_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ShumateVectorSymbolContainer *self = (ShumateVectorSymbolContainer *)object;
+
+ switch (property_id)
+ {
+ case PROP_MAP_SOURCE:
+ g_value_set_object (value, self->map_source);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+shumate_vector_symbol_container_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ShumateVectorSymbolContainer *self = SHUMATE_VECTOR_SYMBOL_CONTAINER (object);
+
+ switch (property_id)
+ {
+ case PROP_MAP_SOURCE:
+ g_set_object (&self->map_source, g_value_get_object (value));
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+rotate_around_center (float *x,
+ float *y,
+ float width,
+ float height,
+ float angle)
+{
+ /* Rotate (x, y) around (width / 2, height / 2) */
+
+ float old_x = *x;
+ float old_y = *y;
+ float center_x = width / 2.0;
+ float center_y = height / 2.0;
+
+ *x = cosf (angle) * (old_x - center_x) - sinf (angle) * (old_y - center_y) + center_x;
+ *y = sinf (angle) * (old_x - center_x) + cosf (angle) * (old_y - center_y) + center_y;
+}
+
+
+static void
+shumate_vector_symbol_container_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ ShumateVectorSymbolContainer *self = SHUMATE_VECTOR_SYMBOL_CONTAINER (widget);
+ GtkAllocation alloc;
+ float tile_size = shumate_map_source_get_tile_size (self->map_source);
+ ShumateViewport *viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
+ float zoom_level = shumate_viewport_get_zoom_level (viewport);
+ float rotation = shumate_viewport_get_rotation (viewport);
+ float center_x = shumate_map_source_get_x (self->map_source, zoom_level, shumate_location_get_longitude
(SHUMATE_LOCATION (viewport)));
+ float center_y = shumate_map_source_get_y (self->map_source, zoom_level, shumate_location_get_latitude
(SHUMATE_LOCATION (viewport)));
+
+ for (GList *l = self->children; l != NULL; l = l->next)
+ {
+ ChildInfo *child = l->data;
+ float tile_size_at_zoom = tile_size * powf (2, zoom_level - child->zoom);
+ float x = (child->tile_x + child->x) * tile_size_at_zoom - center_x + width/2.0;
+ float y = (child->tile_y + child->y) * tile_size_at_zoom - center_y + height/2.0;
+
+ rotate_around_center (&x, &y, width, height, rotation);
+ alloc.x = x - child->width/2.0;
+ alloc.y = y - child->height/2.0;
+
+ alloc.width = child->width;
+ alloc.height = child->height;
+
+ gtk_widget_size_allocate (GTK_WIDGET (child->symbol), &alloc, -1);
+ }
+}
+
+
+static void
+shumate_vector_symbol_container_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ ShumateVectorSymbolContainer *self = SHUMATE_VECTOR_SYMBOL_CONTAINER (widget);
+
+ for (GList *l = self->children; l != NULL; l = l->next)
+ {
+ ChildInfo *child = (ChildInfo *)l->data;
+
+ gtk_snapshot_save (snapshot);
+
+ gtk_widget_snapshot_child (widget, GTK_WIDGET (child->symbol), snapshot);
+ gtk_snapshot_restore (snapshot);
+ }
+
+}
+
+
+static void
+shumate_vector_symbol_container_class_init (ShumateVectorSymbolContainerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->constructed = shumate_vector_symbol_container_constructed;
+ object_class->dispose = shumate_vector_symbol_container_dispose;
+ object_class->finalize = shumate_vector_symbol_container_finalize;
+ object_class->get_property = shumate_vector_symbol_container_get_property;
+ object_class->set_property = shumate_vector_symbol_container_set_property;
+ widget_class->size_allocate = shumate_vector_symbol_container_size_allocate;
+ widget_class->snapshot = shumate_vector_symbol_container_snapshot;
+
+ obj_properties[PROP_MAP_SOURCE] =
+ g_param_spec_object ("map-source",
+ "Map source",
+ "Map source",
+ SHUMATE_TYPE_MAP_SOURCE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, N_PROPS, obj_properties);
+}
+
+static void
+shumate_vector_symbol_container_init (ShumateVectorSymbolContainer *self)
+{
+}
+
+
+void
+shumate_vector_symbol_container_add_symbols (ShumateVectorSymbolContainer *self,
+ GPtrArray *symbol_infos,
+ int tile_x,
+ int tile_y,
+ int zoom)
+{
+ g_return_if_fail (SHUMATE_IS_VECTOR_SYMBOL_CONTAINER (self));
+
+ for (int i = 0; i < symbol_infos->len; i ++)
+ {
+ ChildInfo *info = g_new0 (ChildInfo, 1);
+ ShumateVectorSymbolInfo *symbol_info = symbol_infos->pdata[i];
+ ShumateVectorSymbol *symbol = shumate_vector_symbol_new (symbol_info);
+
+ info->symbol = symbol;
+ gtk_widget_measure (GTK_WIDGET (symbol), GTK_ORIENTATION_HORIZONTAL, -1, NULL, &info->width, NULL,
NULL);
+ gtk_widget_measure (GTK_WIDGET (symbol), GTK_ORIENTATION_VERTICAL, -1, NULL, &info->height, NULL,
NULL);
+ info->x = symbol_info->x;
+ info->y = symbol_info->y;
+ info->tile_x = tile_x;
+ info->tile_y = tile_y;
+ info->zoom = zoom;
+
+ self->children = g_list_prepend (self->children, info);
+ gtk_widget_set_parent (GTK_WIDGET (info->symbol), GTK_WIDGET (self));
+ }
+}
+
+
+void
+shumate_vector_symbol_container_remove_symbols (ShumateVectorSymbolContainer *self,
+ int tile_x,
+ int tile_y,
+ int zoom)
+{
+ g_return_if_fail (SHUMATE_IS_VECTOR_SYMBOL_CONTAINER (self));
+
+ for (GList *l = self->children; l != NULL; l = l->next)
+ {
+ ChildInfo *info = l->data;
+
+ if (info->tile_x != tile_x || info->tile_y != tile_y || info->zoom != zoom)
+ continue;
+
+ gtk_widget_unparent (GTK_WIDGET (info->symbol));
+ g_clear_pointer (&l->data, g_free);
+ }
+
+ self->children = g_list_remove_all (self->children, NULL);
+}
diff --git a/shumate/vector/shumate-vector-symbol-info-private.h
b/shumate/vector/shumate-vector-symbol-info-private.h
new file mode 100644
index 0000000..3552f8f
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-info-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 <glib-object.h>
+#include "shumate-vector-render-scope-private.h"
+
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_SYMBOL_INFO (shumate_vector_symbol_info_get_type ())
+
+typedef struct _ShumateVectorSymbolInfo ShumateVectorSymbolInfo;
+
+struct _ShumateVectorSymbolInfo
+{
+ char *text;
+ GdkRGBA text_color;
+ double text_size;
+ char *text_font;
+ gboolean line_placement;
+ double x;
+ double y;
+
+ /*< private >*/
+ guint ref_count;
+};
+
+ShumateVectorSymbolInfo *shumate_vector_symbol_info_new (const char *text,
+ const GdkRGBA *text_color,
+ double text_size,
+ const char *text_font,
+ gboolean line_placement,
+ double x,
+ double y);
+
+GType shumate_vector_symbol_info_get_type (void) G_GNUC_CONST;
+ShumateVectorSymbolInfo *shumate_vector_symbol_info_ref (ShumateVectorSymbolInfo *self);
+void shumate_vector_symbol_info_unref (ShumateVectorSymbolInfo *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (ShumateVectorSymbolInfo, shumate_vector_symbol_info_unref)
+
+G_END_DECLS
+
diff --git a/shumate/vector/shumate-vector-symbol-info.c b/shumate/vector/shumate-vector-symbol-info.c
new file mode 100644
index 0000000..de8a605
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-info.c
@@ -0,0 +1,85 @@
+/*
+ * 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-symbol-info-private.h"
+
+
+G_DEFINE_BOXED_TYPE (ShumateVectorSymbolInfo, shumate_vector_symbol_info, shumate_vector_symbol_info_ref,
shumate_vector_symbol_info_unref)
+
+
+static void
+shumate_vector_symbol_info_free (ShumateVectorSymbolInfo *self)
+{
+ g_assert (self);
+ g_assert_cmpint (self->ref_count, ==, 0);
+
+ g_clear_pointer (&self->text, g_free);
+ g_clear_pointer (&self->text_font, g_free);
+
+ g_free (self);
+}
+
+ShumateVectorSymbolInfo *
+shumate_vector_symbol_info_ref (ShumateVectorSymbolInfo *self)
+{
+ g_return_val_if_fail (self, NULL);
+ g_return_val_if_fail (self->ref_count, NULL);
+
+ g_atomic_int_inc (&self->ref_count);
+
+ return self;
+}
+
+void
+shumate_vector_symbol_info_unref (ShumateVectorSymbolInfo *self)
+{
+ g_return_if_fail (self);
+ g_return_if_fail (self->ref_count);
+
+ if (g_atomic_int_dec_and_test (&self->ref_count))
+ shumate_vector_symbol_info_free (self);
+}
+
+
+ShumateVectorSymbolInfo *
+shumate_vector_symbol_info_new (const char *text,
+ const GdkRGBA *text_color,
+ double text_size,
+ const char *text_font,
+ gboolean line_placement,
+ double x,
+ double y)
+{
+ ShumateVectorSymbolInfo *self;
+
+ self = g_new0 (ShumateVectorSymbolInfo, 1);
+
+ *self = (ShumateVectorSymbolInfo) {
+ .ref_count = 1,
+ .text = g_strdup (text),
+ .text_color = *text_color,
+ .text_size = text_size,
+ .text_font = g_strdup (text_font),
+ .line_placement = line_placement,
+ .x = x,
+ .y = y,
+ };
+
+ return self;
+}
+
diff --git a/shumate/vector/shumate-vector-symbol-layer-private.h
b/shumate/vector/shumate-vector-symbol-layer-private.h
new file mode 100644
index 0000000..34e1953
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-layer-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-layer-private.h"
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_SYMBOL_LAYER (shumate_vector_symbol_layer_get_type())
+G_DECLARE_FINAL_TYPE (ShumateVectorSymbolLayer, shumate_vector_symbol_layer, SHUMATE, VECTOR_SYMBOL_LAYER,
ShumateVectorLayer)
+
+ShumateVectorLayer *shumate_vector_symbol_layer_create_from_json (JsonObject *object, GError **error);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-symbol-layer.c b/shumate/vector/shumate-vector-symbol-layer.c
new file mode 100644
index 0000000..d57589d
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-layer.c
@@ -0,0 +1,151 @@
+/*
+ * 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 <gtk/gtk.h>
+#include "shumate-vector-symbol-info-private.h"
+#include "shumate-vector-symbol-layer-private.h"
+#include "shumate-vector-expression-private.h"
+#include "shumate-vector-utils-private.h"
+
+struct _ShumateVectorSymbolLayer
+{
+ ShumateVectorLayer parent_instance;
+
+ ShumateVectorExpression *text_field;
+ ShumateVectorExpression *text_color;
+ ShumateVectorExpression *text_size;
+ gboolean line_placement;
+ char *text_fonts;
+};
+
+G_DEFINE_TYPE (ShumateVectorSymbolLayer, shumate_vector_symbol_layer, SHUMATE_TYPE_VECTOR_LAYER)
+
+
+ShumateVectorLayer *
+shumate_vector_symbol_layer_create_from_json (JsonObject *object, GError **error)
+{
+ ShumateVectorSymbolLayer *layer = g_object_new (SHUMATE_TYPE_VECTOR_SYMBOL_LAYER, NULL);
+
+ if (json_object_has_member (object, "paint"))
+ {
+ JsonObject *paint = json_object_get_object_member (object, "paint");
+
+ layer->text_color = shumate_vector_expression_from_json (json_object_get_member (paint, "text-color"),
error);
+ if (layer->text_color == NULL)
+ return NULL;
+ }
+
+ if (json_object_has_member (object, "layout"))
+ {
+ JsonObject *layout = json_object_get_object_member (object, "layout");
+ JsonNode *text_font_node;
+ JsonArray *text_font;
+
+ layer->text_field = shumate_vector_expression_from_json (json_object_get_member (layout,
"text-field"), error);
+ if (layer->text_field == NULL)
+ return NULL;
+
+ text_font_node = json_object_get_member (layout, "text-font");
+ if (text_font_node != NULL)
+ {
+ g_autoptr(GStrvBuilder) builder = g_strv_builder_new ();
+ g_auto(GStrv) fonts = NULL;
+
+ if (!shumate_vector_json_get_array (text_font_node, &text_font, error))
+ return NULL;
+
+ for (int i = 0, n = json_array_get_length (text_font); i < n; i ++)
+ g_strv_builder_add (builder, json_array_get_string_element (text_font, i));
+
+ fonts = g_strv_builder_end (builder);
+ layer->text_fonts = g_strjoinv (", ", fonts);
+ }
+
+ layer->line_placement = g_strcmp0 (json_object_get_string_member_with_default (layout,
"symbol-placement", NULL), "line") == 0;
+
+ layer->text_size = shumate_vector_expression_from_json (json_object_get_member (layout, "text-size"),
error);
+ if (layer->text_size == NULL)
+ return NULL;
+ }
+
+ return (ShumateVectorLayer *)layer;
+}
+
+
+static void
+shumate_vector_symbol_layer_finalize (GObject *object)
+{
+ ShumateVectorSymbolLayer *self = SHUMATE_VECTOR_SYMBOL_LAYER (object);
+
+ g_clear_object (&self->text_field);
+ g_clear_object (&self->text_color);
+ g_clear_object (&self->text_size);
+ g_clear_pointer (&self->text_fonts, g_free);
+
+ G_OBJECT_CLASS (shumate_vector_symbol_layer_parent_class)->finalize (object);
+}
+
+
+static void
+shumate_vector_symbol_layer_render (ShumateVectorLayer *layer, ShumateVectorRenderScope *scope)
+{
+ ShumateVectorSymbolLayer *self = SHUMATE_VECTOR_SYMBOL_LAYER (layer);
+ g_autofree char *text_field = NULL;
+ GdkRGBA text_color = SHUMATE_VECTOR_COLOR_BLACK;
+ double text_size;
+ ShumateVectorSymbolInfo *symbol_info;
+ double x, y;
+
+ shumate_vector_render_scope_get_geometry_center (scope, &x, &y);
+ if (x < 0 || x >= 1 || y < 0 || y >= 1)
+ /* Tiles usually include a bit of margin. Don't include symbols that are
+ * covered by a different tile. */
+ return;
+
+ shumate_vector_expression_eval_color (self->text_color, scope, &text_color);
+ text_size = shumate_vector_expression_eval_number (self->text_size, scope, 16.0);
+ text_field = shumate_vector_expression_eval_string (self->text_field, scope, "");
+
+ if (strlen (text_field) == 0)
+ return;
+
+ symbol_info = shumate_vector_symbol_info_new (text_field,
+ &text_color,
+ text_size,
+ self->text_fonts,
+ self->line_placement,
+ x,
+ y);
+ g_ptr_array_add (scope->symbols, symbol_info);
+}
+
+
+static void
+shumate_vector_symbol_layer_class_init (ShumateVectorSymbolLayerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ShumateVectorLayerClass *layer_class = SHUMATE_VECTOR_LAYER_CLASS (klass);
+
+ object_class->finalize = shumate_vector_symbol_layer_finalize;
+ layer_class->render = shumate_vector_symbol_layer_render;
+}
+
+
+static void
+shumate_vector_symbol_layer_init (ShumateVectorSymbolLayer *self)
+{
+}
diff --git a/shumate/vector/shumate-vector-symbol-private.h b/shumate/vector/shumate-vector-symbol-private.h
new file mode 100644
index 0000000..3494595
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol-private.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <gtk/gtk.h>
+#include "shumate-vector-symbol-info-private.h"
+
+G_BEGIN_DECLS
+
+#define SHUMATE_TYPE_VECTOR_SYMBOL (shumate_vector_symbol_get_type())
+G_DECLARE_FINAL_TYPE (ShumateVectorSymbol, shumate_vector_symbol, SHUMATE, VECTOR_SYMBOL, GtkWidget)
+
+ShumateVectorSymbol *shumate_vector_symbol_new (ShumateVectorSymbolInfo *symbol_info);
+
+ShumateVectorSymbolInfo *shumate_vector_symbol_get_symbol_info (ShumateVectorSymbol *self);
+
+G_END_DECLS
diff --git a/shumate/vector/shumate-vector-symbol.c b/shumate/vector/shumate-vector-symbol.c
new file mode 100644
index 0000000..ed65242
--- /dev/null
+++ b/shumate/vector/shumate-vector-symbol.c
@@ -0,0 +1,177 @@
+/*
+ * 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-symbol-private.h"
+#include "shumate-vector-utils-private.h"
+#include "shumate-vector-symbol-info-private.h"
+
+
+struct _ShumateVectorSymbol
+{
+ GtkWidget parent_instance;
+
+ ShumateVectorSymbolInfo *symbol_info;
+};
+
+G_DEFINE_TYPE (ShumateVectorSymbol, shumate_vector_symbol, GTK_TYPE_WIDGET)
+
+
+enum {
+ PROP_0,
+ PROP_SYMBOL_INFO,
+ N_PROPS,
+};
+
+static GParamSpec *obj_properties[N_PROPS] = { NULL, };
+
+
+ShumateVectorSymbol *
+shumate_vector_symbol_new (ShumateVectorSymbolInfo *symbol_info)
+{
+ return g_object_new (SHUMATE_TYPE_VECTOR_SYMBOL,
+ "symbol-info", symbol_info,
+ NULL);
+}
+
+
+static void
+shumate_vector_symbol_constructed (GObject *object)
+{
+ ShumateVectorSymbol *self = (ShumateVectorSymbol *)object;
+ g_autoptr(PangoAttrList) attrs = pango_attr_list_new ();
+ PangoAttribute *attr;
+
+ if (self->symbol_info->text_font != NULL)
+ {
+ g_autoptr(PangoFontDescription) desc = pango_font_description_from_string
(self->symbol_info->text_font);
+ attr = pango_attr_font_desc_new (desc);
+ pango_attr_list_insert (attrs, attr);
+ }
+
+ attr = pango_attr_foreground_new (self->symbol_info->text_color.red * 65535,
+ self->symbol_info->text_color.green * 65535,
+ self->symbol_info->text_color.blue * 65535);
+ pango_attr_list_insert (attrs, attr);
+
+ attr = pango_attr_foreground_alpha_new (self->symbol_info->text_color.alpha * 65535);
+ pango_attr_list_insert (attrs, attr);
+
+ attr = pango_attr_size_new_absolute (self->symbol_info->text_size * PANGO_SCALE);
+ pango_attr_list_insert (attrs, attr);
+
+ GtkWidget *label = gtk_label_new (self->symbol_info->text);
+ gtk_label_set_attributes (GTK_LABEL (label), attrs);
+ gtk_widget_set_parent (label, GTK_WIDGET (self));
+
+ G_OBJECT_CLASS (shumate_vector_symbol_parent_class)->constructed (object);
+}
+
+
+static void
+shumate_vector_symbol_dispose (GObject *object)
+{
+ ShumateVectorSymbol *self = (ShumateVectorSymbol *)object;
+ GtkWidget *child;
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))))
+ gtk_widget_unparent (child);
+
+ g_clear_pointer (&self->symbol_info, shumate_vector_symbol_info_unref);
+
+ G_OBJECT_CLASS (shumate_vector_symbol_parent_class)->dispose (object);
+}
+
+
+static void
+shumate_vector_symbol_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ShumateVectorSymbol *self = (ShumateVectorSymbol *)object;
+
+ switch (property_id)
+ {
+ case PROP_SYMBOL_INFO:
+ g_value_set_boxed (value, self->symbol_info);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+shumate_vector_symbol_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ShumateVectorSymbol *self = SHUMATE_VECTOR_SYMBOL (object);
+
+ switch (property_id)
+ {
+ case PROP_SYMBOL_INFO:
+ g_assert (self->symbol_info == NULL);
+ self->symbol_info = g_value_dup_boxed (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+shumate_vector_symbol_class_init (ShumateVectorSymbolClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->constructed = shumate_vector_symbol_constructed;
+ object_class->dispose = shumate_vector_symbol_dispose;
+ object_class->get_property = shumate_vector_symbol_get_property;
+ object_class->set_property = shumate_vector_symbol_set_property;
+
+ obj_properties[PROP_SYMBOL_INFO] =
+ g_param_spec_boxed ("symbol-info",
+ "Symbol info",
+ "Symbol info",
+ SHUMATE_TYPE_VECTOR_SYMBOL_INFO,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, N_PROPS, obj_properties);
+
+ gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+}
+
+
+static void
+shumate_vector_symbol_init (ShumateVectorSymbol *self)
+{
+}
+
+
+ShumateVectorSymbolInfo *
+shumate_vector_symbol_get_symbol_info (ShumateVectorSymbol *self)
+{
+ g_return_val_if_fail (SHUMATE_IS_VECTOR_SYMBOL (self), NULL);
+
+ return self->symbol_info;
+}
diff --git a/tests/memory-cache.c b/tests/memory-cache.c
index 95670a7..bb885ca 100644
--- a/tests/memory-cache.c
+++ b/tests/memory-cache.c
@@ -20,7 +20,8 @@ test_memory_cache_store_retrieve ()
g_object_ref_sink (tile);
/* Store the tile */
- shumate_memory_cache_store_texture (cache, tile, texture, "A");
+ shumate_tile_set_texture (tile, texture);
+ shumate_memory_cache_store_tile (cache, tile, "A");
/* Now retrieve it */
g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile, "A"));
@@ -41,7 +42,8 @@ test_memory_cache_miss ()
g_object_ref_sink (tile2);
/* Store a tile */
- shumate_memory_cache_store_texture (cache, tile1, texture, "A");
+ shumate_tile_set_texture (tile1, texture);
+ shumate_memory_cache_store_tile (cache, tile1, "A");
/* Now retrieve a different one */
g_assert_false (shumate_memory_cache_try_fill_tile (cache, tile2, "A"));
@@ -54,22 +56,26 @@ static void
test_memory_cache_source_id ()
{
g_autoptr(ShumateMemoryCache) cache = shumate_memory_cache_new_full (100);
- g_autoptr(ShumateTile) tile = shumate_tile_new_full (0, 0, 256, 0);
+ g_autoptr(ShumateTile) tile1 = shumate_tile_new_full (0, 0, 256, 0);
+ g_autoptr(ShumateTile) tile2 = shumate_tile_new_full (0, 0, 256, 0);
g_autoptr(GdkTexture) texture1 = create_texture ();
g_autoptr(GdkTexture) texture2 = create_texture ();
- g_object_ref_sink (tile);
+ g_object_ref_sink (tile1);
+ g_object_ref_sink (tile2);
/* Store the tiles */
- shumate_memory_cache_store_texture (cache, tile, texture1, "A");
- shumate_memory_cache_store_texture (cache, tile, texture2, "B");
+ shumate_tile_set_texture (tile1, texture1);
+ shumate_tile_set_texture (tile2, texture2);
+ shumate_memory_cache_store_tile (cache, tile1, "A");
+ shumate_memory_cache_store_tile (cache, tile2, "B");
/* Now retrieve them */
- g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile, "A"));
- g_assert_true (texture1 == shumate_tile_get_texture (tile));
+ g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile1, "A"));
+ g_assert_true (texture1 == shumate_tile_get_texture (tile1));
- g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile, "B"));
- g_assert_true (texture2 == shumate_tile_get_texture (tile));
+ g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile2, "B"));
+ g_assert_true (texture2 == shumate_tile_get_texture (tile2));
}
@@ -79,14 +85,13 @@ test_memory_cache_purge ()
{
g_autoptr(ShumateMemoryCache) cache = shumate_memory_cache_new_full (3);
g_autoptr(ShumateTile) tile = shumate_tile_new_full (0, 0, 256, 0);
- g_autoptr(GdkTexture) texture = create_texture ();
g_object_ref_sink (tile);
/* Store a few tiles */
- shumate_memory_cache_store_texture (cache, tile, texture, "A");
- shumate_memory_cache_store_texture (cache, tile, texture, "B");
- shumate_memory_cache_store_texture (cache, tile, texture, "C");
+ shumate_memory_cache_store_tile (cache, tile, "A");
+ shumate_memory_cache_store_tile (cache, tile, "B");
+ shumate_memory_cache_store_tile (cache, tile, "C");
/* Make sure they're all still cached */
g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile, "B"));
@@ -94,7 +99,7 @@ test_memory_cache_purge ()
g_assert_true (shumate_memory_cache_try_fill_tile (cache, tile, "C"));
/* Store another one */
- shumate_memory_cache_store_texture (cache, tile, texture, "D");
+ shumate_memory_cache_store_tile (cache, tile, "D");
/* Since B was the least recently accessed, it should be the one that was
* dropped */
@@ -111,12 +116,11 @@ test_memory_cache_clean ()
{
g_autoptr(ShumateMemoryCache) cache = shumate_memory_cache_new_full (100);
g_autoptr(ShumateTile) tile = shumate_tile_new_full (0, 0, 256, 0);
- g_autoptr(GdkTexture) texture = create_texture ();
g_object_ref_sink (tile);
/* Store a tile */
- shumate_memory_cache_store_texture (cache, tile, texture, "A");
+ shumate_memory_cache_store_tile (cache, tile, "A");
/* Clean the cache */
shumate_memory_cache_clean (cache);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]