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: Linear dimensions
25 * The #AdgRDim entity represents a linear dimension.
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
36 #include "adg-internal.h"
38 #include "adg-rdim-private.h"
39 #include "adg-dim-private.h"
40 #include "adg-dim-style.h"
42 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_rdim_parent_class)
43 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_rdim_parent_class)
46 G_DEFINE_TYPE(AdgRDim
, adg_rdim
, ADG_TYPE_DIM
);
54 static void dispose (GObject
*object
);
55 static void _adg_get_property (GObject
*object
,
59 static void _adg_set_property (GObject
*object
,
63 static void _adg_global_changed (AdgEntity
*entity
);
64 static void _adg_local_changed (AdgEntity
*entity
);
65 static void invalidate (AdgEntity
*entity
);
66 static void arrange (AdgEntity
*entity
);
67 static void render (AdgEntity
*entity
,
69 static gchar
* default_value (AdgDim
*dim
);
70 static void update_geometry (AdgRDim
*rdim
);
71 static void update_entities (AdgRDim
*rdim
);
72 static void unset_trail (AdgRDim
*rdim
);
73 static void dispose_marker (AdgRDim
*rdim
);
74 static CpmlPath
* trail_callback (AdgTrail
*trail
,
79 adg_rdim_class_init(AdgRDimClass
*klass
)
81 GObjectClass
*gobject_class
;
82 AdgEntityClass
*entity_class
;
83 AdgDimClass
*dim_class
;
84 GParamSpec
*param
, *old_param
;
86 gobject_class
= (GObjectClass
*) klass
;
87 entity_class
= (AdgEntityClass
*) klass
;
88 dim_class
= (AdgDimClass
*) klass
;
90 g_type_class_add_private(klass
, sizeof(AdgRDimPrivate
));
92 gobject_class
->dispose
= dispose
;
93 gobject_class
->get_property
= _adg_get_property
;
94 gobject_class
->set_property
= _adg_set_property
;
96 entity_class
->global_changed
= _adg_global_changed
;
97 entity_class
->local_changed
= _adg_local_changed
;
98 entity_class
->invalidate
= invalidate
;
99 entity_class
->arrange
= arrange
;
100 entity_class
->render
= render
;
102 dim_class
->default_value
= default_value
;
104 /* Override #AdgDim:value to prepend "R "
105 * to the default set value template string */
106 old_param
= g_object_class_find_property(gobject_class
, "value");
107 param
= g_param_spec_string(old_param
->name
,
108 g_param_spec_get_nick(old_param
),
109 g_param_spec_get_blurb(old_param
),
112 g_object_class_install_property(gobject_class
, PROP_VALUE
, param
);
116 adg_rdim_init(AdgRDim
*rdim
)
118 AdgRDimPrivate
*data
;
119 cairo_path_data_t move_to
, line_to
;
121 data
= G_TYPE_INSTANCE_GET_PRIVATE(rdim
, ADG_TYPE_RDIM
, AdgRDimPrivate
);
122 move_to
.header
.type
= CPML_MOVE
;
123 move_to
.header
.length
= 2;
124 line_to
.header
.type
= CPML_LINE
;
125 line_to
.header
.length
= 2;
129 data
->geometry_arranged
= FALSE
;
131 data
->shift
.base
.x
= data
->shift
.base
.y
= 0;
132 cairo_matrix_init_identity(&data
->quote
.global_map
);
134 data
->cpml
.path
.status
= CAIRO_STATUS_INVALID_PATH_DATA
;
135 data
->cpml
.path
.data
= data
->cpml
.data
;
136 data
->cpml
.path
.num_data
= G_N_ELEMENTS(data
->cpml
.data
);
137 data
->cpml
.path
.data
[0] = move_to
;
138 data
->cpml
.path
.data
[2] = line_to
;
139 data
->cpml
.path
.data
[4] = move_to
;
140 data
->cpml
.path
.data
[6] = line_to
;
146 dispose(GObject
*object
)
148 dispose_marker((AdgRDim
*) object
);
150 if (PARENT_OBJECT_CLASS
->dispose
)
151 PARENT_OBJECT_CLASS
->dispose(object
);
155 _adg_get_property(GObject
*object
, guint prop_id
,
156 GValue
*value
, GParamSpec
*pspec
)
160 g_value_set_string(value
, adg_dim_get_value((AdgDim
*) object
));
163 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
169 _adg_set_property(GObject
*object
, guint prop_id
,
170 const GValue
*value
, GParamSpec
*pspec
)
174 adg_dim_set_value((AdgDim
*) object
, g_value_get_string(value
));
177 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
186 * Creates a new uninitialized radial dimension. To be useful, you
187 * need at least define the center of the arc to quote in #AdgDim:ref1,
188 * a point on the arc in #AdgDim:ref2 and the position of the quote
189 * in #AdgDim:pos using any valid #AdgDim method.
191 * Returns: a newly created quote
196 return g_object_new(ADG_TYPE_RDIM
, NULL
);
201 * @center: center of the arc to quote
202 * @radius: where the quote must be applied on the arc
203 * @pos: position of the quote text
205 * Creates a new quote by specifying explicitely all the needed
206 * data to get a valid quote.
208 * Returns: a newly created quote
211 adg_rdim_new_full(const AdgPair
*center
, const AdgPair
*radius
,
217 rdim
= adg_rdim_new();
218 dim
= (AdgDim
*) rdim
;
220 adg_dim_set_ref1_from_pair(dim
, center
);
221 adg_dim_set_ref2_from_pair(dim
, radius
);
222 adg_dim_set_pos_from_pair(dim
, pos
);
228 * adg_rdim_new_full_explicit:
229 * @center_x: x coordinate of the center of the arc to quote
230 * @center_y: y coordinate of the center of the arc to quote
231 * @radius_x: x coordiante where the quote must be applied on the arc
232 * @radius_y: y coordiante where the quote must be applied on the arc
233 * @pos_x: x coordinate of the quote text
234 * @pos_y: y coordinate of the quote text
236 * Does the same job of adg_rdim_full() but using specific coordinates
237 * instead of AdgPair structures.
238 * data to get a valid quote.
240 * Returns: a newly created quote
243 adg_rdim_new_full_explicit(gdouble center_x
, gdouble center_y
,
244 gdouble radius_x
, gdouble radius_y
,
245 gdouble pos_x
, gdouble pos_y
)
247 AdgPair center
, radius
, pos
;
256 return adg_rdim_new_full(¢er
, &radius
, &pos
);
260 * adg_rdim_new_full_from_model:
261 * @model: the model from which the named pairs are taken
262 * @center: the center point of the arc to quote
263 * @radius: an arbitrary point on the arc
264 * @pos: the position reference
266 * Creates a new radial dimension, specifing all the needed properties in
267 * one shot and using named pairs from @model.
269 * Returns: the newly created radial dimension entity
272 adg_rdim_new_full_from_model(AdgModel
*model
, const gchar
*center
,
273 const gchar
*radius
, const gchar
*pos
)
275 AdgDim
*dim
= g_object_new(ADG_TYPE_RDIM
, NULL
);
277 adg_dim_set_ref1_from_model(dim
, model
, center
);
278 adg_dim_set_ref2_from_model(dim
, model
, radius
);
279 adg_dim_set_pos_from_model(dim
, model
, pos
);
281 return (AdgRDim
*) dim
;
286 _adg_global_changed(AdgEntity
*entity
)
288 AdgRDimPrivate
*data
= ((AdgRDim
*) entity
)->data
;
290 unset_trail((AdgRDim
*) entity
);
292 if (PARENT_ENTITY_CLASS
->global_changed
)
293 PARENT_ENTITY_CLASS
->global_changed(entity
);
295 if (data
->marker
!= NULL
)
296 adg_entity_global_changed((AdgEntity
*) data
->marker
);
300 _adg_local_changed(AdgEntity
*entity
)
302 unset_trail((AdgRDim
*) entity
);
304 if (PARENT_ENTITY_CLASS
->local_changed
)
305 PARENT_ENTITY_CLASS
->local_changed(entity
);
309 invalidate(AdgEntity
*entity
)
312 AdgRDimPrivate
*data
;
314 rdim
= (AdgRDim
*) entity
;
317 dispose_marker(rdim
);
318 data
->geometry_arranged
= FALSE
;
321 if (PARENT_ENTITY_CLASS
->invalidate
)
322 PARENT_ENTITY_CLASS
->invalidate(entity
);
326 arrange(AdgEntity
*entity
)
330 AdgRDimPrivate
*data
;
332 AdgDimStyle
*dim_style
;
334 const AdgMatrix
*local
;
335 AdgPair ref1
, ref2
, base
;
338 if (PARENT_ENTITY_CLASS
->arrange
)
339 PARENT_ENTITY_CLASS
->arrange(entity
);
341 rdim
= (AdgRDim
*) entity
;
342 dim
= (AdgDim
*) rdim
;
344 quote
= adg_dim_get_quote(dim
);
346 update_geometry(rdim
);
347 update_entities(rdim
);
349 if (data
->cpml
.path
.status
== CAIRO_STATUS_SUCCESS
) {
350 AdgEntity
*quote_entity
= (AdgEntity
*) quote
;
351 adg_entity_set_global_map(quote_entity
, &data
->quote
.global_map
);
355 dim_style
= _ADG_GET_DIM_STYLE(dim
);
356 outside
= adg_dim_get_outside(dim
);
357 if (outside
== ADG_THREE_STATE_UNKNOWN
)
358 outside
= ADG_THREE_STATE_OFF
;
360 local
= adg_entity_get_local_matrix(entity
);
361 cpml_pair_copy(&ref1
, adg_point_get_pair(adg_dim_get_ref1(dim
)));
362 cpml_pair_copy(&ref2
, adg_point_get_pair(adg_dim_get_ref2(dim
)));
363 cpml_pair_copy(&base
, &data
->point
.base
);
365 cpml_pair_transform(&ref1
, local
);
366 cpml_pair_transform(&ref2
, local
);
367 cpml_pair_transform(&base
, local
);
368 base
.x
+= data
->shift
.base
.x
;
369 base
.y
+= data
->shift
.base
.y
;
372 cpml_pair_to_cairo(&base
, &data
->cpml
.data
[1]);
375 cpml_pair_to_cairo(&ref2
, &data
->cpml
.data
[3]);
378 data
->cpml
.data
[2].header
.length
= 2;
379 /* TODO: outside radius dimensions */
381 data
->cpml
.data
[2].header
.length
= 6;
384 data
->cpml
.path
.status
= CAIRO_STATUS_SUCCESS
;
387 AdgEntity
*quote_entity
;
390 quote_entity
= (AdgEntity
*) quote
;
391 cpml_pair_from_cairo(&pair
, &data
->cpml
.data
[1]);
393 adg_alignment_set_factor_explicit(quote
, 1, 0);
395 cairo_matrix_init_translate(&map
, pair
.x
, pair
.y
);
396 cairo_matrix_rotate(&map
, data
->angle
);
397 adg_entity_set_global_map(quote_entity
, &map
);
399 adg_matrix_copy(&data
->quote
.global_map
,
400 adg_entity_get_global_map(quote_entity
));
403 if (data
->marker
!= NULL
) {
404 adg_marker_set_segment(data
->marker
, data
->trail
, outside
? 2 : 1);
405 adg_entity_local_changed((AdgEntity
*) data
->marker
);
408 /* TODO: compute the extents */
412 render(AdgEntity
*entity
, cairo_t
*cr
)
416 AdgRDimPrivate
*data
;
417 AdgDimStyle
*dim_style
;
419 const cairo_path_t
*cairo_path
;
421 rdim
= (AdgRDim
*) entity
;
422 dim
= (AdgDim
*) entity
;
424 dim_style
= _ADG_GET_DIM_STYLE(dim
);
426 adg_style_apply((AdgStyle
*) dim_style
, entity
, cr
);
428 if (data
->marker
!= NULL
)
429 adg_entity_render((AdgEntity
*) data
->marker
, cr
);
431 adg_entity_render((AdgEntity
*) adg_dim_get_quote(dim
), cr
);
433 dress
= adg_dim_style_get_line_dress(dim_style
);
434 adg_entity_apply_dress(entity
, dress
, cr
);
436 cairo_path
= adg_trail_get_cairo_path(data
->trail
);
437 cairo_append_path(cr
, cairo_path
);
442 default_value(AdgDim
*dim
)
445 AdgRDimPrivate
*data
;
446 AdgDimStyle
*dim_style
;
449 rdim
= (AdgRDim
*) dim
;
451 dim_style
= _ADG_GET_DIM_STYLE(dim
);
452 format
= adg_dim_style_get_number_format(dim_style
);
454 update_geometry(rdim
);
456 return g_strdup_printf(format
, data
->radius
);
460 update_geometry(AdgRDim
*rdim
)
462 AdgRDimPrivate
*data
;
464 AdgDimStyle
*dim_style
;
465 const AdgPair
*ref1
, *ref2
;
467 gdouble spacing
, level
, pos_distance
;
472 if (data
->geometry_arranged
)
475 dim
= (AdgDim
*) rdim
;
476 dim_style
= _ADG_GET_DIM_STYLE(rdim
);
477 ref1
= adg_point_get_pair(adg_dim_get_ref1(dim
));
478 ref2
= adg_point_get_pair(adg_dim_get_ref2(dim
));
479 pos
= adg_point_get_pair(adg_dim_get_pos(dim
));
480 spacing
= adg_dim_style_get_baseline_spacing(dim_style
);
481 level
= adg_dim_get_level(dim
);
482 pos_distance
= cpml_pair_distance(pos
, ref1
);
483 vector
.x
= ref2
->x
- ref1
->x
;
484 vector
.y
= ref2
->y
- ref1
->y
;
485 if (cpml_pair_squared_distance(pos
, ref1
) <
486 cpml_pair_squared_distance(pos
, ref2
)) {
487 vector
.x
= -vector
.x
;
488 vector
.y
= -vector
.y
;
492 data
->radius
= cpml_pair_distance(&vector
, NULL
);
495 data
->angle
= adg_dim_quote_angle(dim
, cpml_vector_angle(&vector
));
498 cpml_pair_copy(&data
->point
.base
, &vector
);
499 cpml_vector_set_length(&data
->point
.base
, pos_distance
);
500 data
->point
.base
.x
+= ref1
->x
;
501 data
->point
.base
.y
+= ref1
->y
;
504 cpml_pair_copy(&data
->shift
.base
, &vector
);
505 cpml_vector_set_length(&data
->shift
.base
, spacing
* level
);
507 data
->geometry_arranged
= TRUE
;
511 update_entities(AdgRDim
*rdim
)
514 AdgRDimPrivate
*data
;
515 AdgDimStyle
*dim_style
;
517 entity
= (AdgEntity
*) rdim
;
519 dim_style
= _ADG_GET_DIM_STYLE(rdim
);
521 if (data
->trail
== NULL
)
522 data
->trail
= adg_trail_new(trail_callback
, rdim
);
524 if (data
->marker
== NULL
) {
525 data
->marker
= adg_dim_style_marker2_new(dim_style
);
526 adg_entity_set_parent((AdgEntity
*) data
->marker
, entity
);
531 unset_trail(AdgRDim
*rdim
)
533 AdgRDimPrivate
*data
= rdim
->data
;
535 if (data
->trail
!= NULL
)
536 adg_model_clear((AdgModel
*) data
->trail
);
538 data
->cpml
.path
.status
= CAIRO_STATUS_INVALID_PATH_DATA
;
542 dispose_marker(AdgRDim
*rdim
)
544 AdgRDimPrivate
*data
= rdim
->data
;
546 if (data
->trail
!= NULL
) {
547 g_object_unref(data
->trail
);
551 if (data
->marker
!= NULL
) {
552 g_object_unref(data
->marker
);
558 trail_callback(AdgTrail
*trail
, gpointer user_data
)
561 AdgRDimPrivate
*data
;
563 rdim
= (AdgRDim
*) user_data
;
566 return &data
->cpml
.path
;