[libshumate] vector: Calculate rectangle intersection differently
- From: Marcus Lundblad <mlundblad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] vector: Calculate rectangle intersection differently
- Date: Thu, 23 Jun 2022 21:16:33 +0000 (UTC)
commit 68a8a2cf9faa790a0c1d68ee7723f816b934f91d
Author: James Westman <james jwestman net>
Date: Wed Mar 30 00:46:44 2022 -0500
vector: Calculate rectangle intersection differently
Use the Separating Axis Theorem to calculate rectangle intersection so
we can handle rotated bounding boxes correctly.
shumate/vector/shumate-vector-collision-private.h | 22 +-
shumate/vector/shumate-vector-collision.c | 285 ++++++++++++---------
shumate/vector/shumate-vector-render-scope.c | 9 +-
shumate/vector/shumate-vector-symbol-container.c | 21 +-
.../vector/shumate-vector-symbol-info-private.h | 1 +
shumate/vector/shumate-vector-symbol-info.c | 4 +
shumate/vector/shumate-vector-symbol-layer.c | 3 +
shumate/vector/shumate-vector-symbol.c | 6 +
shumate/vector/shumate-vector-utils-private.h | 4 +-
shumate/vector/shumate-vector-utils.c | 28 ++
tests/vector-collision.c | 35 ++-
11 files changed, 262 insertions(+), 156 deletions(-)
---
diff --git a/shumate/vector/shumate-vector-collision-private.h
b/shumate/vector/shumate-vector-collision-private.h
index 4a3437f..33da298 100644
--- a/shumate/vector/shumate-vector-collision-private.h
+++ b/shumate/vector/shumate-vector-collision-private.h
@@ -26,21 +26,22 @@ G_BEGIN_DECLS
typedef struct ShumateVectorCollision ShumateVectorCollision;
typedef struct {
- float left;
- float right;
- float top;
- float bottom;
-} ShumateVectorCollisionRect;
+ float x;
+ float y;
+ float xextent;
+ float yextent;
+ float rotation;
+} ShumateVectorCollisionBBox;
typedef struct {
- ShumateVectorCollisionRect rect;
- ShumateVectorPoint center;
+ ShumateVectorCollisionBBox bbox;
GList *list_link;
float x;
float y;
int zoom;
guint seq : 1;
guint visible : 1;
+ guint rotates : 1;
} ShumateVectorCollisionMarker;
ShumateVectorCollision *shumate_vector_collision_new ();
@@ -50,10 +51,9 @@ ShumateVectorCollisionMarker *shumate_vector_collision_insert (ShumateVectorColl
int zoom,
float x,
float y,
- float left,
- float right,
- float top,
- float bottom);
+ float xextent,
+ float yextent,
+ guint rotates);
void shumate_vector_collision_remove (ShumateVectorCollision *self,
ShumateVectorCollisionMarker *marker);
diff --git a/shumate/vector/shumate-vector-collision.c b/shumate/vector/shumate-vector-collision.c
index 4899b6b..4682a83 100644
--- a/shumate/vector/shumate-vector-collision.c
+++ b/shumate/vector/shumate-vector-collision.c
@@ -52,31 +52,31 @@ struct ShumateVectorCollision {
typedef struct {
GPtrArray *markers;
- ShumateVectorCollisionRect rect;
+ ShumateVectorCollisionBBox bbox;
} RTreeCol;
typedef struct {
RTreeCol cols[NODES];
- ShumateVectorCollisionRect rect;
+ ShumateVectorCollisionBBox bbox;
} RTreeRow;
typedef struct {
RTreeRow rows[NODES];
- ShumateVectorCollisionRect rect;
+ ShumateVectorCollisionBBox bbox;
int n_markers;
} RTreeTileCol;
typedef struct {
GHashTable *tile_cols;
- ShumateVectorCollisionRect rect;
+ ShumateVectorCollisionBBox bbox;
} RTreeTileRow;
static RTreeTileCol *
-tile_col_new (ShumateVectorCollisionRect *rect)
+tile_col_new (ShumateVectorCollisionBBox *bbox)
{
RTreeTileCol *tile_col = g_new0 (RTreeTileCol, 1);
- tile_col->rect = *rect;
+ tile_col->bbox = *bbox;
return tile_col;
}
@@ -93,11 +93,11 @@ tile_col_free (RTreeTileCol *tile_col)
static RTreeTileRow *
-tile_row_new (ShumateVectorCollisionRect *rect)
+tile_row_new (ShumateVectorCollisionBBox *bbox)
{
RTreeTileRow *tile_row = g_new0 (RTreeTileRow, 1);
tile_row->tile_cols = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)
tile_col_free);
- tile_row->rect = *rect;
+ tile_row->bbox = *bbox;
return tile_row;
}
@@ -136,104 +136,164 @@ shumate_vector_collision_free (ShumateVectorCollision *self)
}
-static gboolean
-rects_intersect (ShumateVectorCollisionRect *a,
- ShumateVectorCollisionRect *b)
+static float
+dot (ShumateVectorPoint *a,
+ ShumateVectorPoint *b)
{
- g_assert (a->left <= a->right);
- g_assert (a->top <= a->bottom);
- g_assert (b->left <= b->right);
- g_assert (b->top <= b->bottom);
-
- return !(a->left >= b->right
- || a->right <= b->left
- || a->top >= b->bottom
- || a->bottom <= b->top);
+ return a->x * b->x + a->y * b->y;
}
-static void
-expand_rect (ShumateVectorCollisionRect *a,
- const ShumateVectorCollisionRect *b)
+static float
+project (ShumateVectorPoint *point,
+ ShumateVectorPoint *axis)
{
- if (a->left == 0 && a->right == 0 && a->top == 0 && a->bottom == 0)
- *a = *b;
- else
- {
- a->left = MIN (a->left, b->left);
- a->right = MAX (a->right, b->right);
- a->top = MIN (a->top, b->top);
- a->bottom = MAX (a->bottom, b->bottom);
- }
+ ShumateVectorPoint tmp;
+ float s = dot (point, axis) / LEN_SQ (axis->x, axis->y);
+ tmp = *axis;
+ tmp.x *= s;
+ tmp.y *= s;
+ return dot (&tmp, axis);
}
-static void
-rotate_point (ShumateVectorPoint *point,
- float radians)
+static ShumateVectorPoint
+corner (float x,
+ float y,
+ float xextent,
+ float yextent,
+ float rot_cos,
+ float rot_sin)
{
- float x, y, s, c;
+ return (ShumateVectorPoint) {
+ .x = xextent * rot_cos - yextent * rot_sin + x,
+ .y = xextent * rot_sin + yextent * rot_cos + y,
+ };
+}
- if (radians == 0)
- return;
- x = point->x;
- y = point->y;
- s = sin (-radians);
- c = cos (-radians);
+static gboolean
+rects_intersect (ShumateVectorCollisionBBox *a,
+ ShumateVectorCollisionBBox *b)
+{
+ float cos_a, sin_a, cos_b, sin_b;
+ ShumateVectorPoint axes[4], corners_a[4], corners_b[4];
+
+ if (a->rotation == 0 && b->rotation == 0)
+ {
+ return !((a->x + a->xextent < b->x - b->xextent)
+ || (b->x + b->xextent < a->x - a->xextent)
+ || (a->y + a->yextent < b->y - b->yextent)
+ || (b->y + b->yextent < a->y - a->yextent));
+ }
+
+ /* See
<https://www.gamedev.net/articles/programming/general-and-gameplay-programming/2d-rotated-rectangle-collision-r2604/>
*/
+
+ cos_a = cosf (a->rotation);
+ sin_a = sinf (a->rotation);
+ cos_b = cosf (b->rotation);
+ sin_b = sinf (b->rotation);
+
+ /* Calculate the four axes of the two rectangles */
+ axes[0] = (ShumateVectorPoint) { cos_a, sin_a };
+ axes[1] = (ShumateVectorPoint) { -sin_a, cos_a };
+ axes[2] = (ShumateVectorPoint) { cos_b, sin_b };
+ axes[3] = (ShumateVectorPoint) { -sin_b, cos_b };
+
+ corners_a[0] = corner (a->x, a->y, a->xextent, a->yextent, cos_a, sin_a);
+ corners_a[1] = corner (a->x, a->y, -a->xextent, a->yextent, cos_a, sin_a);
+ corners_a[2] = corner (a->x, a->y, a->xextent, -a->yextent, cos_a, sin_a);
+ corners_a[3] = corner (a->x, a->y, -a->xextent, -a->yextent, cos_a, sin_a);
+
+ corners_b[0] = corner (b->x, b->y, b->xextent, b->yextent, cos_b, sin_b);
+ corners_b[1] = corner (b->x, b->y, -b->xextent, b->yextent, cos_b, sin_b);
+ corners_b[2] = corner (b->x, b->y, b->xextent, -b->yextent, cos_b, sin_b);
+ corners_b[3] = corner (b->x, b->y, -b->xextent, -b->yextent, cos_b, sin_b);
+
+ for (int i = 0; i < 4; i ++)
+ {
+ ShumateVectorPoint *axis = &axes[i];
+
+ float proj_a[4], proj_b[4];
+
+ /* Project the corners of the rectangles onto the axis */
+ for (int j = 0; j < 4; j ++)
+ {
+ proj_a[j] = project (&corners_a[j], axis);
+ proj_b[j] = project (&corners_b[j], axis);
+ }
+
+ /* If the projected points don't overlap, the rectangles don't overlap
+ * (i.e. either every item in proj_a is greater than or is less than every
+ * item in proj_b). */
+ float min_a = MIN4 (proj_a[0], proj_a[1], proj_a[2], proj_a[3]);
+ float max_a = MAX4 (proj_a[0], proj_a[1], proj_a[2], proj_a[3]);
+ float min_b = MIN4 (proj_b[0], proj_b[1], proj_b[2], proj_b[3]);
+ float max_b = MAX4 (proj_b[0], proj_b[1], proj_b[2], proj_b[3]);
+
+ if (min_a >= max_b || min_b >= max_a)
+ return FALSE;
+ }
- point->x = x * c - y * s;
- point->y = x * s + y * c;
+ return TRUE;
}
static void
-scale_point (ShumateVectorPoint *point,
- float scale)
+expand_rect (ShumateVectorCollisionBBox *a,
+ const ShumateVectorCollisionBBox *b)
{
- point->x *= scale;
- point->y *= scale;
+ g_assert (a->rotation == 0);
+ g_assert (b->rotation == 0);
+
+ if (a->x == 0 && a->y == 0 && a->xextent == 0 && a->yextent == 0)
+ *a = *b;
+ else
+ {
+ float left = MIN (a->x - a->xextent, b->x - b->xextent);
+ float right = MAX (a->x + a->xextent, b->x + b->xextent);
+ float top = MIN (a->y - a->yextent, b->y - b->yextent);
+ float bottom = MAX (a->y + a->yextent, b->y + b->yextent);
+ a->x = (left + right) / 2.0;
+ a->y = (top + bottom) / 2.0;
+ a->xextent = (right - left) / 2.0;
+ a->yextent = (bottom - top) / 2.0;
+ }
}
static void
-get_marker_bbox (ShumateVectorCollisionMarker *marker,
- float rot,
- float zoom,
- ShumateVectorCollisionRect *rect_out)
+get_marker_full_rot_bbox (ShumateVectorCollisionMarker *marker,
+ ShumateVectorCollisionBBox *bbox_out)
{
- ShumateVectorPoint top_left = { marker->rect.left, marker->rect.top };
- ShumateVectorPoint top_right = { marker->rect.right, marker->rect.top };
- ShumateVectorPoint bottom_left = { marker->rect.left, marker->rect.bottom };
- ShumateVectorPoint bottom_right = { marker->rect.right, marker->rect.bottom };
-
- rotate_point (&top_left, rot);
- rotate_point (&top_right, rot);
- rotate_point (&bottom_left, rot);
- rotate_point (&bottom_right, rot);
-
- rect_out->left = MIN4 (top_left.x, top_right.x, bottom_left.x, bottom_right.x) + marker->center.x;
- rect_out->right = MAX4 (top_left.x, top_right.x, bottom_left.x, bottom_right.x) + marker->center.x;
- rect_out->top = MIN4 (top_left.y, top_right.y, bottom_left.y, bottom_right.y) + marker->center.y;
- rect_out->bottom = MAX4 (top_left.y, top_right.y, bottom_left.y, bottom_right.y) + marker->center.y;
+ float radius = sqrt (LEN_SQ (marker->bbox.xextent, marker->bbox.yextent));
+
+ if (marker->rotates)
+ {
+ bbox_out->x = marker->bbox.x;
+ bbox_out->y = marker->bbox.y;
+ bbox_out->xextent = radius;
+ bbox_out->yextent = radius;
+ bbox_out->rotation = 0;
+ }
+ else
+ *bbox_out = marker->bbox;
}
static void
-get_marker_full_rot_bbox (ShumateVectorCollisionMarker *marker,
- ShumateVectorCollisionRect *rect_out)
+get_marker_bbox (ShumateVectorCollisionMarker *marker,
+ float rot,
+ float zoom,
+ ShumateVectorCollisionBBox *bbox)
{
- float top_left = LEN_SQ (marker->rect.top, marker->rect.left);
- float bottom_left = LEN_SQ (marker->rect.bottom, marker->rect.left);
- float top_right = LEN_SQ (marker->rect.top, marker->rect.right);
- float bottom_right = LEN_SQ (marker->rect.bottom, marker->rect.right);
+ float scale = powf (2, zoom - marker->zoom);
- float radius = sqrt (MAX4 (top_left, bottom_left, top_right, bottom_right));
-
- rect_out->left = marker->center.x - radius;
- rect_out->right = marker->center.x + radius;
- rect_out->top = marker->center.y - radius;
- rect_out->bottom = marker->center.y + radius;
+ *bbox = marker->bbox;
+ bbox->x *= scale;
+ bbox->y *= scale;
+ if (marker->rotates)
+ bbox->rotation -= rot;
}
@@ -243,23 +303,12 @@ markers_intersect (ShumateVectorCollisionMarker *a,
float rot,
float zoom)
{
- ShumateVectorPoint a_center = a->center;
- ShumateVectorPoint b_center = b->center;
-
- g_assert (a->rect.left <= a->rect.right);
- g_assert (a->rect.top <= a->rect.bottom);
- g_assert (b->rect.left <= b->rect.right);
- g_assert (b->rect.top <= b->rect.bottom);
-
- rotate_point (&a_center, -rot);
- rotate_point (&b_center, -rot);
- scale_point (&a_center, powf (2, zoom - a->zoom));
- scale_point (&b_center, powf (2, zoom - b->zoom));
-
- return !(a_center.x + a->rect.left >= b_center.x + b->rect.right
- || a_center.x + a->rect.right <= b_center.x + b->rect.left
- || a_center.y + a->rect.top >= b_center.y + b->rect.bottom
- || a_center.y + a->rect.bottom <= b_center.y + b->rect.top);
+ ShumateVectorCollisionBBox a_bbox, b_bbox;
+
+ get_marker_bbox (a, rot, zoom, &a_bbox);
+ get_marker_bbox (b, rot, zoom, &b_bbox);
+
+ return rects_intersect (&a_bbox, &b_bbox);
}
@@ -282,17 +331,16 @@ shumate_vector_collision_insert (ShumateVectorCollision *self,
int zoom,
float x,
float y,
- float left,
- float right,
- float top,
- float bottom)
+ float xextent,
+ float yextent,
+ guint rotates)
{
RTreeTileRow *tile_row;
RTreeTileCol *tile_col;
RTreeRow *row;
RTreeCol *col;
+ ShumateVectorCollisionBBox bbox;
ShumateVectorCollisionMarker *marker;
- ShumateVectorCollisionRect bbox;
gint64 tile_x = floor (x / TILE_SIZE);
gint64 tile_y = floor (y / TILE_SIZE);
@@ -301,12 +349,11 @@ shumate_vector_collision_insert (ShumateVectorCollision *self,
zoom = CLAMP (zoom, 0, ZOOM_LAYERS - 1);
marker = g_new0 (ShumateVectorCollisionMarker, 1);
- marker->center.x = x;
- marker->center.y = y;
- marker->rect.left = left;
- marker->rect.right = right;
- marker->rect.top = top;
- marker->rect.bottom = bottom;
+ marker->bbox.x = x;
+ marker->bbox.y = y;
+ marker->bbox.xextent = xextent;
+ marker->bbox.yextent = yextent;
+ marker->rotates = !!rotates;
marker->zoom = zoom;
marker->seq = self->seq;
@@ -339,10 +386,10 @@ shumate_vector_collision_insert (ShumateVectorCollision *self,
tile_col->n_markers ++;
/* Expand the parents to fit the new marker */
- expand_rect (&tile_row->rect, &bbox);
- expand_rect (&tile_col->rect, &bbox);
- expand_rect (&row->rect, &bbox);
- expand_rect (&col->rect, &bbox);
+ expand_rect (&tile_row->bbox, &bbox);
+ expand_rect (&tile_col->bbox, &bbox);
+ expand_rect (&row->bbox, &bbox);
+ expand_rect (&col->bbox, &bbox);
self->dirty = TRUE;
return marker;
@@ -357,8 +404,8 @@ shumate_vector_collision_remove (ShumateVectorCollision *self,
RTreeTileCol *tile_col;
RTreeRow *row;
RTreeCol *col;
- gint64 tile_x = floor (marker->center.x / TILE_SIZE);
- gint64 tile_y = floor (marker->center.y / TILE_SIZE);
+ gint64 tile_x = floor (marker->bbox.x / TILE_SIZE);
+ gint64 tile_y = floor (marker->bbox.y / TILE_SIZE);
g_assert (self != NULL);
g_assert (marker != NULL);
@@ -369,8 +416,8 @@ shumate_vector_collision_remove (ShumateVectorCollision *self,
tile_col = g_hash_table_lookup (tile_row->tile_cols, (gpointer) tile_x);
g_assert (tile_col != NULL);
- row = &tile_col->rows[row_for_position (marker->center.y)];
- col = &row->cols[row_for_position (marker->center.x)];
+ row = &tile_col->rows[row_for_position (marker->bbox.y)];
+ col = &row->cols[row_for_position (marker->bbox.x)];
self->markers = g_list_remove_link (self->markers, marker->list_link);
g_list_free (marker->list_link);
@@ -395,7 +442,7 @@ detect_collision (ShumateVectorCollision *self,
float rot,
float zoom)
{
- ShumateVectorCollisionRect bbox;
+ ShumateVectorCollisionBBox bbox;
for (int z = 0; z < ZOOM_LAYERS; z ++)
{
@@ -411,28 +458,28 @@ detect_collision (ShumateVectorCollision *self,
GHashTableIter tile_cols;
RTreeTileCol *tile_col;
- if (!rects_intersect (&bbox, &tile_row->rect))
+ if (!rects_intersect (&bbox, &tile_row->bbox))
continue;
g_hash_table_iter_init (&tile_cols, tile_row->tile_cols);
while (g_hash_table_iter_next (&tile_cols, NULL, (gpointer*) &tile_col))
{
- if (!rects_intersect (&bbox, &tile_col->rect))
+ if (!rects_intersect (&bbox, &tile_col->bbox))
continue;
for (int y = 0; y < NODES; y ++)
{
RTreeRow *row = &tile_col->rows[y];
- if (!rects_intersect (&bbox, &row->rect))
+ if (!rects_intersect (&bbox, &row->bbox))
continue;
for (int x = 0; x < NODES; x ++)
{
RTreeCol *col = &row->cols[x];
- if (col->markers == NULL || !rects_intersect (&bbox, &col->rect))
+ if (col->markers == NULL || !rects_intersect (&bbox, &col->bbox))
continue;
for (int i = 0; i < col->markers->len; i ++)
diff --git a/shumate/vector/shumate-vector-render-scope.c b/shumate/vector/shumate-vector-render-scope.c
index 3a156d6..8b9106b 100644
--- a/shumate/vector/shumate-vector-render-scope.c
+++ b/shumate/vector/shumate-vector-render-scope.c
@@ -197,6 +197,11 @@ shumate_vector_render_scope_get_bounds (ShumateVectorRenderScope *self,
*max_y = MAX (*max_y, y);
}
}
+
+ *min_x /= self->layer->extent;
+ *min_y /= self->layer->extent;
+ *max_x /= self->layer->extent;
+ *max_y /= self->layer->extent;
}
@@ -207,8 +212,8 @@ shumate_vector_render_scope_get_geometry_center (ShumateVectorRenderScope *self,
{
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;
+ *x = (min_x + max_x) / 2.0;
+ *y = (min_y + max_y) / 2.0;
}
diff --git a/shumate/vector/shumate-vector-symbol-container.c
b/shumate/vector/shumate-vector-symbol-container.c
index c10aeb6..06625d8 100644
--- a/shumate/vector/shumate-vector-symbol-container.c
+++ b/shumate/vector/shumate-vector-symbol-container.c
@@ -301,22 +301,33 @@ shumate_vector_symbol_container_add_symbols (ShumateVectorSymbolContainer *self,
info->symbol = symbol;
info->symbol_info = symbol_info;
- 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;
+ if (symbol_info->line_placement)
+ {
+ /* Use the line geometry and font size to get an upper bound on the
+ * symbol size */
+ info->width = symbol_info->line_size.x * 2 * tile_size + symbol_info->text_size;
+ info->height = symbol_info->line_size.y * 2 * tile_size + symbol_info->text_size;
+ }
+ else
+ {
+ /* Measure the label widget to get the symbol size */
+ 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->marker = shumate_vector_collision_insert (self->collision,
zoom,
(tile_x + info->x) * tile_size,
(tile_y + info->y) * tile_size,
- -info->width / 2,
info->width / 2,
- -info->height / 2,
- info->height / 2);
+ info->height / 2,
+ !symbol_info->line_placement);
self->children = g_list_prepend (self->children, info);
gtk_widget_set_parent (GTK_WIDGET (info->symbol), GTK_WIDGET (self));
diff --git a/shumate/vector/shumate-vector-symbol-info-private.h
b/shumate/vector/shumate-vector-symbol-info-private.h
index bfe19cd..09782b6 100644
--- a/shumate/vector/shumate-vector-symbol-info-private.h
+++ b/shumate/vector/shumate-vector-symbol-info-private.h
@@ -40,6 +40,7 @@ struct _ShumateVectorSymbolInfo
double y;
ShumateVectorLineString line;
+ ShumateVectorPoint line_size;
/*< private >*/
guint ref_count;
diff --git a/shumate/vector/shumate-vector-symbol-info.c b/shumate/vector/shumate-vector-symbol-info.c
index 8731b76..3dc2d97 100644
--- a/shumate/vector/shumate-vector-symbol-info.c
+++ b/shumate/vector/shumate-vector-symbol-info.c
@@ -89,6 +89,10 @@ void
shumate_vector_symbol_info_set_line_points (ShumateVectorSymbolInfo *self,
ShumateVectorLineString *linestring)
{
+ ShumateVectorPoint center;
shumate_vector_line_string_clear (&self->line);
self->line = *linestring;
+ shumate_vector_line_string_bounds (&self->line, &self->line_size, ¢er);
+ self->x = center.x;
+ self->y = center.y;
}
diff --git a/shumate/vector/shumate-vector-symbol-layer.c b/shumate/vector/shumate-vector-symbol-layer.c
index a73fba9..9ee597b 100644
--- a/shumate/vector/shumate-vector-symbol-layer.c
+++ b/shumate/vector/shumate-vector-symbol-layer.c
@@ -109,6 +109,7 @@ shumate_vector_symbol_layer_render (ShumateVectorLayer *layer, ShumateVectorRend
double text_size;
ShumateVectorSymbolInfo *symbol_info;
double x, y;
+ double min_x, min_y, max_x, max_y;
shumate_vector_render_scope_get_geometry_center (scope, &x, &y);
if (x < 0 || x >= 1 || y < 0 || y >= 1)
@@ -116,6 +117,8 @@ shumate_vector_symbol_layer_render (ShumateVectorLayer *layer, ShumateVectorRend
* covered by a different tile. */
return;
+ shumate_vector_render_scope_get_bounds (scope, &min_x, &min_y, &max_x, &max_y);
+
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, "");
diff --git a/shumate/vector/shumate-vector-symbol.c b/shumate/vector/shumate-vector-symbol.c
index 7ed9937..756c0c3 100644
--- a/shumate/vector/shumate-vector-symbol.c
+++ b/shumate/vector/shumate-vector-symbol.c
@@ -238,6 +238,10 @@ shumate_vector_symbol_snapshot (GtkWidget *widget,
if (self->glyphs_length > self->line_length * scale)
return;
+ gtk_snapshot_save (snapshot);
+ gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (gtk_widget_get_allocated_width (widget) / 2,
+ gtk_widget_get_allocated_height (widget) / 2));
+
gtk_snapshot_rotate (snapshot, rotation * 180 / G_PI);
shumate_vector_point_iter_init (&iter, &self->symbol_info->line);
@@ -268,6 +272,8 @@ shumate_vector_symbol_snapshot (GtkWidget *widget,
shumate_vector_point_iter_advance (&iter, glyph->width / scale);
}
+
+ gtk_snapshot_restore (snapshot);
}
else
GTK_WIDGET_CLASS (shumate_vector_symbol_parent_class)->snapshot (widget, snapshot);
diff --git a/shumate/vector/shumate-vector-utils-private.h b/shumate/vector/shumate-vector-utils-private.h
index 3c0d511..f424297 100644
--- a/shumate/vector/shumate-vector-utils-private.h
+++ b/shumate/vector/shumate-vector-utils-private.h
@@ -91,6 +91,8 @@ void shumate_vector_point_iter_advance (ShumateVectorPointIter *i
double distance);
double shumate_vector_point_iter_get_current_angle (ShumateVectorPointIter *iter);
-
void shumate_vector_line_string_clear (ShumateVectorLineString *linestring);
double shumate_vector_line_string_length (ShumateVectorLineString *linestring);
+void shumate_vector_line_string_bounds (ShumateVectorLineString *linestring,
+ ShumateVectorPoint *radius_out,
+ ShumateVectorPoint *center_out);
diff --git a/shumate/vector/shumate-vector-utils.c b/shumate/vector/shumate-vector-utils.c
index 06dcf73..d2cf7c9 100644
--- a/shumate/vector/shumate-vector-utils.c
+++ b/shumate/vector/shumate-vector-utils.c
@@ -313,3 +313,31 @@ shumate_vector_line_string_length (ShumateVectorLineString *linestring)
return sum;
}
+
+
+void
+shumate_vector_line_string_bounds (ShumateVectorLineString *linestring,
+ ShumateVectorPoint *radius_out,
+ ShumateVectorPoint *center_out)
+{
+ guint i;
+ float min_x, max_x, min_y, max_y;
+
+ g_return_if_fail (linestring->n_points > 0);
+
+ min_x = max_x = linestring->points[0].x;
+ min_y = max_y = linestring->points[0].y;
+
+ for (i = 1; i < linestring->n_points; i ++)
+ {
+ min_x = MIN (min_x, linestring->points[i].x);
+ max_x = MAX (max_x, linestring->points[i].x);
+ min_y = MIN (min_y, linestring->points[i].y);
+ max_y = MAX (max_y, linestring->points[i].y);
+ }
+
+ radius_out->x = (max_x - min_x) / 2.0;
+ radius_out->y = (max_y - min_y) / 2.0;
+ center_out->x = (max_x + min_x) / 2.0;
+ center_out->y = (max_y + min_y) / 2.0;
+}
diff --git a/tests/vector-collision.c b/tests/vector-collision.c
index 21ac14b..7f333e8 100644
--- a/tests/vector-collision.c
+++ b/tests/vector-collision.c
@@ -11,20 +11,19 @@ test_vector_collision_nonoverlapping (void)
collision = shumate_vector_collision_new ();
- shumate_vector_collision_insert (collision, 0, 0, 0, -1, 1, -1, 1);
+ shumate_vector_collision_insert (collision, 0, 0, 0, -1, 1, TRUE);
/* Far away markers */
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 10, 10, -1, 1, -1, 1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 100000, 0, -1, 1, -1,
1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 100000, -1, 1, -1,
1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 100000, 100000, -1, 1,
-1, 1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 0, 100, 200, 100,
200));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 10, 10, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 100000, 0, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 100000, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 100000, 100000, 1, 1,
TRUE));
/* Edge only */
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 2, 0, -1, 1, -1, 1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, -2, 0, -1, 1, -1, 1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 2, -1, 1, -1, 1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, -2, -1, 1, -1, 1));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 2, 0, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, -2, 0, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 2, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, -2, 1, 1, TRUE));
shumate_vector_collision_recalc (collision, 0, 0);
@@ -44,13 +43,13 @@ test_vector_collision_overlapping (void)
collision = shumate_vector_collision_new ();
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 0, -1, 1, -1, 1));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 0, -2, 2, -2, 2));
- markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 1, 1, -1, 1, -1, 1));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 0, 1, 1, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 0, 0, 2, 2, TRUE));
+ markers = g_list_prepend (markers, shumate_vector_collision_insert (collision, 0, 1, 1, 1, 1, TRUE));
/* The current implementation uses g_list_prepend, so the last inserted
* marker has priority. */
- visible_marker = shumate_vector_collision_insert (collision, 0, 0, 0, -1, 1, -1, 1);
+ visible_marker = shumate_vector_collision_insert (collision, 0, 0, 0, 1, 1, TRUE);
markers = g_list_prepend (markers, visible_marker);
shumate_vector_collision_recalc (collision, 0, 0);
@@ -75,8 +74,8 @@ test_vector_collision_zoom (void)
collision = shumate_vector_collision_new ();
- marker1 = shumate_vector_collision_insert (collision, 1, 0, 0, -1, 1, -1, 1);
- marker2 = shumate_vector_collision_insert (collision, 2, 3, 3, -2, 2, -2, 2);
+ marker1 = shumate_vector_collision_insert (collision, 1, 0, 0, 1, 1, TRUE);
+ marker2 = shumate_vector_collision_insert (collision, 2, 2, 2, 1, 1, TRUE);
shumate_vector_collision_recalc (collision, 0, 1);
g_assert_false (marker1->visible);
@@ -102,8 +101,8 @@ test_vector_collision_rotate (void)
collision = shumate_vector_collision_new ();
- marker1 = shumate_vector_collision_insert (collision, 0, 0, 0, -10, 10, -1, 1);
- marker2 = shumate_vector_collision_insert (collision, 0, 0, 3, -10, 10, -1, 1);
+ marker1 = shumate_vector_collision_insert (collision, 0, 0, 0, 10, 1, TRUE);
+ marker2 = shumate_vector_collision_insert (collision, 0, 0, 3, 10, 1, TRUE);
shumate_vector_collision_recalc (collision, 0, 0);
g_assert_true (marker1->visible);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]