doc: update copyright line for 2021
[adg.git] / src / adg / adg-point.c
blobf5abf04c38ef0c89edf2b6b9b215476126de67ae
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2021 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 through 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 * #CpmlPair on steroid, because it adds named pair support to
33 * a simple pair, enabling coordinates depending on #AdgModel.
35 * Since: 1.0
36 **/
38 /**
39 * AdgPoint:
41 * This is an opaque struct: all its fields are privates.
43 * Since: 1.0
44 **/
47 #include "adg-internal.h"
48 #include "adg-model.h"
49 #include <string.h>
51 #include "adg-point.h"
54 struct _AdgPoint {
55 CpmlPair pair;
56 AdgModel *model;
57 gchar *name;
58 gboolean up_to_date;
62 GType
63 adg_point_get_type(void)
65 static GType type = 0;
67 if (G_UNLIKELY(type == 0))
68 type = g_boxed_type_register_static("AdgPoint",
69 (GBoxedCopyFunc) adg_point_dup,
70 (GBoxedFreeFunc) adg_point_destroy);
72 return type;
75 /**
76 * adg_point_new:
78 * Creates a new empty #AdgPoint. The returned pointer
79 * should be freed with adg_point_destroy() when no longer needed.
81 * Returns: a newly created #AdgPoint
83 * Since: 1.0
84 **/
85 AdgPoint *
86 adg_point_new(void)
88 return g_new0(AdgPoint, 1);
91 /**
92 * adg_point_dup:
93 * @src: an #AdgPoint
95 * Duplicates @src. This operation also adds a new reference
96 * to the internal model if @src is linked to a named pair.
98 * The returned value should be freed with adg_point_destroy()
99 * when no longer needed.
101 * Returns: the duplicated #AdgPoint struct or <constant>NULL</constant> on errors.
103 * Since: 1.0
105 AdgPoint *
106 adg_point_dup(const AdgPoint *src)
108 AdgPoint *point;
110 g_return_val_if_fail(src != NULL, NULL);
112 if (src->model)
113 g_object_ref(src->model);
115 point = cpml_memdup(src, sizeof(AdgPoint));
116 point->name = g_strdup(src->name);
118 return point;
122 * adg_point_destroy:
123 * @point: an #AdgPoint
125 * Destroys the @point instance, unreferencing the internal model if
126 * @point is linked to a named pair.
128 * Since: 1.0
130 void
131 adg_point_destroy(AdgPoint *point)
133 g_return_if_fail(point != NULL);
135 adg_point_unset(point);
136 g_free(point);
140 * adg_point_copy:
141 * @point: an #AdgPoint
142 * @src: the source point to copy
144 * Copies @src into @point. If the old content of @point was linked
145 * to the named pair of a model, the reference to that model is
146 * dropped. Similary, if @src is a named pair, a new reference to
147 * the new model is added.
149 * Since: 1.0
151 void
152 adg_point_copy(AdgPoint *point, const AdgPoint *src)
154 g_return_if_fail(point != NULL);
155 g_return_if_fail(src != NULL);
157 if (src->model != NULL)
158 g_object_ref(src->model);
160 if (point->model != NULL)
161 g_object_unref(point->model);
163 if (point->name != NULL)
164 g_free(point->name);
166 memcpy(point, src, sizeof(AdgPoint));
167 point->name = g_strdup(src->name);
171 * adg_point_set_pair:
172 * @point: an #AdgPoint
173 * @pair: the #CpmlPair to use
175 * Sets an explicit pair in @point by using the given @pair. If
176 * @point was linked to a named pair in a model, this link is
177 * dropped before setting the pair.
179 * Since: 1.0
181 void
182 adg_point_set_pair(AdgPoint *point, const CpmlPair *pair)
184 g_return_if_fail(point != NULL);
185 g_return_if_fail(pair != NULL);
187 adg_point_set_pair_explicit(point, pair->x, pair->y);
191 * adg_point_set_pair_explicit:
192 * @point: an #AdgPoint
193 * @x: the x coordinate of the point
194 * @y: the y coordinate of the point
196 * Works in the same way of adg_point_set_pair() but accept direct numbers
197 * instead of an #CpmlPair structure.
199 * Since: 1.0
201 void
202 adg_point_set_pair_explicit(AdgPoint *point, gdouble x, gdouble y)
204 g_return_if_fail(point != NULL);
206 adg_point_unset(point);
207 point->pair.x = x;
208 point->pair.y = y;
209 point->up_to_date = TRUE;
213 * adg_point_set_pair_from_model:
214 * @point: an #AdgPoint
215 * @model: the #AdgModel
216 * @name: the id of a named pair in @model
218 * Links the @name named pair of @model to @point, so any subsequent
219 * call to adg_point_get_pair() will return the named pair value.
220 * A new reference is added to @model while the previous model (if any)
221 * is unreferenced.
223 * Since: 1.0
225 void
226 adg_point_set_pair_from_model(AdgPoint *point,
227 AdgModel *model, const gchar *name)
229 g_return_if_fail(point != NULL);
230 g_return_if_fail(ADG_IS_MODEL(model));
231 g_return_if_fail(name != NULL);
233 /* Return if the new named pair is the same of the old one */
234 if (model == point->model && strcmp(point->name, name) == 0)
235 return;
237 g_object_ref(model);
239 if (point->model) {
240 /* Remove the old named pair */
241 g_object_unref(point->model);
242 g_free(point->name);
245 /* Set the new named pair */
246 point->up_to_date = FALSE;
247 point->model = model;
248 point->name = g_strdup(name);
252 * adg_point_invalidate:
253 * @point: an #AdgPoint
255 * Invalidates @point, forcing a refresh of its internal #CpmlPair if
256 * the point is linked to a named pair. If @point is explicitely set,
257 * this function has no effect.
259 * Since: 1.0
261 void
262 adg_point_invalidate(AdgPoint *point)
264 g_return_if_fail(point != NULL);
266 if (point->model != NULL)
267 point->up_to_date = FALSE;
271 * adg_point_unset:
272 * @point: a pointer to an #AdgPoint
274 * Unsets @point by resetting the internal <varname>up_to_date</varname>
275 * flag and (eventually) unlinking it from the named pair it is bound
276 * to. After this call the content of @point is undefined, so a
277 * subsequent call to adg_point_get_pair() will
278 * return <constant>NULL</constant> raising a warning.
280 * Since: 1.0
282 void
283 adg_point_unset(AdgPoint *point)
285 g_return_if_fail(point != NULL);
287 if (point->model) {
288 /* Remove the old named pair */
289 g_object_unref(point->model);
290 g_free(point->name);
293 point->up_to_date = FALSE;
294 point->model = NULL;
295 point->name = NULL;
299 * adg_point_update:
300 * @point: a pointer to an #AdgPoint
302 * Updates the internal #CpmlPair of @point. The internal
303 * implementation is protected against multiple calls so it
304 * can be called more times without harms.
306 * Returns: <constant>TRUE</constant> if @point has been updated or <constant>FALSE</constant> on errors, i.e. when it is bound to a non-existent named pair.
308 * Since: 1.0
310 gboolean
311 adg_point_update(AdgPoint *point)
313 AdgModel *model;
314 const CpmlPair *pair;
316 g_return_val_if_fail(point != NULL, FALSE);
318 if (point->up_to_date)
319 return TRUE;
321 model = point->model;
322 if (model == NULL) {
323 /* A point with explicit coordinates not up to date
324 * is an unexpected condition */
325 g_warning(_("%s: trying to get a pair from an undefined point"),
326 G_STRLOC);
327 return FALSE;
330 pair = adg_model_get_named_pair(model, point->name);
331 if (pair == NULL)
332 return FALSE;
334 cpml_pair_copy(&point->pair, pair);
335 point->up_to_date = TRUE;
336 return TRUE;
340 * adg_point_get_pair:
341 * @point: an #AdgPoint
343 * #AdgPoint is an evolution of the pair concept but internally the
344 * relevant data is still stored in an #CpmlPair struct. This function
345 * returns a copy of the internally owned pair.
347 * <note><para>
348 * The #CpmlPair is the first field of an #AdgPoint struct so casting
349 * is allowed between them and, in fact, it is often more convenient
350 * than calling this function. Just remember to update the internal
351 * pair by using adg_point_update() before.
352 * </para></note>
354 * Returns: (transfer full): the pair of @point or <constant>NULL</constant> if the named pair does not exist.
356 * Since: 1.0
358 CpmlPair *
359 adg_point_get_pair(AdgPoint *point)
361 g_return_val_if_fail(point != NULL, NULL);
363 if (! adg_point_update(point))
364 return NULL;
366 return cpml_pair_dup(& point->pair);
370 * adg_point_get_model:
371 * @point: an #AdgPoint
373 * Gets the source model of the named pair bound to @point, or
374 * returns <constant>NULL</constant> if @point is an explicit
375 * pair. The returned value is owned by @point.
377 * Returns: (transfer none): an #AdgModel or <constant>NULL</constant>.
379 * Since: 1.0
381 AdgModel *
382 adg_point_get_model(const AdgPoint *point)
384 g_return_val_if_fail(point != NULL, NULL);
385 return point->model;
389 * adg_point_get_name:
390 * @point: an #AdgPoint
392 * Gets the name of the named pair bound to @point, or
393 * returns <constant>NULL</constant> if @point is an explicit
394 * pair. The returned value is owned by @point and should not
395 * be modified or freed.
397 * Returns: the name of the named pair or <constant>NULL</constant>.
399 * Since: 1.0
401 const gchar *
402 adg_point_get_name(const AdgPoint *point)
404 g_return_val_if_fail(point != NULL, NULL);
405 return point->name;
409 * adg_point_equal:
410 * @point1: the first point to compare
411 * @point2: the second point to compare
413 * Compares @point1 and @point2 and returns <constant>TRUE</constant>
414 * if the points are equals. The comparison is made by checking also
415 * the named pairs they are bound to. If you want to compare only
416 * their coordinates, use cpml_pair_equal() directly on the
417 * #AdgPoint structs:
419 * <informalexample><programlisting language="C">
420 * if (adg_point_update(point1) &&
421 * adg_point_update(point2) &&
422 * cpml_pair_equal((CpmlPair *) point1, (CpmlPair *) point2))
424 * ...
426 * </programlisting></informalexample>
428 * <constant>NULL</constant> points are handled gracefully.
430 * Returns: <constant>TRUE</constant> if @point1 is equal to @point2, <constant>FALSE</constant> otherwise.
432 * Since: 1.0
434 gboolean
435 adg_point_equal(const AdgPoint *point1, const AdgPoint *point2)
437 if (point1 == point2)
438 return TRUE;
440 if (point1 == NULL || point2 == NULL)
441 return FALSE;
443 /* Check if the points are not bound to the same model
444 * or if only one of the two points is explicit */
445 if (point1->model != point2->model)
446 return FALSE;
448 /* Handle points bound to named pairs */
449 if (point1->model != NULL)
450 return g_strcmp0(point1->name, point2->name) == 0;
452 /* Handle points with explicit coordinates */
453 return cpml_pair_equal(&point1->pair, &point2->pair);