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.
23 * @short_description: Angular dimensions
25 * The #AdgADim entity defines an angular dimension.
31 * All fields are privates and should not be used directly.
32 * Use its public methods instead.
36 #include "adg-internal.h"
38 #include "adg-adim-private.h"
39 #include "adg-dim-private.h"
41 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_adim_parent_class)
42 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_adim_parent_class)
45 G_DEFINE_TYPE(AdgADim
, adg_adim
, ADG_TYPE_DIM
);
57 static void _adg_dispose (GObject
*object
);
58 static void _adg_get_property (GObject
*object
,
62 static void _adg_set_property (GObject
*object
,
66 static void _adg_global_changed (AdgEntity
*entity
);
67 static void _adg_local_changed (AdgEntity
*entity
);
68 static void _adg_invalidate (AdgEntity
*entity
);
69 static void _adg_arrange (AdgEntity
*entity
);
70 static void _adg_render (AdgEntity
*entity
,
72 static gchar
* _adg_default_value (AdgDim
*dim
);
73 static void _adg_update_geometry (AdgADim
*adim
);
74 static void _adg_update_entities (AdgADim
*adim
);
75 static void _adg_unset_trail (AdgADim
*adim
);
76 static void _adg_dispose_markers (AdgADim
*adim
);
77 static gboolean
_adg_get_info (AdgADim
*adim
,
81 static CpmlPath
* _adg_trail_callback (AdgTrail
*trail
,
86 adg_adim_class_init(AdgADimClass
*klass
)
88 GObjectClass
*gobject_class
;
89 AdgEntityClass
*entity_class
;
90 AdgDimClass
*dim_class
;
91 GParamSpec
*param
, *old_param
;
93 gobject_class
= (GObjectClass
*) klass
;
94 entity_class
= (AdgEntityClass
*) klass
;
95 dim_class
= (AdgDimClass
*) klass
;
97 g_type_class_add_private(klass
, sizeof(AdgADimPrivate
));
99 gobject_class
->dispose
= _adg_dispose
;
100 gobject_class
->get_property
= _adg_get_property
;
101 gobject_class
->set_property
= _adg_set_property
;
103 entity_class
->global_changed
= _adg_global_changed
;
104 entity_class
->local_changed
= _adg_local_changed
;
105 entity_class
->invalidate
= _adg_invalidate
;
106 entity_class
->arrange
= _adg_arrange
;
107 entity_class
->render
= _adg_render
;
109 dim_class
->default_value
= _adg_default_value
;
111 /* Override #AdgDim:value to append a degree symbol
112 * to the default set value template string */
113 old_param
= g_object_class_find_property(gobject_class
, "value");
114 param
= g_param_spec_string(old_param
->name
,
115 g_param_spec_get_nick(old_param
),
116 g_param_spec_get_blurb(old_param
),
117 "<>" ADG_UTF8_DEGREE
,
119 g_object_class_install_property(gobject_class
, PROP_VALUE
, param
);
121 param
= g_param_spec_boxed("org1",
123 P_("Where the first line comes from: this point is used toghether with \"ref1\" to align the first extension line"),
126 g_object_class_install_property(gobject_class
, PROP_ORG1
, param
);
128 param
= g_param_spec_boxed("org2",
130 P_("Where the second line comes from: this point is used toghether with \"ref2\" to align the second extension line"),
133 g_object_class_install_property(gobject_class
, PROP_ORG2
, param
);
137 adg_adim_init(AdgADim
*adim
)
139 AdgADimPrivate
*data
;
140 cairo_path_data_t move_to
, line_to
, arc_to
;
142 data
= G_TYPE_INSTANCE_GET_PRIVATE(adim
, ADG_TYPE_ADIM
, AdgADimPrivate
);
143 move_to
.header
.type
= CPML_MOVE
;
144 move_to
.header
.length
= 2;
145 line_to
.header
.type
= CPML_LINE
;
146 line_to
.header
.length
= 2;
147 arc_to
.header
.type
= CPML_ARC
;
148 arc_to
.header
.length
= 3;
152 data
->has_extension1
= TRUE
;
153 data
->has_extension2
= TRUE
;
155 data
->cpml
.path
.status
= CAIRO_STATUS_INVALID_PATH_DATA
;
156 data
->cpml
.path
.data
= data
->cpml
.data
;
157 data
->cpml
.path
.num_data
= G_N_ELEMENTS(data
->cpml
.data
);
158 data
->cpml
.path
.data
[0] = move_to
;
159 data
->cpml
.path
.data
[2] = arc_to
;
160 data
->cpml
.path
.data
[5] = move_to
;
161 data
->cpml
.path
.data
[7] = line_to
;
162 data
->cpml
.path
.data
[9] = move_to
;
163 data
->cpml
.path
.data
[11] = line_to
;
166 data
->marker1
= NULL
;
167 data
->marker2
= NULL
;
169 data
->geometry_arranged
= FALSE
;
175 _adg_dispose(GObject
*object
)
178 AdgADimPrivate
*data
;
180 entity
= (AdgEntity
*) object
;
181 data
= ((AdgADim
*) object
)->data
;
183 _adg_dispose_markers((AdgADim
*) object
);
185 if (data
->org1
!= NULL
)
186 data
->org1
= adg_entity_point(entity
, data
->org1
, NULL
);
188 if (data
->org2
!= NULL
)
189 data
->org2
= adg_entity_point(entity
, data
->org2
, NULL
);
191 if (_ADG_OLD_OBJECT_CLASS
->dispose
)
192 _ADG_OLD_OBJECT_CLASS
->dispose(object
);
196 _adg_get_property(GObject
*object
, guint prop_id
,
197 GValue
*value
, GParamSpec
*pspec
)
199 AdgADimPrivate
*data
= ((AdgADim
*) object
)->data
;
203 g_value_set_string(value
, adg_dim_get_value((AdgDim
*) object
));
206 g_value_set_boxed(value
, data
->org1
);
209 g_value_set_boxed(value
, data
->org2
);
211 case PROP_HAS_EXTENSION1
:
212 g_value_set_boolean(value
, data
->has_extension1
);
214 case PROP_HAS_EXTENSION2
:
215 g_value_set_boolean(value
, data
->has_extension2
);
218 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
224 _adg_set_property(GObject
*object
, guint prop_id
,
225 const GValue
*value
, GParamSpec
*pspec
)
228 AdgADimPrivate
*data
;
230 entity
= (AdgEntity
*) object
;
231 data
= ((AdgADim
*) object
)->data
;
235 adg_dim_set_value((AdgDim
*) object
, g_value_get_string(value
));
238 data
->org1
= adg_entity_point(entity
, data
->org1
,
239 g_value_get_boxed(value
));
242 data
->org2
= adg_entity_point(entity
, data
->org2
,
243 g_value_get_boxed(value
));
245 case PROP_HAS_EXTENSION1
:
246 data
->has_extension1
= g_value_get_boolean(value
);
248 case PROP_HAS_EXTENSION2
:
249 data
->has_extension2
= g_value_get_boolean(value
);
252 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
261 * Creates a new - undefined - angular dimension. You must, at least,
262 * define the first line by setting #AdgADim:org1 (start point) and
263 * #AdgDim:ref1 (end point), the second line by setting #AdgADim:org2
264 * (start point) and #AdgDim:ref2 (end point) and the position of
265 * the quote in #AdgDim:pos.
267 * Returns: the newly created angular dimension entity
272 return g_object_new(ADG_TYPE_ADIM
, NULL
);
277 * @ref1: first reference point
278 * @ref2: second reference point
279 * @org1: first origin point
280 * @org2: second origin point
282 * Creates a new angular dimension, specifing all the needed
283 * properties in one shot using #AdgPair.
285 * Returns: the newly created angular dimension entity
288 adg_adim_new_full(const AdgPair
*ref1
, const AdgPair
*ref2
,
289 const AdgPair
*org1
, const AdgPair
*org2
,
295 adim
= g_object_new(ADG_TYPE_ADIM
, NULL
);
296 dim
= (AdgDim
*) adim
;
298 adg_dim_set_ref1_from_pair(dim
, ref1
);
299 adg_dim_set_ref2_from_pair(dim
, ref2
);
300 adg_dim_set_pos_from_pair(dim
, pos
);
301 adg_adim_set_org1_from_pair(adim
, org1
);
302 adg_adim_set_org2_from_pair(adim
, org2
);
308 * adg_adim_new_full_explicit:
309 * @ref1_x: the x coordinate of the first reference point
310 * @ref1_y: the y coordinate of the first reference point
311 * @ref2_x: the x coordinate of the second reference point
312 * @ref2_y: the y coordinate of the second reference point
313 * @direction: angle where to extend the dimension
314 * @pos_x: the x coordinate of the position reference
315 * @pos_y: the y coordinate of the position reference
317 * Wrappes adg_adim_new_full() with explicit values.
319 * Returns: the newly created linear dimension entity
322 adg_adim_new_full_explicit(gdouble ref1_x
, gdouble ref1_y
,
323 gdouble ref2_x
, gdouble ref2_y
,
324 gdouble org1_x
, gdouble org1_y
,
325 gdouble org2_x
, gdouble org2_y
,
326 gdouble pos_x
, gdouble pos_y
)
328 AdgPair ref1
, ref2
, org1
, org2
, pos
;
341 return adg_adim_new_full(&ref1
, &ref2
, &org1
, &org2
, &pos
);
345 * adg_adim_new_full_from_model:
346 * @model: the model from which the named pairs are taken
347 * @ref1: the end point of the first line
348 * @ref2: the end point of the second line
349 * @org1: the origin of the first line
350 * @org2: the origin of the second line
351 * @pos: the position reference
353 * Creates a new angular dimension, specifing all the needed properties
354 * in one shot and using named pairs from @model.
356 * Returns: the newly created angular dimension entity
359 adg_adim_new_full_from_model(AdgModel
*model
,
360 const gchar
*ref1
, const gchar
*ref2
,
361 const gchar
*org1
, const gchar
*org2
,
367 adim
= g_object_new(ADG_TYPE_ADIM
, NULL
);
368 dim
= (AdgDim
*) adim
;
370 adg_dim_set_ref1_from_model(dim
, model
, ref1
);
371 adg_dim_set_ref2_from_model(dim
, model
, ref2
);
372 adg_dim_set_pos_from_model(dim
, model
, pos
);
373 adg_adim_set_org1_from_model(adim
, model
, org1
);
374 adg_adim_set_org2_from_model(adim
, model
, org2
);
382 * @org1: the new point to use as first reference
384 * Sets the #AdgADim:org1 property to @org1. The old point
385 * is silently discarded, unreferencing its model if that
386 * point was bound to a named pair (hence, possibly destroying
387 * the model if this was the last reference).
389 * @org1 can be %NULL, in which case the point is destroyed.
392 adg_adim_set_org1(AdgADim
*adim
, const AdgPoint
*org1
)
394 g_return_if_fail(ADG_IS_ADIM(adim
));
395 g_object_set((GObject
*) adim
, "org1", org1
, NULL
);
399 * adg_adim_set_org1_explicit:
401 * @x: x coordinate of the first reference point
402 * @y: y coordinate of the first reference point
404 * Sets the #AdgADim:org1 property to the (@x, @y) explicit
405 * coordinates. The old point is silently discarded,
406 * unreferencing its model if that point was bound to a named
407 * pair (hence, possibly destroying the model if this was the
411 adg_adim_set_org1_explicit(AdgADim
*adim
, gdouble x
, gdouble y
)
413 AdgPoint
*point
= adg_point_new();
415 adg_point_set_pair_explicit(point
, x
, y
);
416 adg_adim_set_org1(adim
, point
);
418 adg_point_destroy(point
);
422 * adg_adim_set_org1_from_pair:
424 * @org1: the coordinates pair of the first reference point
426 * Convenient function to set the #AdgADim:org1 property using a
427 * pair instead of explicit coordinates.
430 adg_adim_set_org1_from_pair(AdgADim
*adim
, const AdgPair
*org1
)
432 g_return_if_fail(org1
!= NULL
);
434 adg_adim_set_org1_explicit(adim
, org1
->x
, org1
->y
);
438 * adg_adim_set_org1_from_model:
440 * @model: the source #AdgModel
441 * @org1: a named pair in @model
443 * Binds #AdgADim:org1 to the @org1 named pair of @model. If @model
444 * is %NULL, the point will be unset. In any case, the old point
445 * is silently discarded, unreferencing its model if that point
446 * was bound to a named pair (hence, possibly destroying the model
447 * if this was the last reference).
449 * The assignment is lazy so @org1 could be not be present in @model.
450 * Anyway, at the first access to this point an error will be raised
451 * if the named pair is still missing.
454 adg_adim_set_org1_from_model(AdgADim
*adim
, AdgModel
*model
, const gchar
*org1
)
456 AdgPoint
*point
= adg_point_new();
458 adg_point_set_pair_from_model(point
, model
, org1
);
459 adg_adim_set_org1(adim
, point
);
461 adg_point_destroy(point
);
468 * Gets the #AdgADim:org1 point. The returned point is internally owned
469 * and must not be freed or modified. Anyway, it is not const because
470 * adg_point_get_pair() must be able to modify the internal cache of
471 * the returned point.
473 * Returns: the first reference point
476 adg_adim_get_org1(AdgADim
*adim
)
478 AdgADimPrivate
*data
;
480 g_return_val_if_fail(ADG_IS_ADIM(adim
), NULL
);
490 * @org2: the new point to use as first reference
492 * Sets the #AdgADim:org2 property to @org2. The old point
493 * is silently discarded, unreferencing its model if that
494 * point was bound to a named pair (hence, possibly destroying
495 * the model if this was the last reference).
497 * @org2 can be %NULL, in which case the point is destroyed.
500 adg_adim_set_org2(AdgADim
*adim
, const AdgPoint
*org2
)
502 g_return_if_fail(ADG_IS_ADIM(adim
));
503 g_object_set((GObject
*) adim
, "org2", org2
, NULL
);
507 * adg_adim_set_org2_explicit:
509 * @x: x coordinate of the first reference point
510 * @y: y coordinate of the first reference point
512 * Sets the #AdgADim:org2 property to the (@x, @y) explicit
513 * coordinates. The old point is silently discarded,
514 * unreferencing its model if that point was bound to a named
515 * pair (hence, possibly destroying the model if this was the
519 adg_adim_set_org2_explicit(AdgADim
*adim
, gdouble x
, gdouble y
)
521 AdgPoint
*point
= adg_point_new();
523 adg_point_set_pair_explicit(point
, x
, y
);
524 adg_adim_set_org2(adim
, point
);
526 adg_point_destroy(point
);
530 * adg_adim_set_org2_from_pair:
532 * @org2: the coordinates pair of the first reference point
534 * Convenient function to set the #AdgADim:org2 property using a
535 * pair instead of explicit coordinates.
538 adg_adim_set_org2_from_pair(AdgADim
*adim
, const AdgPair
*org2
)
540 g_return_if_fail(org2
!= NULL
);
542 adg_adim_set_org2_explicit(adim
, org2
->x
, org2
->y
);
546 * adg_adim_set_org2_from_model:
548 * @model: the source #AdgModel
549 * @org2: a named pair in @model
551 * Binds #AdgADim:org2 to the @org2 named pair of @model. If @model
552 * is %NULL, the point will be unset. In any case, the old point
553 * is silently discarded, unreferencing its model if that point
554 * was bound to a named pair (hence, possibly destroying the model
555 * if this was the last reference).
557 * The assignment is lazy so @org2 could be not be present in @model.
558 * Anyway, at the first access to this point an error will be raised
559 * if the named pair is still missing.
562 adg_adim_set_org2_from_model(AdgADim
*adim
, AdgModel
*model
, const gchar
*org2
)
564 AdgPoint
*point
= adg_point_new();
566 adg_point_set_pair_from_model(point
, model
, org2
);
567 adg_adim_set_org2(adim
, point
);
569 adg_point_destroy(point
);
576 * Gets the #AdgADim:org2 point. The returned point is internally owned
577 * and must not be freed or modified. Anyway, it is not const because
578 * adg_point_get_pair() must be able to modify the internal cache of
579 * the returned point.
581 * Returns: the first reference point
584 adg_adim_get_org2(AdgADim
*adim
)
586 AdgADimPrivate
*data
;
588 g_return_val_if_fail(ADG_IS_ADIM(adim
), NULL
);
597 _adg_global_changed(AdgEntity
*entity
)
599 AdgADimPrivate
*data
= ((AdgADim
*) entity
)->data
;
601 _adg_unset_trail((AdgADim
*) entity
);
603 if (_ADG_OLD_ENTITY_CLASS
->global_changed
)
604 _ADG_OLD_ENTITY_CLASS
->global_changed(entity
);
606 if (data
->marker1
!= NULL
)
607 adg_entity_global_changed((AdgEntity
*) data
->marker1
);
609 if (data
->marker2
!= NULL
)
610 adg_entity_global_changed((AdgEntity
*) data
->marker2
);
614 _adg_local_changed(AdgEntity
*entity
)
616 _adg_unset_trail((AdgADim
*) entity
);
618 if (_ADG_OLD_ENTITY_CLASS
->local_changed
)
619 _ADG_OLD_ENTITY_CLASS
->local_changed(entity
);
623 _adg_invalidate(AdgEntity
*entity
)
626 AdgADimPrivate
*data
;
628 adim
= (AdgADim
*) entity
;
631 _adg_dispose_markers(adim
);
632 data
->geometry_arranged
= FALSE
;
633 _adg_unset_trail(adim
);
636 adg_point_invalidate(data
->org1
);
638 adg_point_invalidate(data
->org2
);
640 if (_ADG_OLD_ENTITY_CLASS
->invalidate
)
641 _ADG_OLD_ENTITY_CLASS
->invalidate(entity
);
645 _adg_arrange(AdgEntity
*entity
)
649 AdgADimPrivate
*data
;
651 const AdgMatrix
*local
;
652 AdgPair ref1
, ref2
, base1
, base12
, base2
;
655 if (_ADG_OLD_ENTITY_CLASS
->arrange
)
656 _ADG_OLD_ENTITY_CLASS
->arrange(entity
);
658 adim
= (AdgADim
*) entity
;
659 dim
= (AdgDim
*) adim
;
661 quote
= adg_dim_get_quote(dim
);
663 _adg_update_geometry(adim
);
664 _adg_update_entities(adim
);
666 if (data
->cpml
.path
.status
== CAIRO_STATUS_SUCCESS
) {
667 AdgEntity
*quote_entity
= (AdgEntity
*) quote
;
668 adg_entity_set_global_map(quote_entity
, &data
->quote
.global_map
);
672 local
= adg_entity_get_local_matrix(entity
);
673 cpml_pair_copy(&ref1
, adg_point_get_pair(adg_dim_get_ref1(dim
)));
674 cpml_pair_copy(&ref2
, adg_point_get_pair(adg_dim_get_ref2(dim
)));
675 cpml_pair_copy(&base1
, &data
->point
.base1
);
676 cpml_pair_copy(&base12
, &data
->point
.base12
);
677 cpml_pair_copy(&base2
, &data
->point
.base2
);
679 /* Apply the local matrix to the relevant points */
680 cpml_pair_transform(&ref1
, local
);
681 cpml_pair_transform(&ref2
, local
);
682 cpml_pair_transform(&base1
, local
);
683 cpml_pair_transform(&base12
, local
);
684 cpml_pair_transform(&base2
, local
);
686 /* Combine points and global shifts to build the path */
687 pair
.x
= ref1
.x
+ data
->shift
.from1
.x
;
688 pair
.y
= ref1
.y
+ data
->shift
.from1
.y
;
689 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[6]);
691 pair
.x
= base1
.x
+ data
->shift
.base1
.x
;
692 pair
.y
= base1
.y
+ data
->shift
.base1
.y
;
693 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[1]);
695 pair
.x
+= data
->shift
.to1
.x
;
696 pair
.y
+= data
->shift
.to1
.y
;
697 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[8]);
699 pair
.x
= base12
.x
+ data
->shift
.base12
.x
;
700 pair
.y
= base12
.y
+ data
->shift
.base12
.y
;
701 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[3]);
703 pair
.x
= ref2
.x
+ data
->shift
.from2
.x
;
704 pair
.y
= ref2
.y
+ data
->shift
.from2
.y
;
705 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[10]);
707 pair
.x
= base2
.x
+ data
->shift
.base2
.x
;
708 pair
.y
= base2
.y
+ data
->shift
.base2
.y
;
709 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[4]);
711 pair
.x
+= data
->shift
.to2
.x
;
712 pair
.y
+= data
->shift
.to2
.y
;
713 cpml_pair_to_cairo(&pair
, &data
->cpml
.data
[12]);
715 data
->cpml
.path
.status
= CAIRO_STATUS_SUCCESS
;
718 /* Update global and local map of the quote */
719 AdgEntity
*quote_entity
;
723 quote_entity
= (AdgEntity
*) quote
;
724 angle
= adg_dim_quote_angle(dim
, (data
->angle1
+ data
->angle2
) / 2 + G_PI_2
);
725 cpml_pair_from_cairo(&pair
, &data
->cpml
.data
[3]);
727 adg_alignment_set_factor_explicit(quote
, 0.5, 0);
729 cairo_matrix_init_translate(&map
, pair
.x
, pair
.y
);
730 cairo_matrix_rotate(&map
, angle
);
731 adg_entity_set_global_map(quote_entity
, &map
);
733 adg_matrix_copy(&data
->quote
.global_map
,
734 adg_entity_get_global_map(quote_entity
));
737 /* Signal to the markers (if any) that the path has changed */
738 if (data
->marker1
!= NULL
) {
739 adg_marker_set_segment(data
->marker1
, data
->trail
, 1);
740 adg_entity_local_changed((AdgEntity
*) data
->marker1
);
743 if (data
->marker2
!= NULL
) {
744 adg_marker_set_segment(data
->marker2
, data
->trail
, 1);
745 adg_entity_local_changed((AdgEntity
*) data
->marker2
);
748 /* TODO: compute the extents */
752 _adg_render(AdgEntity
*entity
, cairo_t
*cr
)
756 AdgADimPrivate
*data
;
757 AdgDimStyle
*dim_style
;
759 const cairo_path_t
*cairo_path
;
761 adim
= (AdgADim
*) entity
;
762 dim
= (AdgDim
*) entity
;
764 dim_style
= _ADG_GET_DIM_STYLE(dim
);
766 adg_style_apply((AdgStyle
*) dim_style
, entity
, cr
);
767 adg_entity_render((AdgEntity
*) adg_dim_get_quote(dim
), cr
);
769 if (data
->marker1
!= NULL
)
770 adg_entity_render((AdgEntity
*) data
->marker1
, cr
);
771 if (data
->marker2
!= NULL
)
772 adg_entity_render((AdgEntity
*) data
->marker2
, cr
);
774 cairo_transform(cr
, adg_entity_get_global_matrix(entity
));
775 dress
= adg_dim_style_get_line_dress(dim_style
);
776 adg_entity_apply_dress(entity
, dress
, cr
);
778 cairo_path
= adg_trail_get_cairo_path(data
->trail
);
779 cairo_append_path(cr
, cairo_path
);
784 _adg_default_value(AdgDim
*dim
)
787 AdgADimPrivate
*data
;
788 AdgDimStyle
*dim_style
;
792 adim
= (AdgADim
*) dim
;
794 dim_style
= _ADG_GET_DIM_STYLE(dim
);
795 format
= adg_dim_style_get_number_format(dim_style
);
797 _adg_update_geometry(adim
);
798 angle
= (data
->angle2
- data
->angle1
) * 180 / M_PI
;
800 return g_strdup_printf(format
, angle
);
803 /* With "geometry" is considered any data (point, vector or angle)
804 * that can be cached: this is strictly related on how the arrange()
807 _adg_update_geometry(AdgADim
*adim
)
809 AdgADimPrivate
*data
;
810 AdgDimStyle
*dim_style
;
811 gdouble from_offset
, to_offset
;
812 gdouble spacing
, level
;
813 CpmlVector vector
[3];
819 if (data
->geometry_arranged
)
822 if (!_adg_get_info(adim
, vector
, ¢er
, &distance
)) {
823 /* Parallel lines: hang with an error message */
824 g_warning("%s: trying to set an angular dimension on parallel lines",
829 dim_style
= _ADG_GET_DIM_STYLE(adim
);
830 from_offset
= adg_dim_style_get_from_offset(dim_style
);
831 to_offset
= adg_dim_style_get_to_offset(dim_style
);
832 spacing
= adg_dim_style_get_baseline_spacing(dim_style
);
833 level
= adg_dim_get_level((AdgDim
*) adim
);
836 cpml_vector_set_length(&vector
[0], from_offset
);
837 cpml_pair_copy(&data
->shift
.from1
, &vector
[0]);
840 cpml_vector_set_length(&vector
[0], level
* spacing
);
841 cpml_pair_copy(&data
->shift
.base1
, &vector
[0]);
844 cpml_vector_set_length(&vector
[0], to_offset
);
845 cpml_pair_copy(&data
->shift
.to1
, &vector
[0]);
848 cpml_vector_set_length(&vector
[2], from_offset
);
849 cpml_pair_copy(&data
->shift
.from2
, &vector
[2]);
852 cpml_vector_set_length(&vector
[2], level
* spacing
);
853 cpml_pair_copy(&data
->shift
.base2
, &vector
[2]);
856 cpml_vector_set_length(&vector
[2], to_offset
);
857 cpml_pair_copy(&data
->shift
.to2
, &vector
[2]);
860 cpml_vector_set_length(&vector
[1], level
* spacing
);
861 cpml_pair_copy(&data
->shift
.base12
, &vector
[1]);
863 /* Distance can be 0, so the following will leave the
864 * vector array in undefined state */
867 cpml_vector_set_length(&vector
[0], distance
);
868 data
->point
.base1
.x
= vector
[0].x
+ center
.x
;
869 data
->point
.base1
.y
= vector
[0].y
+ center
.y
;
872 cpml_vector_set_length(&vector
[2], distance
);
873 data
->point
.base2
.x
= vector
[2].x
+ center
.x
;
874 data
->point
.base2
.y
= vector
[2].y
+ center
.y
;
877 cpml_vector_set_length(&vector
[1], distance
);
878 data
->point
.base12
.x
= vector
[1].x
+ center
.x
;
879 data
->point
.base12
.y
= vector
[1].y
+ center
.y
;
881 data
->geometry_arranged
= TRUE
;
885 _adg_update_entities(AdgADim
*adim
)
888 AdgADimPrivate
*data
;
889 AdgDimStyle
*dim_style
;
891 entity
= (AdgEntity
*) adim
;
893 dim_style
= _ADG_GET_DIM_STYLE(adim
);
895 if (data
->trail
== NULL
)
896 data
->trail
= adg_trail_new(_adg_trail_callback
, adim
);
898 if (data
->marker1
== NULL
) {
899 data
->marker1
= adg_dim_style_marker1_new(dim_style
);
900 adg_entity_set_parent((AdgEntity
*) data
->marker1
, entity
);
903 if (data
->marker2
== NULL
) {
904 data
->marker2
= adg_dim_style_marker2_new(dim_style
);
905 adg_entity_set_parent((AdgEntity
*) data
->marker2
, entity
);
910 _adg_unset_trail(AdgADim
*adim
)
912 AdgADimPrivate
*data
= adim
->data
;
914 if (data
->trail
!= NULL
)
915 adg_model_clear((AdgModel
*) data
->trail
);
917 data
->cpml
.path
.status
= CAIRO_STATUS_INVALID_PATH_DATA
;
921 _adg_dispose_markers(AdgADim
*adim
)
923 AdgADimPrivate
*data
= adim
->data
;
925 if (data
->trail
!= NULL
) {
926 g_object_unref(data
->trail
);
930 if (data
->marker1
!= NULL
) {
931 g_object_unref(data
->marker1
);
932 data
->marker1
= NULL
;
935 if (data
->marker2
!= NULL
) {
936 g_object_unref(data
->marker2
);
937 data
->marker2
= NULL
;
942 _adg_get_info(AdgADim
*adim
, CpmlVector vector
[],
943 AdgPair
*center
, gdouble
*distance
)
946 AdgADimPrivate
*data
;
947 const AdgPair
*ref1
, *ref2
;
948 const AdgPair
*org1
, *org2
;
951 dim
= (AdgDim
*) adim
;
953 ref1
= adg_point_get_pair(adg_dim_get_ref1(dim
));
954 ref2
= adg_point_get_pair(adg_dim_get_ref2(dim
));
955 org1
= adg_point_get_pair(data
->org1
);
956 org2
= adg_point_get_pair(data
->org2
);
958 vector
[0].x
= ref1
->x
- org1
->x
;
959 vector
[0].y
= ref1
->y
- org1
->y
;
960 vector
[2].x
= ref2
->x
- org2
->x
;
961 vector
[2].y
= ref2
->y
- org2
->y
;
963 factor
= vector
[0].x
* vector
[2].y
- vector
[0].y
* vector
[2].x
;
967 factor
= ((ref1
->y
- ref2
->y
) * vector
[2].x
-
968 (ref1
->x
- ref2
->x
) * vector
[2].y
) / factor
;
970 center
->x
= ref1
->x
+ vector
[0].x
* factor
;
971 center
->y
= ref1
->y
+ vector
[0].y
* factor
;
972 *distance
= cpml_pair_distance(center
, adg_point_get_pair(adg_dim_get_pos(dim
)));
973 data
->angle1
= cpml_vector_angle(&vector
[0]);
974 data
->angle2
= cpml_vector_angle(&vector
[2]);
975 while (data
->angle2
< data
->angle1
)
976 data
->angle2
+= M_PI
* 2;
978 cpml_vector_from_angle(&vector
[1], (data
->angle1
+ data
->angle2
) / 2);
984 _adg_trail_callback(AdgTrail
*trail
, gpointer user_data
)
987 AdgADimPrivate
*data
;
989 adim
= (AdgADim
*) user_data
;
992 return &data
->cpml
.path
;