[CPML] Added equality method for pairs and extents
[adg.git] / src / adg / adg-point.c
blob854d8127191f856c9b7f9aff0ae3756eb2d13b1d
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-point
23 * @Section_Id:AdgPoint
24 * @title: AdgPoint
25 * @short_description: A struct holding x, y coordinates
26 * (either named or explicit)
28 * AdgPoint is an opaque structure that manages 2D coordinates,
29 * either set explicitely throught adg_point_set_pair() and
30 * adg_point_set_pair_explicit() or taken from a model with
31 * adg_point_set_pair_from_model(). It can be thought as an
32 * #AdgPair on steroid, because it adds named pair support to
33 * a simple pair, enabling coordinates depending on #AdgModel.
34 **/
36 /**
37 * AdgPoint:
39 * This is an opaque struct: all its fields are privates.
40 **/
43 #include "adg-internal.h"
44 #include "adg-point.h"
45 #include <string.h>
48 struct _AdgPoint {
49 AdgPair pair;
50 AdgModel *model;
51 gchar *name;
52 gboolean is_uptodate;
56 GType
57 adg_point_get_type(void)
59 static int type = 0;
61 if (G_UNLIKELY(type == 0))
62 type = g_boxed_type_register_static("AdgPoint",
63 (GBoxedCopyFunc) adg_point_dup,
64 (GBoxedFreeFunc) adg_point_destroy);
66 return type;
69 /**
70 * adg_point_new:
72 * Creates a new empty #AdgPoint. The returned pointer
73 * should be freed with adg_point_destroy() when no longer needed.
75 * The returned value should be freed with adg_point_destroy()
76 * when no longer needed.
78 * Returns: a newly created #AdgPoint
79 **/
80 AdgPoint *
81 adg_point_new(void)
83 return g_new0(AdgPoint, 1);
86 /**
87 * adg_point_dup:
88 * @src: an #AdgPoint
90 * Duplicates @src. This operation also adds a new reference
91 * to the internal model if @src is linked to a named pair.
93 * The returned value should be freed with adg_point_destroy()
94 * when no longer needed.
96 * Returns: the duplicated #AdgPoint struct or %NULL on errors
97 **/
98 AdgPoint *
99 adg_point_dup(const AdgPoint *src)
101 AdgPoint *point;
103 g_return_val_if_fail(src != NULL, NULL);
105 if (src->model)
106 g_object_ref(src->model);
108 point = g_memdup(src, sizeof(AdgPoint));
109 point->name = g_strdup(src->name);
111 return point;
115 * adg_point_destroy:
116 * @point: an #AdgPoint
118 * Destroys the @point instance, unreferencing the internal model if
119 * @point is linked to a named pair.
121 void
122 adg_point_destroy(AdgPoint *point)
124 g_return_if_fail(point != NULL);
126 adg_point_unset(point);
127 g_free(point);
131 * adg_point_copy:
132 * @point: an #AdgPoint
133 * @src: the source point to copy
135 * Copies @src into @point. If the old content of @point was linked
136 * to the named pair of a model, the reference to that model is
137 * dropped. Similary, if @src is a named pair, a new reference to
138 * the new model is added.
140 void
141 adg_point_copy(AdgPoint *point, const AdgPoint *src)
143 g_return_if_fail(point != NULL);
144 g_return_if_fail(src != NULL);
146 if (src->model != NULL)
147 g_object_ref(src->model);
149 if (point->model != NULL)
150 g_object_unref(point->model);
152 if (point->name != NULL)
153 g_free(point->name);
155 memcpy(point, src, sizeof(AdgPoint));
156 point->name = g_strdup(src->name);
160 * adg_point_set_pair:
161 * @point: an #AdgPoint
162 * @pair: the #AdgPair to use
164 * Sets an explicit pair in @point by using the given @pair. If
165 * @point was linked to a named pair in a model, this link is
166 * dropped before setting the pair.
168 void
169 adg_point_set_pair(AdgPoint *point, const AdgPair *pair)
171 g_return_if_fail(point != NULL);
172 g_return_if_fail(pair != NULL);
174 adg_point_set_pair_explicit(point, pair->x, pair->y);
178 * adg_point_set_pair_explicit:
179 * @point: an #AdgPoint
180 * @x: the x coordinate of the point
181 * @y: the y coordinate of the point
183 * Works in the same way of adg_point_set_pair() but accept direct numbers
184 * instead of an #AdgPair structure.
186 void
187 adg_point_set_pair_explicit(AdgPoint *point, gdouble x, gdouble y)
189 g_return_if_fail(point != NULL);
191 adg_point_unset(point);
192 point->pair.x = x;
193 point->pair.y = y;
194 point->is_uptodate = TRUE;
198 * adg_point_set_pair_from_model:
199 * @point: an #AdgPoint
200 * @model: the #AdgModel
201 * @name: the id of a named pair in @model
203 * Links the @name named pair of @model to @point, so any subsequent
204 * call to adg_point_get_pair() will return the named pair value.
205 * A new reference is added to @model while the previous model (if any)
206 * is unreferenced.
208 void
209 adg_point_set_pair_from_model(AdgPoint *point,
210 AdgModel *model, const gchar *name)
212 g_return_if_fail(point != NULL);
213 g_return_if_fail(ADG_IS_MODEL(model));
214 g_return_if_fail(name != NULL);
216 /* Return if the new named pair is the same of the old one */
217 if (model == point->model && strcmp(point->name, name) == 0)
218 return;
220 g_object_ref(model);
222 if (point->model) {
223 /* Remove the old named pair */
224 g_object_unref(point->model);
225 g_free(point->name);
228 /* Set the new named pair */
229 point->is_uptodate = FALSE;
230 point->model = model;
231 point->name = g_strdup(name);
235 * adg_point_unset:
236 * @point: a pointer to an #AdgPoint
238 * Unsets @point by resetting the internal "is_uptodate" flag.
239 * This also means @point is unlinked from the model if it is
240 * a named pair. In any cases, after this call the content of
241 * @point is undefined, that is calling adg_point_get_pair()
242 * will return %NULL.
244 void
245 adg_point_unset(AdgPoint *point)
247 g_return_if_fail(point != NULL);
249 if (point->model) {
250 /* Remove the old named pair */
251 g_object_unref(point->model);
252 g_free(point->name);
255 point->is_uptodate = FALSE;
256 point->model = NULL;
257 point->name = NULL;
261 * adg_point_get_pair:
262 * @point: an #AdgPoint
264 * #AdgPoint is an evolution of the pair concept but internally the
265 * relevant data is still stored in an #AdgPair struct. This function
266 * gets the pointer to this struct, updating the value prior to
267 * return it if needed (that is, if @point is linked to a not up
268 * to date named pair).
270 * Returns: the pair of @point or %NULL if the named pair does not exist
272 const AdgPair *
273 adg_point_get_pair(AdgPoint *point)
275 g_return_val_if_fail(point != NULL, NULL);
277 if (!point->is_uptodate) {
278 const AdgPair *pair;
280 if (point->model == NULL) {
281 /* A point with explicit coordinates not up to date
282 * is an unexpected condition */
283 g_warning(_("%s: trying to get a pair from an undefined point"),
284 G_STRLOC);
285 return NULL;
288 pair = adg_model_get_named_pair(point->model, point->name);
290 /* "Named pair not found" condition: return NULL without warnings */
291 if (pair == NULL)
292 return NULL;
294 cpml_pair_copy(&point->pair, pair);
295 point->is_uptodate = TRUE;
298 return (AdgPair *) point;
302 * adg_point_get_model:
303 * @point: an #AdgPoint
305 * Gets the source model of the named pair bound to @point, or
306 * returns %NULL if @point is an explicit pair. The returned
307 * value is owned by @point.
309 * Returns: an #AdgModel or %NULL
311 AdgModel *
312 adg_point_get_model(AdgPoint *point)
314 g_return_val_if_fail(point != NULL, NULL);
315 return point->model;
319 * adg_point_get_name:
320 * @point: an #AdgPoint
322 * Gets the name of the named pair bound to @point, or returns
323 * %NULL if @point is an explicit pair. The returned value is
324 * owned by @point and should not be modified or freed.
326 * Returns: the name of the named pair or %NULL
328 const gchar *
329 adg_point_get_name(AdgPoint *point)
331 g_return_val_if_fail(point != NULL, NULL);
332 return point->name;
336 * adg_point_invalidate:
337 * @point: an #AdgPoint
339 * Invalidates @point, forcing a refresh of its internal #AdgPair if
340 * the point is linked to a named pair. If @point is explicitely set,
341 * this function has no effect.
343 void
344 adg_point_invalidate(AdgPoint *point)
346 g_return_if_fail(point != NULL);
348 if (point->model)
349 point->is_uptodate = FALSE;
353 * adg_point_equal:
354 * @point1: the first point to compare
355 * @point2: the second point to compare
357 * Compares @point1 and @point2 and returns %TRUE if the points are
358 * equals. The comparison is made by matching also where the points
359 * are bound. If you want to compare only the coordinates, use
360 * cpml_pair_equal() directly on their pairs:
362 * |[
363 * cpml_pair_equal(adg_point_get_pair(point1), adg_point_get_pair(point2));
364 * ]|
366 * %NULL values are handled gracefully.
368 * Returns: %TRUE if @point1 is equal to @point2, %FALSE otherwise
370 gboolean
371 adg_point_equal(const AdgPoint *point1, const AdgPoint *point2)
373 if (point1 == point2)
374 return TRUE;
376 if (point1 == NULL || point2 == NULL)
377 return FALSE;
379 /* Check if the points are not bound to the same model
380 * or if only one of the two points is explicit */
381 if (point1->model != point2->model)
382 return FALSE;
384 /* Handle points bound to named pairs */
385 if (point1->model)
386 return g_strcmp0(point1->name, point2->name) == 0;
388 /* Handle points with explicit coordinates */
389 return cpml_pair_equal(&point1->pair, &point2->pair);