doc: updated italian translations
[adg.git] / src / adg / adg-rdim.c
blob712848d6f4af72569caa9bab3e42843a0a22d3bd
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012 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-rdim
23 * @short_description: Radial dimensions
25 * The #AdgRDim entity represents a radial dimension.
27 * Since: 1.0
28 **/
30 /**
31 * AdgRDim:
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
36 * Since: 1.0
37 **/
40 #include "adg-internal.h"
41 #include "adg-container.h"
42 #include "adg-alignment.h"
43 #include "adg-model.h"
44 #include "adg-point.h"
45 #include "adg-trail.h"
46 #include "adg-marker.h"
47 #include "adg-style.h"
48 #include "adg-dim-style.h"
49 #include "adg-textual.h"
50 #include "adg-toy-text.h"
51 #include "adg-dim.h"
52 #include "adg-dim-private.h"
53 #include <math.h>
55 #include "adg-rdim.h"
56 #include "adg-rdim-private.h"
59 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_rdim_parent_class)
60 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_rdim_parent_class)
63 G_DEFINE_TYPE(AdgRDim, adg_rdim, ADG_TYPE_DIM)
65 enum {
66 PROP_0,
67 PROP_VALUE
71 static void _adg_dispose (GObject *object);
72 static void _adg_get_property (GObject *object,
73 guint param_id,
74 GValue *value,
75 GParamSpec *pspec);
76 static void _adg_set_property (GObject *object,
77 guint param_id,
78 const GValue *value,
79 GParamSpec *pspec);
80 static void _adg_global_changed (AdgEntity *entity);
81 static void _adg_local_changed (AdgEntity *entity);
82 static void _adg_invalidate (AdgEntity *entity);
83 static void _adg_arrange (AdgEntity *entity);
84 static void _adg_render (AdgEntity *entity,
85 cairo_t *cr);
86 static gchar * _adg_default_value (AdgDim *dim);
87 static gboolean _adg_update_geometry (AdgRDim *rdim);
88 static void _adg_update_entities (AdgRDim *rdim);
89 static void _adg_clear_trail (AdgRDim *rdim);
90 static void _adg_dispose_trail (AdgRDim *rdim);
91 static void _adg_dispose_marker (AdgRDim *rdim);
92 static CpmlPath * _adg_trail_callback (AdgTrail *trail,
93 gpointer user_data);
96 static void
97 adg_rdim_class_init(AdgRDimClass *klass)
99 GObjectClass *gobject_class;
100 AdgEntityClass *entity_class;
101 AdgDimClass *dim_class;
102 GParamSpec *param, *old_param;
104 gobject_class = (GObjectClass *) klass;
105 entity_class = (AdgEntityClass *) klass;
106 dim_class = (AdgDimClass *) klass;
108 g_type_class_add_private(klass, sizeof(AdgRDimPrivate));
110 gobject_class->dispose = _adg_dispose;
111 gobject_class->get_property = _adg_get_property;
112 gobject_class->set_property = _adg_set_property;
114 entity_class->global_changed = _adg_global_changed;
115 entity_class->local_changed = _adg_local_changed;
116 entity_class->invalidate = _adg_invalidate;
117 entity_class->arrange = _adg_arrange;
118 entity_class->render = _adg_render;
120 dim_class->default_value = _adg_default_value;
122 /* Override #AdgDim:value to prepend "R "
123 * to the default set value template string */
124 old_param = g_object_class_find_property(gobject_class, "value");
125 param = g_param_spec_string(old_param->name,
126 g_param_spec_get_nick(old_param),
127 g_param_spec_get_blurb(old_param),
128 "R <>",
129 old_param->flags);
130 g_object_class_install_property(gobject_class, PROP_VALUE, param);
133 static void
134 adg_rdim_init(AdgRDim *rdim)
136 AdgRDimPrivate *data;
137 cairo_path_data_t move_to, line_to;
139 data = G_TYPE_INSTANCE_GET_PRIVATE(rdim, ADG_TYPE_RDIM, AdgRDimPrivate);
140 move_to.header.type = CPML_MOVE;
141 move_to.header.length = 2;
142 line_to.header.type = CPML_LINE;
143 line_to.header.length = 2;
145 data->trail = NULL;
146 data->marker = NULL;
147 data->geometry_arranged = FALSE;
148 data->radius = -1.;
149 data->shift.base.x = data->shift.base.y = 0;
150 cairo_matrix_init_identity(&data->quote.global_map);
152 data->cpml.path.status = CAIRO_STATUS_INVALID_PATH_DATA;
153 data->cpml.path.data = data->cpml.data;
154 data->cpml.path.num_data = G_N_ELEMENTS(data->cpml.data);
155 data->cpml.path.data[0] = move_to;
156 data->cpml.path.data[2] = line_to;
157 data->cpml.path.data[4] = move_to;
158 data->cpml.path.data[6] = line_to;
160 rdim->data = data;
163 static void
164 _adg_dispose(GObject *object)
166 AdgRDim *rdim = (AdgRDim *) object;
168 _adg_dispose_trail(rdim);
169 _adg_dispose_marker(rdim);
171 if (_ADG_OLD_OBJECT_CLASS->dispose)
172 _ADG_OLD_OBJECT_CLASS->dispose(object);
175 static void
176 _adg_get_property(GObject *object, guint prop_id,
177 GValue *value, GParamSpec *pspec)
179 switch (prop_id) {
180 case PROP_VALUE:
181 g_value_set_string(value, adg_dim_get_value((AdgDim *) object));
182 break;
183 default:
184 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
185 break;
189 static void
190 _adg_set_property(GObject *object, guint prop_id,
191 const GValue *value, GParamSpec *pspec)
193 switch (prop_id) {
194 case PROP_VALUE:
195 adg_dim_set_value((AdgDim *) object, g_value_get_string(value));
196 break;
197 default:
198 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
199 break;
205 * adg_rdim_new:
207 * Creates a new uninitialized radial dimension. To be useful, you
208 * need at least define the center of the arc to quote in #AdgDim:ref1,
209 * a point on the arc in #AdgDim:ref2 and the position of the quote
210 * in #AdgDim:pos using any valid #AdgDim method.
212 * Returns: a newly created quote
214 * Since: 1.0
216 AdgRDim *
217 adg_rdim_new(void)
219 return g_object_new(ADG_TYPE_RDIM, NULL);
223 * adg_rdim_new_full:
224 * @center: allow-none: center of the arc to quote
225 * @radius: allow-none: where the quote must be applied on the arc
226 * @pos: allow-none: position of the quote text
228 * Creates a new quote by specifying explicitely all the needed
229 * data to get a valid quote.
231 * Returns: a newly created quote
233 * Since: 1.0
235 AdgRDim *
236 adg_rdim_new_full(const AdgPair *center, const AdgPair *radius, const AdgPair *pos)
238 AdgRDim *rdim;
239 AdgDim *dim;
241 rdim = adg_rdim_new();
242 dim = (AdgDim *) rdim;
244 if (center != NULL)
245 adg_dim_set_ref1_from_pair(dim, center);
247 if (radius != NULL)
248 adg_dim_set_ref2_from_pair(dim, radius);
250 if (pos != NULL)
251 adg_dim_set_pos_from_pair(dim, pos);
253 return rdim;
257 * adg_rdim_new_full_explicit:
258 * @center_x: x coordinate of the center of the arc to quote
259 * @center_y: y coordinate of the center of the arc to quote
260 * @radius_x: x coordiante where the quote must be applied on the arc
261 * @radius_y: y coordiante where the quote must be applied on the arc
262 * @pos_x: x coordinate of the quote text
263 * @pos_y: y coordinate of the quote text
265 * Does the same job of adg_rdim_full() but using specific coordinates
266 * instead of AdgPair structures.
267 * data to get a valid quote.
269 * Returns: a newly created quote
271 * Since: 1.0
273 AdgRDim *
274 adg_rdim_new_full_explicit(gdouble center_x, gdouble center_y,
275 gdouble radius_x, gdouble radius_y,
276 gdouble pos_x, gdouble pos_y)
278 AdgPair center, radius, pos;
280 center.x = center_x;
281 center.y = center_y;
282 radius.x = radius_x;
283 radius.y = radius_y;
284 pos.x = pos_x;
285 pos.y = pos_y;
287 return adg_rdim_new_full(&center, &radius, &pos);
291 * adg_rdim_new_full_from_model:
292 * @model: transfer-none: the model from which the named pairs are taken
293 * @center: allow-none: the center point of the arc to quote
294 * @radius: allow-none: an arbitrary point on the arc
295 * @pos: allow-none: the position reference
297 * Creates a new radial dimension, specifing all the needed properties in
298 * one shot and using named pairs from @model.
300 * Returns: the newly created radial dimension entity
302 * Since: 1.0
304 AdgRDim *
305 adg_rdim_new_full_from_model(AdgModel *model, const gchar *center,
306 const gchar *radius, const gchar *pos)
308 AdgRDim *rdim;
309 AdgDim *dim;
311 g_return_val_if_fail(model != NULL, NULL);
313 rdim = adg_rdim_new();
314 dim = (AdgDim *) rdim;
316 if (center != NULL)
317 adg_dim_set_ref1_from_model(dim, model, center);
319 if (radius != NULL)
320 adg_dim_set_ref2_from_model(dim, model, radius);
322 if (pos != NULL)
323 adg_dim_set_pos_from_model(dim, model, pos);
325 return rdim;
329 static void
330 _adg_global_changed(AdgEntity *entity)
332 AdgRDimPrivate *data = ((AdgRDim *) entity)->data;
334 _adg_clear_trail((AdgRDim *) entity);
336 if (_ADG_OLD_ENTITY_CLASS->global_changed)
337 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
339 if (data->marker != NULL)
340 adg_entity_global_changed((AdgEntity *) data->marker);
343 static void
344 _adg_local_changed(AdgEntity *entity)
346 _adg_clear_trail((AdgRDim *) entity);
348 if (_ADG_OLD_ENTITY_CLASS->local_changed)
349 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
352 static void
353 _adg_invalidate(AdgEntity *entity)
355 AdgRDim *rdim;
356 AdgRDimPrivate *data;
358 rdim = (AdgRDim *) entity;
359 data = rdim->data;
361 _adg_dispose_trail(rdim);
362 _adg_dispose_marker(rdim);
363 data->geometry_arranged = FALSE;
364 _adg_clear_trail(rdim);
366 if (_ADG_OLD_ENTITY_CLASS->invalidate)
367 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
370 static void
371 _adg_arrange(AdgEntity *entity)
373 AdgRDim *rdim;
374 AdgDim *dim;
375 AdgRDimPrivate *data;
376 AdgAlignment *quote;
377 AdgEntity *quote_entity;
378 gboolean outside;
379 const AdgMatrix *global, *local;
380 AdgPair ref2, base;
381 AdgPair pair;
382 CpmlExtents extents;
384 if (_ADG_OLD_ENTITY_CLASS->arrange != NULL)
385 _ADG_OLD_ENTITY_CLASS->arrange(entity);
387 rdim = (AdgRDim *) entity;
388 dim = (AdgDim *) rdim;
389 data = rdim->data;
390 quote = adg_dim_get_quote(dim);
391 quote_entity = (AdgEntity *) quote;
393 if (!_adg_update_geometry(rdim))
394 return;
396 _adg_update_entities(rdim);
398 /* Check for cached result */
399 if (data->cpml.path.status == CAIRO_STATUS_SUCCESS) {
400 adg_entity_set_global_map(quote_entity, &data->quote.global_map);
401 return;
404 outside = adg_dim_get_outside(dim);
405 if (outside == ADG_THREE_STATE_UNKNOWN)
406 outside = ADG_THREE_STATE_OFF;
408 global = adg_entity_get_global_matrix(entity);
409 local = adg_entity_get_local_matrix(entity);
410 extents.is_defined = FALSE;
412 cpml_pair_copy(&ref2, adg_point_get_pair(adg_dim_get_ref2(dim)));
413 cpml_pair_copy(&base, &data->point.base);
415 cpml_pair_transform(&ref2, local);
416 cpml_pair_transform(&base, local);
417 base.x += data->shift.base.x;
418 base.y += data->shift.base.y;
420 /* baseline start */
421 cpml_pair_to_cairo(&base, &data->cpml.data[1]);
423 /* baseline end */
424 cpml_pair_to_cairo(&ref2, &data->cpml.data[3]);
426 if (outside) {
427 AdgDimStyle *dim_style;
428 gdouble beyond;
429 CpmlVector vector;
431 dim_style = _ADG_GET_DIM_STYLE(dim);
432 beyond = adg_dim_style_get_beyond(dim_style);
433 vector.x = ref2.x - base.x;
434 vector.y = ref2.y - base.y;
435 cpml_vector_set_length(&vector, beyond);
436 pair.x = ref2.x + vector.x;
437 pair.y = ref2.y + vector.y;
439 data->cpml.data[2].header.length = 2;
441 /* Outside segment start */
442 cpml_pair_to_cairo(&pair, &data->cpml.data[5]);
444 /* Outside segment end */
445 cpml_pair_to_cairo(&ref2, &data->cpml.data[7]);
446 } else {
447 data->cpml.data[2].header.length = 6;
450 /* Arrange the quote */
451 if (quote != NULL) {
452 AdgMatrix map;
454 adg_alignment_set_factor_explicit(quote, 1, 0);
456 cpml_pair_from_cairo(&pair, &data->cpml.data[1]);
457 cairo_matrix_init_translate(&map, pair.x, pair.y);
458 cairo_matrix_rotate(&map, data->angle);
459 adg_entity_set_global_map(quote_entity, &map);
460 adg_entity_arrange(quote_entity);
461 cpml_extents_add(&extents, adg_entity_get_extents(quote_entity));
463 adg_matrix_copy(&data->quote.global_map, &map);
466 data->cpml.path.status = CAIRO_STATUS_SUCCESS;
468 /* Arrange the trail */
469 if (data->trail != NULL) {
470 CpmlExtents trail_extents;
471 cpml_extents_copy(&trail_extents, adg_trail_get_extents(data->trail));
472 cpml_extents_transform(&trail_extents, global);
473 cpml_extents_add(&extents, &trail_extents);
474 } else {
475 _adg_dispose_marker(rdim);
478 /* Arrange the marker */
479 if (data->marker != NULL) {
480 AdgEntity *marker_entity = (AdgEntity *) data->marker;
481 adg_marker_set_segment(data->marker, data->trail, outside ? 2 : 1);
482 adg_entity_local_changed(marker_entity);
483 adg_entity_arrange(marker_entity);
484 cpml_extents_add(&extents, adg_entity_get_extents(marker_entity));
487 adg_entity_set_extents(entity, &extents);
490 static void
491 _adg_render(AdgEntity *entity, cairo_t *cr)
493 AdgRDim *rdim;
494 AdgDim *dim;
495 AdgRDimPrivate *data;
496 AdgDimStyle *dim_style;
497 AdgDress dress;
498 const cairo_path_t *cairo_path;
500 rdim = (AdgRDim *) entity;
501 data = rdim->data;
503 if (!data->geometry_arranged) {
504 /* Entity not arranged, probably due to undefined pair found */
505 return;
508 dim = (AdgDim *) entity;
509 dim_style = _ADG_GET_DIM_STYLE(dim);
511 adg_style_apply((AdgStyle *) dim_style, entity, cr);
512 adg_entity_render((AdgEntity *) adg_dim_get_quote(dim), cr);
514 if (data->marker != NULL)
515 adg_entity_render((AdgEntity *) data->marker, cr);
517 cairo_transform(cr, adg_entity_get_global_matrix(entity));
518 dress = adg_dim_style_get_line_dress(dim_style);
519 adg_entity_apply_dress(entity, dress, cr);
521 cairo_path = adg_trail_get_cairo_path(data->trail);
522 cairo_append_path(cr, cairo_path);
523 cairo_stroke(cr);
526 static gchar *
527 _adg_default_value(AdgDim *dim)
529 AdgRDim *rdim;
530 AdgRDimPrivate *data;
531 AdgDimStyle *dim_style;
532 const gchar *format;
534 rdim = (AdgRDim *) dim;
535 data = rdim->data;
536 dim_style = _ADG_GET_DIM_STYLE(dim);
537 format = adg_dim_style_get_number_format(dim_style);
539 if (!_adg_update_geometry(rdim))
540 return g_strdup("undef");
542 return g_strdup_printf(format, data->radius);
545 static gboolean
546 _adg_update_geometry(AdgRDim *rdim)
548 AdgRDimPrivate *data;
549 AdgDim *dim;
550 AdgDimStyle *dim_style;
551 const AdgPair *ref1, *ref2;
552 const AdgPair *pos;
553 gdouble spacing, level, pos_distance;
554 CpmlVector vector;
556 data = rdim->data;
558 if (data->geometry_arranged)
559 return TRUE;
561 dim = (AdgDim *) rdim;
562 ref1 = adg_point_get_pair(adg_dim_get_ref1(dim));
563 ref2 = adg_point_get_pair(adg_dim_get_ref2(dim));
564 pos = adg_point_get_pair(adg_dim_get_pos(dim));
566 if (ref1 == NULL || ref2 == NULL || pos == NULL)
567 return FALSE;
569 dim_style = _ADG_GET_DIM_STYLE(rdim);
570 spacing = adg_dim_style_get_baseline_spacing(dim_style);
571 level = adg_dim_get_level(dim);
572 pos_distance = cpml_pair_distance(pos, ref1);
573 vector.x = ref2->x - ref1->x;
574 vector.y = ref2->y - ref1->y;
576 if (cpml_pair_squared_distance(pos, ref1) <
577 cpml_pair_squared_distance(pos, ref2)) {
578 vector.x = -vector.x;
579 vector.y = -vector.y;
582 /* radius */
583 data->radius = cpml_pair_distance(&vector, NULL);
585 /* angle */
586 data->angle = adg_dim_quote_angle(dim, cpml_vector_angle(&vector));
588 /* point.base */
589 cpml_pair_copy(&data->point.base, &vector);
590 cpml_vector_set_length(&data->point.base, pos_distance);
591 data->point.base.x += ref1->x;
592 data->point.base.y += ref1->y;
594 /* shift.base */
595 cpml_pair_copy(&data->shift.base, &vector);
596 cpml_vector_set_length(&data->shift.base, spacing * level);
598 data->geometry_arranged = TRUE;
600 return TRUE;
603 static void
604 _adg_update_entities(AdgRDim *rdim)
606 AdgEntity *entity;
607 AdgRDimPrivate *data;
608 AdgDimStyle *dim_style;
610 entity = (AdgEntity *) rdim;
611 data = rdim->data;
612 dim_style = _ADG_GET_DIM_STYLE(rdim);
614 if (data->trail == NULL)
615 data->trail = adg_trail_new(_adg_trail_callback, rdim);
617 if (data->marker == NULL) {
618 data->marker = adg_dim_style_marker2_new(dim_style);
619 adg_entity_set_parent((AdgEntity *) data->marker, entity);
623 static void
624 _adg_clear_trail(AdgRDim *rdim)
626 AdgRDimPrivate *data = rdim->data;
628 if (data->trail != NULL)
629 adg_model_clear((AdgModel *) data->trail);
631 data->cpml.path.status = CAIRO_STATUS_INVALID_PATH_DATA;
634 static void
635 _adg_dispose_trail(AdgRDim *rdim)
637 AdgRDimPrivate *data = rdim->data;
639 if (data->trail != NULL) {
640 g_object_unref(data->trail);
641 data->trail = NULL;
645 static void
646 _adg_dispose_marker(AdgRDim *rdim)
648 AdgRDimPrivate *data = rdim->data;
650 if (data->marker != NULL) {
651 g_object_unref(data->marker);
652 data->marker = NULL;
656 static CpmlPath *
657 _adg_trail_callback(AdgTrail *trail, gpointer user_data)
659 AdgRDim *rdim;
660 AdgRDimPrivate *data;
662 rdim = (AdgRDim *) user_data;
663 data = rdim->data;
665 return &data->cpml.path;