1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2015 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.
22 * SECTION:adg-projection
23 * @short_description: The standard symbol for specifying the projection scheme
25 * The #AdgProjection is an entity representing the standard symbol
26 * of the projection scheme.
34 * All fields are private and should not be used directly.
35 * Use its public methods instead.
41 #include "adg-internal.h"
42 #include "adg-model.h"
43 #include "adg-trail.h"
45 #include "adg-dress.h"
46 #include "adg-param-dress.h"
48 #include "adg-projection.h"
49 #include "adg-projection-private.h"
52 G_DEFINE_TYPE(AdgProjection
, adg_projection
, ADG_TYPE_ENTITY
)
62 static void _adg_get_property (GObject
*object
,
66 static void _adg_set_property (GObject
*object
,
70 static void _adg_arrange (AdgEntity
*entity
);
71 static void _adg_render (AdgEntity
*entity
,
73 static void _adg_arrange_class (AdgProjectionClass
*projection_class
,
74 AdgProjectionScheme scheme
);
78 adg_projection_class_init(AdgProjectionClass
*klass
)
80 GObjectClass
*gobject_class
;
81 AdgEntityClass
*entity_class
;
83 AdgProjectionClassPrivate
*data_class
;
85 gobject_class
= (GObjectClass
*) klass
;
86 entity_class
= (AdgEntityClass
*) klass
;
88 g_type_class_add_private(klass
, sizeof(AdgProjectionPrivate
));
90 gobject_class
->get_property
= _adg_get_property
;
91 gobject_class
->set_property
= _adg_set_property
;
93 entity_class
->arrange
= _adg_arrange
;
94 entity_class
->render
= _adg_render
;
96 param
= adg_param_spec_dress("symbol-dress",
98 P_("The line dress to use for rendering the views of the projection"),
101 g_object_class_install_property(gobject_class
, PROP_SYMBOL_DRESS
, param
);
103 param
= adg_param_spec_dress("axis-dress",
105 P_("The line dress to use for rendering the axis of the projection scheme"),
108 g_object_class_install_property(gobject_class
, PROP_AXIS_DRESS
, param
);
110 param
= g_param_spec_enum("scheme",
111 P_("Projection Scheme"),
112 P_("The projection scheme to be represented"),
113 ADG_TYPE_PROJECTION_SCHEME
,
114 ADG_PROJECTION_SCHEME_UNDEFINED
,
116 g_object_class_install_property(gobject_class
, PROP_SCHEME
, param
);
118 /* Initialize the private class data: the allocated struct is
119 * never freed as this type is registered statically, hence
120 * never destroyed. A better approach would be to use the old
121 * type initialization (no G_TYPE_DEFINE and friends) that
122 * allows to specify a custom class finalization method */
123 data_class
= g_new(AdgProjectionClassPrivate
, 1);
125 data_class
->scheme
= ADG_PROJECTION_SCHEME_UNDEFINED
;
126 data_class
->symbol
= NULL
;
127 data_class
->axis
= NULL
;
128 data_class
->extents
.is_defined
= FALSE
;
130 klass
->data_class
= data_class
;
134 adg_projection_init(AdgProjection
*projection
)
136 AdgProjectionPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(projection
, ADG_TYPE_PROJECTION
,
137 AdgProjectionPrivate
);
139 data
->symbol_dress
= ADG_DRESS_LINE
;
140 data
->axis_dress
= ADG_DRESS_LINE
;
141 data
->scheme
= ADG_PROJECTION_SCHEME_UNDEFINED
;
143 projection
->data
= data
;
147 _adg_get_property(GObject
*object
, guint prop_id
,
148 GValue
*value
, GParamSpec
*pspec
)
150 AdgProjectionPrivate
*data
= ((AdgProjection
*) object
)->data
;
153 case PROP_SYMBOL_DRESS
:
154 g_value_set_enum(value
, data
->symbol_dress
);
156 case PROP_AXIS_DRESS
:
157 g_value_set_enum(value
, data
->axis_dress
);
160 g_value_set_enum(value
, data
->scheme
);
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
)
172 AdgProjection
*projection
;
173 AdgProjectionPrivate
*data
;
175 projection
= (AdgProjection
*) object
;
176 data
= projection
->data
;
179 case PROP_SYMBOL_DRESS
:
180 data
->symbol_dress
= g_value_get_enum(value
);
182 case PROP_AXIS_DRESS
:
183 data
->axis_dress
= g_value_get_enum(value
);
186 data
->scheme
= g_value_get_enum(value
);
187 adg_entity_invalidate((AdgEntity
*) object
);
190 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
197 * adg_projection_new:
198 * @scheme: the scheme represented by this projection
200 * Creates a new projection entity representing the selected @scheme.
201 * If @scheme is invalid, a projection symbol without a scheme is
202 * returned, that is #AdgProjection:scheme is set to
203 * #ADG_PROJECTION_SCHEME_UNDEFINED, and a warning is raised.
205 * Returns: (transfer full): the newly created projection entity.
210 adg_projection_new(AdgProjectionScheme scheme
)
212 return g_object_new(ADG_TYPE_PROJECTION
, "scheme", scheme
, NULL
);
216 * adg_projection_set_symbol_dress:
217 * @projection: an #AdgProjection
218 * @dress: the new #AdgDress to use
220 * Sets a new line dress for rendering the symbol of @projection. The
221 * new dress must be a line dress: the check is done by calling
222 * adg_dress_are_related() with @dress and the old dress as
223 * arguments. Check out its documentation for further details.
225 * The default dress is a transparent line dress: the rendering
226 * callback will stroke the symbol using the default color with
227 * a predefined thickness.
232 adg_projection_set_symbol_dress(AdgProjection
*projection
, AdgDress dress
)
234 g_return_if_fail(ADG_IS_PROJECTION(projection
));
235 g_object_set(projection
, "symbol-dress", dress
, NULL
);
239 * adg_projection_get_symbol_dress:
240 * @projection: an #AdgProjection
242 * Gets the line dress to be used in stroking the symbol of @projection.
244 * Returns: (transfer none): the requested line dress.
249 adg_projection_get_symbol_dress(AdgProjection
*projection
)
251 AdgProjectionPrivate
*data
;
253 g_return_val_if_fail(ADG_IS_PROJECTION(projection
), ADG_DRESS_UNDEFINED
);
255 data
= projection
->data
;
257 return data
->symbol_dress
;
261 * adg_projection_set_axis_dress:
262 * @projection: an #AdgProjection
263 * @dress: the new #AdgDress to use
265 * Sets a new line dress for rendering the axis of @projection.
266 * The new dress must be a line dress: the check is done by
267 * calling adg_dress_are_related() with @dress and the old
268 * dress as arguments. Check out its documentation for
271 * The default dress is a transparent line dress: the rendering
272 * callback will stroke the axis using the default line style.
277 adg_projection_set_axis_dress(AdgProjection
*projection
, AdgDress dress
)
279 g_return_if_fail(ADG_IS_PROJECTION(projection
));
280 g_object_set(projection
, "axis-dress", dress
, NULL
);
284 * adg_projection_get_axis_dress:
285 * @projection: an #AdgProjection
287 * Gets the line dress to be used in stroking the axis of @projection.
289 * Returns: (transfer none): the requested line dress.
294 adg_projection_get_axis_dress(AdgProjection
*projection
)
296 AdgProjectionPrivate
*data
;
298 g_return_val_if_fail(ADG_IS_PROJECTION(projection
), ADG_DRESS_UNDEFINED
);
300 data
= projection
->data
;
302 return data
->axis_dress
;
306 * adg_projection_set_scheme:
307 * @projection: an #AdgProjection
308 * @scheme: the new projection scheme
310 * Sets a new scheme on @projection. If @scheme is different
311 * from the old one, @projection is invalidated.
316 adg_projection_set_scheme(AdgProjection
*projection
,
317 AdgProjectionScheme scheme
)
319 g_return_if_fail(ADG_IS_PROJECTION(projection
));
320 g_object_set(projection
, "scheme", scheme
, NULL
);
324 * adg_projection_get_scheme:
325 * @projection: an #AdgProjection
327 * Gets the scheme represented by @projection.
329 * Returns: (transfer none): the scheme of @projection
334 adg_projection_get_scheme(AdgProjection
*projection
)
336 AdgProjectionPrivate
*data
;
338 g_return_val_if_fail(ADG_IS_PROJECTION(projection
),
339 ADG_PROJECTION_SCHEME_UNDEFINED
);
341 data
= projection
->data
;
348 _adg_arrange(AdgEntity
*entity
)
350 AdgProjectionPrivate
*data
;
351 AdgProjectionClass
*projection_class
;
352 AdgProjectionClassPrivate
*data_class
;
355 data
= ((AdgProjection
*) entity
)->data
;
356 projection_class
= ADG_PROJECTION_GET_CLASS(entity
);
357 data_class
= projection_class
->data_class
;
359 _adg_arrange_class(projection_class
, data
->scheme
);
360 cpml_extents_copy(&extents
, &data_class
->extents
);
362 cpml_extents_transform(&extents
, adg_entity_get_local_matrix(entity
));
363 cpml_extents_transform(&extents
, adg_entity_get_global_matrix(entity
));
364 adg_entity_set_extents(entity
, &extents
);
368 _adg_arrange_class(AdgProjectionClass
*projection_class
,
369 AdgProjectionScheme scheme
)
371 AdgProjectionClassPrivate
*data_class
;
372 AdgPath
*symbol
, *axis
;
374 data_class
= projection_class
->data_class
;
376 if (data_class
->scheme
== scheme
)
379 if (data_class
->symbol
!= NULL
)
380 g_object_unref(data_class
->symbol
);
382 if (data_class
->axis
!= NULL
)
383 g_object_unref(data_class
->axis
);
385 data_class
->scheme
= scheme
;
388 case ADG_PROJECTION_SCHEME_UNDEFINED
:
392 case ADG_PROJECTION_SCHEME_FIRST_ANGLE
:
393 symbol
= adg_path_new();
394 adg_path_move_to_explicit(symbol
, 4, 19);
395 adg_path_line_to_explicit(symbol
, 24, 24);
396 adg_path_line_to_explicit(symbol
, 24, 4);
397 adg_path_line_to_explicit(symbol
, 4, 9);
398 adg_path_close(symbol
);
399 adg_path_move_to_explicit(symbol
, 49, 14);
400 adg_path_arc_to_explicit(symbol
, 29, 14, 49, 14);
401 adg_path_move_to_explicit(symbol
, 44, 14);
402 adg_path_arc_to_explicit(symbol
, 34, 14, 44, 14);
404 axis
= adg_path_new();
405 adg_path_move_to_explicit(axis
, 0, 14);
406 adg_path_line_to_explicit(axis
, 53, 14);
407 adg_path_move_to_explicit(axis
, 39, 0);
408 adg_path_line_to_explicit(axis
, 39, 28);
410 case ADG_PROJECTION_SCHEME_THIRD_ANGLE
:
411 symbol
= adg_path_new();
412 adg_path_move_to_explicit(symbol
, 29, 19);
413 adg_path_line_to_explicit(symbol
, 49, 24);
414 adg_path_line_to_explicit(symbol
, 49, 4);
415 adg_path_line_to_explicit(symbol
, 29, 9);
416 adg_path_close(symbol
);
417 adg_path_move_to_explicit(symbol
, 24, 14);
418 adg_path_arc_to_explicit(symbol
, 4, 14, 24, 14);
419 adg_path_move_to_explicit(symbol
, 19, 14);
420 adg_path_arc_to_explicit(symbol
, 9, 14, 19, 14);
422 axis
= adg_path_new();
423 adg_path_move_to_explicit(axis
, 0, 14);
424 adg_path_line_to_explicit(axis
, 53, 14);
425 adg_path_move_to_explicit(axis
, 14, 0);
426 adg_path_line_to_explicit(axis
, 14, 28);
429 g_return_if_reached();
433 data_class
->symbol
= symbol
;
434 data_class
->axis
= axis
;
435 data_class
->extents
.is_defined
= FALSE
;
438 cpml_extents_add(&data_class
->extents
,
439 adg_trail_get_extents((AdgTrail
*) axis
));
442 cpml_extents_add(&data_class
->extents
,
443 adg_trail_get_extents((AdgTrail
*) symbol
));
447 _adg_render(AdgEntity
*entity
, cairo_t
*cr
)
449 AdgProjectionClassPrivate
*data_class
;
450 AdgProjectionPrivate
*data
;
451 const cairo_path_t
*cairo_path
;
453 data_class
= ADG_PROJECTION_GET_CLASS(entity
)->data_class
;
454 data
= ((AdgProjection
*) entity
)->data
;
456 cairo_transform(cr
, adg_entity_get_global_matrix(entity
));
458 if (data_class
->symbol
!= NULL
) {
459 cairo_path
= adg_trail_get_cairo_path((AdgTrail
*) data_class
->symbol
);
462 cairo_transform(cr
, adg_entity_get_local_matrix(entity
));
463 cairo_append_path(cr
, cairo_path
);
466 cairo_set_line_width(cr
, 2);
467 adg_entity_apply_dress(entity
, data
->symbol_dress
, cr
);
472 if (data_class
->axis
!= NULL
) {
473 const gdouble dashes
[] = { 5, 2, 1, 2 };
475 cairo_path
= adg_trail_get_cairo_path((AdgTrail
*) data_class
->axis
);
478 cairo_transform(cr
, adg_entity_get_local_matrix(entity
));
479 cairo_append_path(cr
, cairo_path
);
482 cairo_set_line_width(cr
, 1);
483 cairo_set_dash(cr
, dashes
, G_N_ELEMENTS(dashes
), -1.5);
484 adg_entity_apply_dress(entity
, data
->axis_dress
, cr
);