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.
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.
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
37 #include "adg-projection.h"
38 #include "adg-projection-private.h"
39 #include "adg-line-style.h"
40 #include "adg-dress-builtins.h"
43 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_projection_parent_class)
54 static void get_property (GObject
*object
,
58 static void set_property (GObject
*object
,
62 static void arrange (AdgEntity
*entity
);
63 static void render (AdgEntity
*entity
,
65 static void arrange_class (AdgProjectionClass
*projection_class
,
66 AdgProjectionScheme scheme
);
67 static gboolean
set_scheme (AdgProjection
*projection
,
68 AdgProjectionScheme scheme
);
71 G_DEFINE_TYPE(AdgProjection
, adg_projection
, ADG_TYPE_ENTITY
);
75 adg_projection_class_init(AdgProjectionClass
*klass
)
77 GObjectClass
*gobject_class
;
78 AdgEntityClass
*entity_class
;
80 AdgProjectionClassPrivate
*data_class
;
82 gobject_class
= (GObjectClass
*) klass
;
83 entity_class
= (AdgEntityClass
*) klass
;
85 g_type_class_add_private(klass
, sizeof(AdgProjectionPrivate
));
87 gobject_class
->get_property
= get_property
;
88 gobject_class
->set_property
= set_property
;
90 entity_class
->arrange
= arrange
;
91 entity_class
->render
= render
;
93 param
= adg_param_spec_dress("symbol-dress",
95 P_("The line dress to use for rendering the views of the projection"),
98 g_object_class_install_property(gobject_class
, PROP_SYMBOL_DRESS
, param
);
100 param
= adg_param_spec_dress("axis-dress",
102 P_("The line dress to use for rendering the axis of the projection scheme"),
105 g_object_class_install_property(gobject_class
, PROP_AXIS_DRESS
, param
);
107 param
= g_param_spec_enum("scheme",
108 P_("Projection Scheme"),
109 P_("The projection scheme to be represented"),
110 ADG_TYPE_PROJECTION_SCHEME
,
111 ADG_PROJECTION_UNDEFINED
,
113 g_object_class_install_property(gobject_class
, PROP_SCHEME
, param
);
115 /* Initialize the private class data: the allocated struct is
116 * never freed as this type is registered statically, hence
117 * never destroyed. A better approach would be to use the old
118 * type initialization (no G_TYPE_DEFINE and friends) that
119 * allows to specify a custom class finalization method */
120 data_class
= g_new(AdgProjectionClassPrivate
, 1);
122 data_class
->scheme
= ADG_PROJECTION_UNDEFINED
;
123 data_class
->symbol
= NULL
;
124 data_class
->axis
= NULL
;
125 data_class
->extents
.is_defined
= FALSE
;
127 klass
->data_class
= data_class
;
131 adg_projection_init(AdgProjection
*projection
)
133 AdgProjectionPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(projection
, ADG_TYPE_PROJECTION
,
134 AdgProjectionPrivate
);
136 data
->symbol_dress
= ADG_DRESS_LINE
;
137 data
->axis_dress
= ADG_DRESS_LINE
;
138 data
->scheme
= ADG_PROJECTION_UNDEFINED
;
140 projection
->data
= data
;
144 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
146 AdgProjectionPrivate
*data
= ((AdgProjection
*) object
)->data
;
149 case PROP_SYMBOL_DRESS
:
150 g_value_set_int(value
, data
->symbol_dress
);
152 case PROP_AXIS_DRESS
:
153 g_value_set_int(value
, data
->axis_dress
);
156 g_value_set_enum(value
, data
->scheme
);
159 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
165 set_property(GObject
*object
, guint prop_id
,
166 const GValue
*value
, GParamSpec
*pspec
)
168 AdgProjection
*projection
;
169 AdgProjectionPrivate
*data
;
171 projection
= (AdgProjection
*) object
;
172 data
= projection
->data
;
175 case PROP_SYMBOL_DRESS
:
176 adg_dress_set(&data
->symbol_dress
, g_value_get_int(value
));
178 case PROP_AXIS_DRESS
:
179 adg_dress_set(&data
->axis_dress
, g_value_get_int(value
));
182 set_scheme(projection
, g_value_get_enum(value
));
185 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
192 * adg_projection_new:
193 * @scheme: the scheme represented by this projection
195 * Creates a new projection entity. The #AdgEntity:local-method
196 * property is set by default to #ADG_MIX_DISABLED, that is the
197 * projection is not subject to any local transformations.
199 * Returns: the newly created projection entity
202 adg_projection_new(AdgProjectionScheme scheme
)
204 return g_object_new(ADG_TYPE_PROJECTION
,
205 "local-method", ADG_MIX_DISABLED
,
206 "scheme", scheme
, NULL
);
210 * adg_projection_get_symbol_dress:
211 * @projection: an #AdgProjection
213 * Gets the line dress to be used in stroking the symbol of @projection.
215 * Returns: the requested line dress
218 adg_projection_get_symbol_dress(AdgProjection
*projection
)
220 AdgProjectionPrivate
*data
;
222 g_return_val_if_fail(ADG_IS_PROJECTION(projection
), ADG_DRESS_UNDEFINED
);
224 data
= projection
->data
;
226 return data
->symbol_dress
;
230 * adg_projection_set_symbol_dress:
231 * @projection: an #AdgProjection
232 * @dress: the new #AdgDress to use
234 * Sets a new line dress for rendering the symbol of @projection. The
235 * new dress must be a line dress: the check is done by calling
236 * adg_dress_are_related() with @dress and the old dress as
237 * arguments. Check out its documentation for further details.
239 * The default dress is a transparent line dress: the rendering
240 * callback will stroke the symbol using the default color with
241 * a predefined thickness.
244 adg_projection_set_symbol_dress(AdgProjection
*projection
, AdgDress dress
)
246 AdgProjectionPrivate
*data
;
248 g_return_if_fail(ADG_IS_PROJECTION(projection
));
250 data
= projection
->data
;
252 if (adg_dress_set(&data
->symbol_dress
, dress
))
253 g_object_notify((GObject
*) projection
, "symbol-dress");
257 * adg_projection_get_axis_dress:
258 * @projection: an #AdgProjection
260 * Gets the line dress to be used in stroking the axis of @projection.
262 * Returns: the requested line dress
265 adg_projection_get_axis_dress(AdgProjection
*projection
)
267 AdgProjectionPrivate
*data
;
269 g_return_val_if_fail(ADG_IS_PROJECTION(projection
), ADG_DRESS_UNDEFINED
);
271 data
= projection
->data
;
273 return data
->axis_dress
;
277 * adg_projection_set_axis_dress:
278 * @projection: an #AdgProjection
279 * @dress: the new #AdgDress to use
281 * Sets a new line dress for rendering the axis of @projection.
282 * The new dress must be a line dress: the check is done by
283 * calling adg_dress_are_related() with @dress and the old
284 * dress as arguments. Check out its documentation for
287 * The default dress is a transparent line dress: the rendering
288 * callback will stroke the axis using the default line style.
291 adg_projection_set_axis_dress(AdgProjection
*projection
, AdgDress dress
)
293 AdgProjectionPrivate
*data
;
295 g_return_if_fail(ADG_IS_PROJECTION(projection
));
297 data
= projection
->data
;
299 if (adg_dress_set(&data
->axis_dress
, dress
))
300 g_object_notify((GObject
*) projection
, "axis-dress");
304 * adg_projection_get_scheme:
305 * @projection: an #AdgProjection
307 * Gets the scheme represented by @projection.
309 * Returns: the scheme of @projection
312 adg_projection_get_scheme(AdgProjection
*projection
)
314 AdgProjectionPrivate
*data
;
316 g_return_val_if_fail(ADG_IS_PROJECTION(projection
),
317 ADG_PROJECTION_UNDEFINED
);
319 data
= projection
->data
;
325 * adg_projection_set_scheme:
326 * @projection: an #AdgProjection
327 * @scheme: the new projection scheme
329 * Sets a new scheme on @projection. If @scheme is different
330 * from the old one, @projection is invalidated.
333 adg_projection_set_scheme(AdgProjection
*projection
,
334 AdgProjectionScheme scheme
)
336 g_return_if_fail(ADG_IS_PROJECTION(projection
));
338 if (set_scheme(projection
, scheme
))
339 g_object_notify((GObject
*) projection
, "scheme");
344 arrange(AdgEntity
*entity
)
346 AdgProjectionPrivate
*data
;
347 AdgProjectionClass
*projection_class
;
348 AdgProjectionClassPrivate
*data_class
;
349 CpmlExtents
*extents
;
350 const AdgMatrix
*local
;
352 data
= ((AdgProjection
*) entity
)->data
;
353 projection_class
= ADG_PROJECTION_GET_CLASS(entity
);
354 data_class
= projection_class
->data_class
;
355 extents
= (CpmlExtents
*) adg_entity_extents(entity
);
356 local
= adg_entity_local_matrix(entity
);
358 arrange_class(projection_class
, data
->scheme
);
359 cpml_extents_copy(extents
, &data_class
->extents
);
361 /* Apply the local matrix to the extents of this projection instance */
362 cpml_pair_transform(&extents
->org
, local
);
363 cpml_vector_transform(&extents
->size
, local
);
367 arrange_class(AdgProjectionClass
*projection_class
, AdgProjectionScheme scheme
)
369 AdgProjectionClassPrivate
*data_class
;
370 AdgPath
*symbol
, *axis
;
372 data_class
= projection_class
->data_class
;
374 if (data_class
->scheme
== scheme
)
377 if (data_class
->symbol
!= NULL
)
378 g_object_unref(data_class
->symbol
);
380 if (data_class
->axis
!= NULL
)
381 g_object_unref(data_class
->axis
);
383 data_class
->scheme
= scheme
;
386 case ADG_PROJECTION_UNDEFINED
:
390 case ADG_PROJECTION_FIRST_ANGLE
:
391 symbol
= adg_path_new();
392 adg_path_move_to_explicit(symbol
, 5, 20);
393 adg_path_line_to_explicit(symbol
, 25, 25);
394 adg_path_line_to_explicit(symbol
, 25, 5);
395 adg_path_line_to_explicit(symbol
, 5, 10);
396 adg_path_close(symbol
);
397 adg_path_move_to_explicit(symbol
, 50, 15);
398 adg_path_arc_to_explicit(symbol
, 30, 15, 50, 15);
399 adg_path_move_to_explicit(symbol
, 45, 15);
400 adg_path_arc_to_explicit(symbol
, 35, 15, 45, 15);
402 axis
= adg_path_new();
403 adg_path_move_to_explicit(axis
, 1, 15);
404 adg_path_line_to_explicit(axis
, 54, 15);
405 adg_path_move_to_explicit(axis
, 40, 1);
406 adg_path_line_to_explicit(axis
, 40, 29);
408 case ADG_PROJECTION_THIRD_ANGLE
:
409 symbol
= adg_path_new();
410 adg_path_move_to_explicit(symbol
, 30, 20);
411 adg_path_line_to_explicit(symbol
, 50, 25);
412 adg_path_line_to_explicit(symbol
, 50, 5);
413 adg_path_line_to_explicit(symbol
, 30, 10);
414 adg_path_close(symbol
);
415 adg_path_move_to_explicit(symbol
, 25, 15);
416 adg_path_arc_to_explicit(symbol
, 5, 15, 25, 15);
417 adg_path_move_to_explicit(symbol
, 20, 15);
418 adg_path_arc_to_explicit(symbol
, 10, 15, 20, 15);
420 axis
= adg_path_new();
421 adg_path_move_to_explicit(axis
, 1, 15);
422 adg_path_line_to_explicit(axis
, 54, 15);
423 adg_path_move_to_explicit(axis
, 15, 1);
424 adg_path_line_to_explicit(axis
, 15, 29);
427 g_assert_not_reached();
431 data_class
->symbol
= symbol
;
432 data_class
->axis
= axis
;
433 data_class
->extents
.is_defined
= FALSE
;
436 cpml_extents_add(&data_class
->extents
,
437 adg_trail_extents((AdgTrail
*) symbol
));
440 cpml_extents_add(&data_class
->extents
,
441 adg_trail_extents((AdgTrail
*) axis
));
445 render(AdgEntity
*entity
, cairo_t
*cr
)
447 AdgProjectionClassPrivate
*data_class
;
448 AdgProjectionPrivate
*data
;
449 const cairo_path_t
*cairo_path
;
451 data_class
= ADG_PROJECTION_GET_CLASS(entity
)->data_class
;
452 data
= ((AdgProjection
*) entity
)->data
;
454 if (data_class
->symbol
!= NULL
) {
455 cairo_path
= adg_trail_get_cairo_path((AdgTrail
*) data_class
->symbol
);
458 cairo_set_matrix(cr
, adg_entity_ctm(entity
));
459 cairo_append_path(cr
, cairo_path
);
462 cairo_set_line_width(cr
, 2);
463 adg_entity_apply_dress(entity
, data
->symbol_dress
, cr
);
468 if (data_class
->axis
!= NULL
) {
469 const gdouble dashes
[] = { 5, 2, 1, 2 };
471 cairo_path
= adg_trail_get_cairo_path((AdgTrail
*) data_class
->axis
);
474 cairo_set_matrix(cr
, adg_entity_ctm(entity
));
475 cairo_append_path(cr
, cairo_path
);
478 cairo_set_line_width(cr
, 1);
479 cairo_set_dash(cr
, dashes
, G_N_ELEMENTS(dashes
), -1.5);
480 adg_entity_apply_dress(entity
, data
->axis_dress
, cr
);
487 set_scheme(AdgProjection
*projection
, AdgProjectionScheme scheme
)
489 AdgProjectionPrivate
*data
= projection
->data
;
491 if (data
->scheme
== scheme
)
494 data
->scheme
= scheme
;
496 adg_entity_invalidate((AdgEntity
*) projection
);