[AdgTitleBlock] s/_get_projection/_projection/
[adg.git] / adg / adg-ldim.c
blobc2238f89143ccd452769fea559ed7a5638b32486
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 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-ldim
23 * @short_description: Linear dimensions
25 * The #AdgLDim entity represents a linear dimension.
26 **/
28 /**
29 * AdgLDim:
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
33 **/
36 #include "adg-ldim.h"
37 #include "adg-ldim-private.h"
38 #include "adg-dim-private.h"
39 #include "adg-dim-style.h"
40 #include "adg-intl.h"
42 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_ldim_parent_class)
43 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_ldim_parent_class)
46 enum {
47 PROP_0,
48 PROP_DIRECTION,
49 PROP_HAS_EXTENSION1,
50 PROP_HAS_EXTENSION2
54 static void dispose (GObject *object);
55 static void get_property (GObject *object,
56 guint param_id,
57 GValue *value,
58 GParamSpec *pspec);
59 static void set_property (GObject *object,
60 guint param_id,
61 const GValue *value,
62 GParamSpec *pspec);
63 static void local_changed (AdgEntity *entity);
64 static void invalidate (AdgEntity *entity);
65 static void arrange (AdgEntity *entity);
66 static void render (AdgEntity *entity,
67 cairo_t *cr);
68 static gchar * default_value (AdgDim *dim);
69 static void update_geometry (AdgLDim *ldim);
70 static void update_shift (AdgLDim *ldim);
71 static void update_entities (AdgLDim *ldim);
72 static gboolean choose_outside (AdgLDim *ldim);
73 static void unset_trail (AdgLDim *ldim);
74 static void dispose_markers (AdgLDim *ldim);
75 static CpmlPath * trail_callback (AdgTrail *trail,
76 gpointer user_data);
79 G_DEFINE_TYPE(AdgLDim, adg_ldim, ADG_TYPE_DIM);
82 static void
83 adg_ldim_class_init(AdgLDimClass *klass)
85 GObjectClass *gobject_class;
86 AdgEntityClass *entity_class;
87 AdgDimClass *dim_class;
88 GParamSpec *param;
90 gobject_class = (GObjectClass *) klass;
91 entity_class = (AdgEntityClass *) klass;
92 dim_class = (AdgDimClass *) klass;
94 g_type_class_add_private(klass, sizeof(AdgLDimPrivate));
96 gobject_class->dispose = dispose;
97 gobject_class->get_property = get_property;
98 gobject_class->set_property = set_property;
100 entity_class->local_changed = local_changed;
101 entity_class->invalidate = invalidate;
102 entity_class->arrange = arrange;
103 entity_class->render = render;
105 dim_class->default_value = default_value;
107 param = g_param_spec_double("direction",
108 P_("Direction"),
109 P_("The inclination angle of the extension lines"),
110 -G_MAXDOUBLE, G_MAXDOUBLE, ADG_DIR_RIGHT,
111 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
112 g_object_class_install_property(gobject_class, PROP_DIRECTION, param);
114 param = g_param_spec_boolean("has-extension1",
115 P_("Has First Extension Line flag"),
116 P_("Show (TRUE) or hide (FALSE) the first extension line"),
117 TRUE, G_PARAM_READWRITE);
118 g_object_class_install_property(gobject_class, PROP_HAS_EXTENSION1, param);
120 param = g_param_spec_boolean("has-extension2",
121 P_("Has Second Extension Line flag"),
122 P_("Show (TRUE) or hide (FALSE) the second extension line"),
123 TRUE, G_PARAM_READWRITE);
124 g_object_class_install_property(gobject_class, PROP_HAS_EXTENSION2, param);
127 static void
128 adg_ldim_init(AdgLDim *ldim)
130 AdgLDimPrivate *data;
131 cairo_path_data_t move_to, line_to;
133 data = G_TYPE_INSTANCE_GET_PRIVATE(ldim, ADG_TYPE_LDIM, AdgLDimPrivate);
134 move_to.header.type = CAIRO_PATH_MOVE_TO;
135 move_to.header.length = 2;
136 line_to.header.type = CAIRO_PATH_LINE_TO;
137 line_to.header.length = 2;
139 data->direction = 0;
140 data->has_extension1 = TRUE;
141 data->has_extension2 = TRUE;
143 data->cpml.path.status = CAIRO_STATUS_INVALID_PATH_DATA;
144 data->cpml.path.data = data->cpml.data;
145 data->cpml.path.num_data = G_N_ELEMENTS(data->cpml.data);
146 data->cpml.path.data[0] = move_to;
147 data->cpml.path.data[2] = line_to;
148 data->cpml.path.data[4] = move_to;
149 data->cpml.path.data[6] = line_to;
150 data->cpml.path.data[8] = move_to;
151 data->cpml.path.data[10] = line_to;
152 data->cpml.path.data[12] = move_to;
153 data->cpml.path.data[14] = line_to;
154 data->cpml.path.data[16] = move_to;
155 data->cpml.path.data[18] = line_to;
157 data->trail = NULL;
158 data->marker1 = NULL;
159 data->marker2 = NULL;
161 data->geometry.is_arranged = FALSE;
162 data->shift.is_arranged = FALSE;
164 ldim->data = data;
167 static void
168 dispose(GObject *object)
170 dispose_markers((AdgLDim *) object);
172 if (PARENT_OBJECT_CLASS->dispose)
173 PARENT_OBJECT_CLASS->dispose(object);
176 static void
177 get_property(GObject *object,
178 guint prop_id, GValue *value, GParamSpec *pspec)
180 AdgLDimPrivate *data = ((AdgLDim *) object)->data;
182 switch (prop_id) {
183 case PROP_DIRECTION:
184 g_value_set_double(value, data->direction);
185 break;
186 case PROP_HAS_EXTENSION1:
187 g_value_set_boolean(value, data->has_extension1);
188 break;
189 case PROP_HAS_EXTENSION2:
190 g_value_set_boolean(value, data->has_extension2);
191 break;
192 default:
193 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
194 break;
198 static void
199 set_property(GObject *object,
200 guint prop_id, const GValue *value, GParamSpec *pspec)
202 AdgLDimPrivate *data = ((AdgLDim *) object)->data;
204 switch (prop_id) {
205 case PROP_DIRECTION:
206 data->direction = g_value_get_double(value);
207 break;
208 case PROP_HAS_EXTENSION1:
209 data->has_extension1 = g_value_get_boolean(value);
210 break;
211 case PROP_HAS_EXTENSION2:
212 data->has_extension2 = g_value_get_boolean(value);
213 break;
214 default:
215 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
216 break;
222 * adg_ldim_new:
224 * Creates a new - undefined - linear dimension. You must, at least,
225 * define the reference points with adg_dim_set_ref(), the dimension
226 * direction with adg_ldim_set_direction() and the position reference
227 * using adg_dim_set_pos().
229 * Returns: the newly created linear dimension entity
231 AdgLDim *
232 adg_ldim_new(void)
234 return g_object_new(ADG_TYPE_LDIM, NULL);
238 * adg_ldim_new_full:
239 * @ref1: the first reference point
240 * @ref2: the second reference point
241 * @pos: the position reference
242 * @direction: angle where to extend the dimension
244 * Creates a new linear dimension, specifing all the needed properties in
245 * one shot.
247 * Returns: the newly created linear dimension entity
249 AdgLDim *
250 adg_ldim_new_full(const AdgPair *ref1, const AdgPair *ref2,
251 const AdgPair *pos, gdouble direction)
253 AdgLDim *ldim;
254 AdgDim *dim;
256 ldim = g_object_new(ADG_TYPE_LDIM, "direction", direction, NULL);
257 dim = (AdgDim *) ldim;
259 adg_dim_set_ref(dim, ref1, ref2);
260 adg_dim_set_pos(dim, pos);
262 return ldim;
266 * adg_ldim_new_full_explicit:
267 * @ref1_x: the x coordinate of the first reference point
268 * @ref1_y: the y coordinate of the first reference point
269 * @ref2_x: the x coordinate of the second reference point
270 * @ref2_y: the y coordinate of the second reference point
271 * @pos_x: the x coordinate of the position reference
272 * @pos_y: the y coordinate of the position reference
273 * @direction: angle where to extend the dimension
275 * Wrappes adg_ldim_new_full() with explicit values.
277 * Returns: the newly created linear dimension entity
279 AdgLDim *
280 adg_ldim_new_full_explicit(gdouble ref1_x, gdouble ref1_y,
281 gdouble ref2_x, gdouble ref2_y,
282 gdouble pos_x, gdouble pos_y, gdouble direction)
284 AdgPair ref1;
285 AdgPair ref2;
286 AdgPair pos;
288 ref1.x = ref1_x;
289 ref1.y = ref1_y;
290 ref2.x = ref2_x;
291 ref2.y = ref2_y;
292 pos.x = pos_x;
293 pos.y = pos_y;
295 return adg_ldim_new_full(&ref1, &ref2, &pos, direction);
299 * adg_ldim_new_full_from_model:
300 * @model: the model from which the named pairs are taken
301 * @ref1: the first reference point
302 * @ref2: the second reference point
303 * @pos: the position reference
304 * @direction: angle where to extend the dimension
306 * Creates a new linear dimension, specifing all the needed properties in
307 * one shot and using named pairs from @model.
309 * Returns: the newly created linear dimension entity
311 AdgLDim *
312 adg_ldim_new_full_from_model(AdgModel *model,
313 const gchar *ref1, const gchar *ref2,
314 const gchar *pos, gdouble direction)
316 AdgLDim *ldim;
317 AdgDim *dim;
319 ldim = g_object_new(ADG_TYPE_LDIM, "direction", direction, NULL);
320 dim = (AdgDim *) ldim;
322 adg_dim_set_ref_from_model(dim, model, ref1, ref2);
323 adg_dim_set_pos_from_model(dim, model, pos);
325 return ldim;
329 * adg_ldim_get_direction:
330 * @ldim: an #AdgLDim entity
332 * Gets the direction where @ldim will extend.
334 * Returns: the direction angle in radians
336 gdouble
337 adg_ldim_get_direction(AdgLDim *ldim)
339 AdgLDimPrivate *data;
341 g_return_val_if_fail(ADG_IS_LDIM(ldim), 0);
343 data = ldim->data;
345 return data->direction;
349 * adg_ldim_set_direction:
350 * @ldim: an #AdgLDim entity
351 * @direction: an angle value, in radians
353 * Sets the direction angle where to extend @ldim.
355 void
356 adg_ldim_set_direction(AdgLDim *ldim, gdouble direction)
358 AdgLDimPrivate *data;
360 g_return_if_fail(ADG_IS_LDIM(ldim));
362 data = ldim->data;
363 data->direction = direction;
365 g_object_notify((GObject *) ldim, "direction");
369 * adg_ldim_has_extension1:
370 * @ldim: an #AdgLDim entity
372 * Checks if @ldim should render also the first extension line.
374 * Returns: %TRUE on first extension line presents, %FALSE otherwise
376 gboolean
377 adg_ldim_has_extension1(AdgLDim *ldim)
379 AdgLDimPrivate *data;
381 g_return_val_if_fail(ADG_IS_LDIM(ldim), FALSE);
383 data = ldim->data;
385 return data->has_extension1;
389 * adg_ldim_switch_extension1:
390 * @ldim: an #AdgLDim entity
391 * @new_state: the new state
393 * Shows (if @new_state is %TRUE) or hide (if @new_state is %FALSE)
394 * the first extension line of @ldim.
396 void
397 adg_ldim_switch_extension1(AdgLDim *ldim, gboolean new_state)
399 AdgLDimPrivate *data;
401 g_return_if_fail(ADG_IS_LDIM(ldim));
403 data = ldim->data;
405 if (data->has_extension1 != new_state) {
406 data->has_extension1 = new_state;
407 g_object_notify((GObject *) ldim, "has-extension1");
412 * adg_ldim_has_extension2:
413 * @ldim: an #AdgLDim entity
415 * Checks if @ldim should render also the second extension line.
417 * Returns: %TRUE on first extension line presents, %FALSE otherwise
419 gboolean
420 adg_ldim_has_extension2(AdgLDim *ldim)
422 AdgLDimPrivate *data;
424 g_return_val_if_fail(ADG_IS_LDIM(ldim), FALSE);
426 data = ldim->data;
428 return data->has_extension2;
432 * adg_ldim_switch_extension2:
433 * @ldim: an #AdgLDim entity
434 * @new_state: the new new_state
436 * Shows (if @new_state is %TRUE) or hide (if @new_state is %FALSE)
437 * the second extension line of @ldim.
439 void
440 adg_ldim_switch_extension2(AdgLDim *ldim, gboolean new_state)
442 AdgLDimPrivate *data;
444 g_return_if_fail(ADG_IS_LDIM(ldim));
446 data = ldim->data;
448 if (data->has_extension2 != new_state) {
449 data->has_extension2 = new_state;
450 g_object_notify((GObject *) ldim, "has-extension2");
455 static void
456 local_changed(AdgEntity *entity)
458 unset_trail((AdgLDim *) entity);
460 if (PARENT_ENTITY_CLASS->local_changed)
461 PARENT_ENTITY_CLASS->local_changed(entity);
464 static void
465 invalidate(AdgEntity *entity)
467 AdgLDim *ldim;
468 AdgLDimPrivate *data;
470 ldim = (AdgLDim *) entity;
471 data = ldim->data;
473 dispose_markers(ldim);
474 data->geometry.is_arranged = FALSE;
475 data->shift.is_arranged = FALSE;
476 unset_trail(ldim);
478 if (PARENT_ENTITY_CLASS->invalidate)
479 PARENT_ENTITY_CLASS->invalidate(entity);
482 static void
483 arrange(AdgEntity *entity)
485 AdgLDim *ldim;
486 AdgDim *dim;
487 AdgLDimPrivate *data;
488 AdgContainer *quote;
489 AdgDimStyle *dim_style;
490 gboolean outside;
491 const AdgMatrix *local;
492 AdgPair ref1, ref2, base1, base2;
493 AdgPair pair;
494 gint n;
495 CpmlExtents extents;
497 if (PARENT_ENTITY_CLASS->arrange)
498 PARENT_ENTITY_CLASS->arrange(entity);
500 ldim = (AdgLDim *) entity;
501 dim = (AdgDim *) ldim;
502 data = ldim->data;
503 quote = adg_dim_get_quote(dim);
505 update_geometry(ldim);
506 update_shift(ldim);
507 update_entities(ldim);
509 /* Check for cached result */
510 if (data->cpml.path.status == CAIRO_STATUS_SUCCESS) {
511 AdgEntity *quote_entity = (AdgEntity *) quote;
512 adg_entity_set_global_map(quote_entity, &data->quote.global_map);
513 adg_entity_set_local_map(quote_entity, &data->quote.local_map);
514 return;
517 dim_style = GET_DIM_STYLE(dim);
519 switch (adg_dim_get_outside(dim)) {
520 case ADG_THREE_STATE_OFF:
521 outside = FALSE;
522 break;
523 case ADG_THREE_STATE_ON:
524 outside = TRUE;
525 break;
526 case ADG_THREE_STATE_UNKNOWN:
527 default:
528 outside = choose_outside(ldim);
529 break;
532 local = adg_entity_get_local_matrix(entity);
533 cpml_pair_copy(&ref1, adg_dim_get_ref1(dim));
534 cpml_pair_copy(&ref2, adg_dim_get_ref2(dim));
535 cpml_pair_copy(&base1, &data->geometry.base1);
536 cpml_pair_copy(&base2, &data->geometry.base2);
538 cpml_pair_transform(&ref1, local);
539 cpml_pair_transform(&ref2, local);
540 cpml_pair_transform(&base1, local);
541 cpml_pair_transform(&base2, local);
543 cpml_pair_add(cpml_pair_copy(&pair, &ref1), &data->shift.from);
544 cpml_pair_to_cairo(&pair, &data->cpml.data[13]);
546 cpml_pair_copy(&pair, &base1);
547 cpml_pair_add(&pair, &data->shift.base);
548 cpml_pair_to_cairo(&pair, &data->cpml.data[1]);
550 cpml_pair_add(&pair, &data->shift.to);
551 cpml_pair_to_cairo(&pair, &data->cpml.data[15]);
553 cpml_pair_add(cpml_pair_copy(&pair, &ref2), &data->shift.from);
554 cpml_pair_to_cairo(&pair, &data->cpml.data[17]);
556 cpml_pair_copy(&pair, &base2);
557 cpml_pair_add(&pair, &data->shift.base);
558 cpml_pair_to_cairo(&pair, &data->cpml.data[3]);
560 cpml_pair_add(&pair, &data->shift.to);
561 cpml_pair_to_cairo(&pair, &data->cpml.data[19]);
563 /* Calculate the outside segments */
564 if (outside) {
565 gdouble beyond;
566 CpmlVector vector;
568 beyond = adg_dim_style_get_beyond(dim_style);
569 cpml_pair_from_cairo(&pair, &data->cpml.data[1]);
571 cpml_pair_from_cairo(&vector, &data->cpml.data[3]);
572 cpml_pair_sub(&vector, &pair);
573 cpml_vector_set_length(&vector, beyond);
575 cpml_pair_from_cairo(&pair, &data->cpml.data[1]);
576 cpml_pair_to_cairo(&pair, &data->cpml.data[5]);
578 cpml_pair_sub(&pair, &vector);
579 cpml_pair_to_cairo(&pair, &data->cpml.data[7]);
581 cpml_pair_from_cairo(&pair, &data->cpml.data[3]);
582 cpml_pair_to_cairo(&pair, &data->cpml.data[11]);
584 cpml_pair_add(&pair, &vector);
585 cpml_pair_to_cairo(&pair, &data->cpml.data[9]);
587 data->cpml.data[2].header.length = 2;
588 data->cpml.data[10].header.length = 2;
589 n = 10;
590 } else {
591 data->cpml.data[2].header.length = 10;
592 n = 2;
595 /* Play with header lengths to show or hide the extension lines */
596 if (data->has_extension1) {
597 data->cpml.data[14].header.length = data->has_extension2 ? 2 : 6;
598 } else {
599 data->cpml.data[n].header.length += 4;
600 if (!data->has_extension2)
601 data->cpml.data[n].header.length += 4;
604 data->cpml.path.status = CAIRO_STATUS_SUCCESS;
605 cpml_extents_copy(&extents, adg_trail_extents(data->trail));
607 if (quote != NULL) {
608 /* Update global and local map of the quote container */
609 AdgEntity *quote_entity;
610 gdouble angle;
611 AdgMatrix map;
612 CpmlExtents quote_extents;
614 quote_entity = (AdgEntity *) quote;
615 angle = adg_dim_quote_angle(dim, data->direction + G_PI_2);
617 pair.x = (data->cpml.data[1].point.x + data->cpml.data[3].point.x) / 2;
618 pair.y = (data->cpml.data[1].point.y + data->cpml.data[3].point.y) / 2;
620 cairo_matrix_init_translate(&map, pair.x, pair.y);
621 cairo_matrix_rotate(&map, angle);
622 adg_entity_set_global_map(quote_entity, &map);
624 adg_matrix_copy(&data->quote.global_map,
625 adg_entity_get_global_map(quote_entity));
626 adg_matrix_copy(&data->quote.local_map,
627 adg_entity_get_local_map(quote_entity));
629 cpml_extents_copy(&quote_extents, adg_entity_get_extents(quote_entity));
630 cpml_extents_transform(&quote_extents, &map);
631 cpml_extents_add(&extents, &quote_extents);
634 if (data->marker1 != NULL) {
635 AdgEntity *marker1_entity;
636 CpmlExtents marker1_extents;
638 marker1_entity = (AdgEntity *) data->marker1;
640 adg_marker_set_segment(data->marker1, data->trail, outside ? 2 : 1);
641 adg_entity_local_changed(marker1_entity);
643 cpml_extents_copy(&marker1_extents, adg_entity_get_extents(marker1_entity));
644 cpml_extents_transform(&marker1_extents,
645 adg_entity_get_global_map(marker1_entity));
646 cpml_extents_add(&extents, &marker1_extents);
649 if (data->marker2 != NULL) {
650 AdgEntity *marker2_entity;
651 CpmlExtents marker2_extents;
653 marker2_entity = (AdgEntity *) data->marker2;
655 adg_marker_set_segment(data->marker2, data->trail, outside ? 3 : 1);
656 adg_entity_local_changed(marker2_entity);
658 cpml_extents_copy(&marker2_extents, adg_entity_get_extents(marker2_entity));
659 cpml_extents_transform(&marker2_extents,
660 adg_entity_get_global_map(marker2_entity));
661 cpml_extents_add(&extents, &marker2_extents);
664 adg_entity_set_extents(entity, &extents);
667 static void
668 render(AdgEntity *entity, cairo_t *cr)
670 AdgLDim *ldim;
671 AdgDim *dim;
672 AdgLDimPrivate *data;
673 AdgDimStyle *dim_style;
674 AdgDress dress;
675 const cairo_path_t *cairo_path;
677 ldim = (AdgLDim *) entity;
678 dim = (AdgDim *) entity;
679 data = ldim->data;
680 dim_style = GET_DIM_STYLE(dim);
682 adg_style_apply((AdgStyle *) dim_style, entity, cr);
684 if (data->marker1 != NULL)
685 adg_entity_render((AdgEntity *) data->marker1, cr);
687 if (data->marker2 != NULL)
688 adg_entity_render((AdgEntity *) data->marker2, cr);
690 adg_entity_render((AdgEntity *) adg_dim_get_quote(dim), cr);
692 dress = adg_dim_style_get_line_dress(dim_style);
693 adg_entity_apply_dress(entity, dress, cr);
695 cairo_path = adg_trail_get_cairo_path(data->trail);
696 cairo_append_path(cr, cairo_path);
697 cairo_stroke(cr);
700 static gchar *
701 default_value(AdgDim *dim)
703 AdgLDim *ldim;
704 AdgLDimPrivate *data;
705 AdgDimStyle *dim_style;
706 const gchar *format;
708 ldim = (AdgLDim *) dim;
709 data = ldim->data;
710 dim_style = GET_DIM_STYLE(dim);
711 format = adg_dim_style_get_number_format(dim_style);
713 update_geometry(ldim);
715 return g_strdup_printf(format, data->geometry.distance);
718 static void
719 update_geometry(AdgLDim *ldim)
721 AdgLDimPrivate *data;
722 AdgDim *dim;
723 const AdgPair *ref1, *ref2;
724 const AdgPair *pos;
725 CpmlVector baseline, extension;
726 gdouble d, k;
728 data = ldim->data;
730 if (data->geometry.is_arranged)
731 return;
733 dim = (AdgDim *) ldim;
734 ref1 = adg_dim_get_ref1(dim);
735 ref2 = adg_dim_get_ref2(dim);
736 pos = adg_dim_get_pos(dim);
737 cpml_vector_from_angle(&extension, data->direction);
738 cpml_pair_copy(&baseline, &extension);
739 cpml_vector_normal(&baseline);
741 d = extension.y * baseline.x -
742 extension.x * baseline.y;
743 g_return_if_fail(d != 0);
745 k = ((pos->y - ref1->y) * baseline.x -
746 (pos->x - ref1->x) * baseline.y) / d;
747 data->geometry.base1.x = ref1->x + k * extension.x;
748 data->geometry.base1.y = ref1->y + k * extension.y;
750 k = ((pos->y - ref2->y) * baseline.x -
751 (pos->x - ref2->x) * baseline.y) / d;
752 data->geometry.base2.x = ref2->x + k * extension.x;
753 data->geometry.base2.y = ref2->y + k * extension.y;
755 data->geometry.distance = cpml_pair_distance(&data->geometry.base1,
756 &data->geometry.base2);
758 data->geometry.is_arranged = TRUE;
761 static void
762 update_shift(AdgLDim *ldim)
764 AdgLDimPrivate *data;
765 AdgDimStyle *dim_style;
766 gdouble from_offset, to_offset;
767 gdouble baseline_spacing, level;
768 CpmlVector vector;
770 data = ldim->data;
772 if (data->shift.is_arranged)
773 return;
775 dim_style = GET_DIM_STYLE(ldim);
776 from_offset = adg_dim_style_get_from_offset(dim_style);
777 to_offset = adg_dim_style_get_to_offset(dim_style);
778 baseline_spacing = adg_dim_style_get_baseline_spacing(dim_style);
779 level = adg_dim_get_level((AdgDim *) ldim);
781 cpml_vector_from_angle(&vector, data->direction);
783 cpml_vector_set_length(&vector, from_offset);
784 cpml_pair_copy(&data->shift.from, &vector);
786 cpml_vector_set_length(&vector, to_offset);
787 cpml_pair_copy(&data->shift.to, &vector);
789 cpml_vector_set_length(&vector, level * baseline_spacing);
790 cpml_pair_copy(&data->shift.base, &vector);
792 data->shift.is_arranged = TRUE;
795 static void
796 update_entities(AdgLDim *ldim)
798 AdgLDimPrivate *data;
799 AdgDimStyle *dim_style;
801 data = ldim->data;
802 dim_style = GET_DIM_STYLE(ldim);
804 if (data->trail == NULL)
805 data->trail = adg_trail_new(trail_callback, ldim);
807 if (data->marker1 == NULL)
808 data->marker1 = adg_dim_style_marker1_new(dim_style);
810 if (data->marker2 == NULL)
811 data->marker2 = adg_dim_style_marker2_new(dim_style);
814 static gboolean
815 choose_outside(AdgLDim *ldim)
817 AdgLDimPrivate *data;
818 AdgEntity *quote;
819 const AdgMatrix *local;
820 gdouble marker1, marker2;
821 gdouble needed, available;
823 data = ldim->data;
824 quote = (AdgEntity *) adg_dim_get_quote((AdgDim *) ldim);
825 local = adg_entity_get_local_matrix((AdgEntity *) ldim);
826 marker1 = data->marker1 == NULL ? 0 : adg_marker_get_size(data->marker1);
827 marker2 = data->marker2 == NULL ? 0 : adg_marker_get_size(data->marker2);
829 needed = adg_entity_get_extents(quote)->size.x + marker1 + marker2;
830 available = data->geometry.distance * local->xx;
832 return needed > available;
835 static void
836 unset_trail(AdgLDim *ldim)
838 AdgLDimPrivate *data = ldim->data;
840 if (data->trail != NULL)
841 adg_model_clear((AdgModel *) data->trail);
843 data->cpml.path.status = CAIRO_STATUS_INVALID_PATH_DATA;
846 static void
847 dispose_markers(AdgLDim *ldim)
849 AdgLDimPrivate *data = ldim->data;
851 if (data->trail != NULL) {
852 g_object_unref(data->trail);
853 data->trail = NULL;
856 if (data->marker1 != NULL) {
857 g_object_unref(data->marker1);
858 data->marker1 = NULL;
861 if (data->marker2 != NULL) {
862 g_object_unref(data->marker2);
863 data->marker2 = NULL;
867 static CpmlPath *
868 trail_callback(AdgTrail *trail, gpointer user_data)
870 AdgLDim *ldim;
871 AdgLDimPrivate *data;
873 ldim = (AdgLDim *) user_data;
874 data = ldim->data;
876 return &data->cpml.path;