/* * ld-types.c * * This file is a part of logdiag. * Copyright Přemysl Janouch 2010 - 2011. All rights reserved. * * See the file LICENSE for licensing information. * */ #include #include #include "liblogdiag.h" #include "config.h" /** * SECTION:ld-types * @short_description: Simple data types * * #LdPoint defines coordinates of a point. * * #LdPointArray defines an array of points. * * #LdRectangle defines the position and size of a rectangle. */ #define DEFINE_BOXED_TYPE(TypeName, type_name) \ GType \ type_name ## _get_type (void) \ { \ static GType our_type = 0; \ if (our_type == 0) \ our_type = g_boxed_type_register_static \ (g_intern_static_string (#TypeName), \ (GBoxedCopyFunc) type_name ## _copy, \ (GBoxedFreeFunc) type_name ## _free); \ return our_type; \ } DEFINE_BOXED_TYPE (LdPoint, ld_point) DEFINE_BOXED_TYPE (LdPointArray, ld_point_array) DEFINE_BOXED_TYPE (LdRectangle, ld_rectangle) #define DEFINE_BOXED_TRIVIAL_COPY(TypeName, type_name) \ TypeName * \ type_name ## _copy (const TypeName *self) \ { \ TypeName *new_copy; \ g_return_val_if_fail (self != NULL, NULL); \ new_copy = g_slice_new (TypeName); \ *new_copy = *self; \ return new_copy; \ } #define DEFINE_BOXED_TRIVIAL_FREE(TypeName, type_name) \ void \ type_name ## _free (TypeName *self) \ { \ g_return_if_fail (self != NULL); \ g_slice_free (TypeName, self); \ } /** * ld_point_copy: * @self: an #LdPoint structure. * * Makes a copy of the structure. * The result must be freed by ld_point_free(). * * Return value: a copy of @self. */ DEFINE_BOXED_TRIVIAL_COPY (LdPoint, ld_point) /** * ld_point_free: * @self: an #LdPoint structure. * * Frees the structure created with ld_point_copy(). */ DEFINE_BOXED_TRIVIAL_FREE (LdPoint, ld_point) /** * ld_point_distance: * @self: an #LdPoint structure. * @x: the X coordinate of the second point. * @y: the Y coordinate of the second point. * * Compute the distance between two points. */ gdouble ld_point_distance (const LdPoint *self, gdouble x, gdouble y) { gdouble dx, dy; g_return_val_if_fail (self != NULL, -1); dx = self->x - x; dy = self->y - y; return sqrt (dx * dx + dy * dy); } /** * ld_point_array_new: * * Create a new #LdPointArray. * * Return value: (transfer full): an #LdPointArray structure. */ LdPointArray * ld_point_array_new (void) { return ld_point_array_sized_new (0); } /** * ld_point_array_sized_new: * @preallocated: the number of points preallocated. * * Create a new #LdPointArray and preallocate storage for @preallocated items. * * Return value: (transfer full): an #LdPointArray structure. */ LdPointArray * ld_point_array_sized_new (guint preallocated) { LdPointArray *new_array; new_array = g_slice_new (LdPointArray); new_array->length = 0; new_array->size = preallocated; new_array->points = g_malloc0 (preallocated * sizeof (LdPoint)); return new_array; } /** * ld_point_array_copy: * @self: an #LdPointArray structure. * * Makes a copy of the structure. * The result must be freed by ld_point_array_free(). * * Return value: (transfer full): a copy of @self. */ LdPointArray * ld_point_array_copy (const LdPointArray *self) { LdPointArray *new_array; g_return_val_if_fail (self != NULL, NULL); new_array = g_slice_new (LdPointArray); new_array->length = self->length; new_array->size = self->size; new_array->points = g_memdup (self->points, self->size * sizeof (LdPoint)); return new_array; } /** * ld_point_array_free: * @self: an #LdPointArray structure. * * Frees the structure created with ld_point_array_copy(). */ void ld_point_array_free (LdPointArray *self) { g_return_if_fail (self != NULL); g_free (self->points); g_slice_free (LdPointArray, self); } /** * ld_point_array_insert: * @self: an #LdPointArray structure. * @points: an array of points to be inserted. * @pos: the position at which the points should be inserted. This number * must not be bigger than the number of points already present * in the array. Negative values append to the array. * @length: count of points in @points. * * Insert points into the array. */ void ld_point_array_insert (LdPointArray *self, LdPoint *points, gint pos, guint length) { guint new_size; g_return_if_fail (self != NULL); g_return_if_fail (points != NULL); g_return_if_fail (pos <= (signed) self->length); new_size = self->size ? self->size : 1; while (self->length + length > new_size) new_size <<= 1; if (new_size != self->size) ld_point_array_set_size (self, new_size); if (pos < 0) pos = self->length; g_memmove (self->points + pos + length, self->points + pos, (self->length - pos) * sizeof (LdPoint)); memcpy (self->points + pos, points, length * sizeof (LdPoint)); self->length += length; } /** * ld_point_array_remove: * @self: an #LdPointArray structure. * @pos: the position at which the points should be removed. * Negative values are relative to the end of the array. * @length: count of points to remove. * * Remove points from the array. The array may be resized as a result. */ void ld_point_array_remove (LdPointArray *self, gint pos, guint length) { guint new_size; g_return_if_fail (self != NULL); if (pos < 0) { pos += self->length; if (pos < 0) { length += pos; pos = 0; } } if ((unsigned) pos >= self->length) return; if (pos + length > self->length) length = self->length - pos; g_memmove (self->points + pos, self->points + pos + length, (self->length - pos) * sizeof (LdPoint)); self->length -= length; new_size = self->size; while (new_size >> 2 > self->length) new_size >>= 1; if (new_size != self->size) ld_point_array_set_size (self, new_size); } /** * ld_point_array_set_size: * @self: an #LdPointArray structure. * @size: the new size. * * Change size of the array. */ void ld_point_array_set_size (LdPointArray *self, guint size) { g_return_if_fail (self != NULL); if (self->size == size) return; self->points = g_realloc (self->points, size * sizeof (LdPoint)); if (self->length > size) self->length = size; if (self->size < size) memset (self->points + self->length, 0, size - self->length); self->size = size; } /** * ld_rectangle_copy: * @self: an #LdRectangle structure. * * Makes a copy of the structure. * The result must be freed by ld_rectangle_free(). * * Return value: a copy of @self. */ DEFINE_BOXED_TRIVIAL_COPY (LdRectangle, ld_rectangle) /** * ld_rectangle_free: * @self: an #LdRectangle structure. * * Frees the structure created with ld_rectangle_copy(). */ DEFINE_BOXED_TRIVIAL_FREE (LdRectangle, ld_rectangle) /** * ld_rectangle_intersects: * @self: an #LdRectangle structure. * @rect: an #LdRectangle to be checked for intersection. * * Return value: %TRUE if the two rectangles intersect. */ gboolean ld_rectangle_intersects (const LdRectangle *self, const LdRectangle *rect) { g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (rect != NULL, FALSE); return !(self->x > rect->x + rect->width || self->y > rect->y + rect->height || self->x + self->width < rect->x || self->y + self->height < rect->y); } /** * ld_rectangle_contains: * @self: an #LdRectangle structure. * @rect: an #LdRectangle to be checked for containment. * * Return value: %TRUE if @self fully contains @rect. */ gboolean ld_rectangle_contains (const LdRectangle *self, const LdRectangle *rect) { g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (rect != NULL, FALSE); return (self->x <= rect->x && self->y <= rect->y && self->x + self->width >= rect->x + rect->width && self->y + self->height >= rect->y + rect->height); } /** * ld_rectangle_contains_point: * @self: an #LdRectangle structure. * @point: the point to be checked. * * Return value: %TRUE if the rectangle contains the specified point. */ gboolean ld_rectangle_contains_point (const LdRectangle *self, const LdPoint *point) { g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (point != NULL, FALSE); return (point->x >= self->x && point->x <= self->x + self->width && point->y >= self->y && point->y <= self->y + self->height); } /** * ld_rectangle_extend: * @self: an #LdRectangle structure. * @border: the border by which the rectangle should be extended. * * Extend a rectangle on all sides. */ void ld_rectangle_extend (LdRectangle *self, gdouble border) { g_return_if_fail (self != NULL); self->x -= border; self->y -= border; self->width += 2 * border; self->height += 2 * border; }