[tests] Implemented basic CpmlPrimitive test
[adg.git] / src / adg / adg-projection.c
blob9b62fba6894af3a863174bda1fd93996a97f2b5d
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011 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-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.
27 **/
29 /**
30 * AdgProjection:
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
34 **/
37 #include "adg-internal.h"
38 #include "adg-dress.h"
39 #include "adg-dress-builtins.h"
40 #include "adg-model.h"
41 #include "adg-trail.h"
42 #include "adg-path.h"
44 #include "adg-projection.h"
45 #include "adg-projection-private.h"
48 G_DEFINE_TYPE(AdgProjection, adg_projection, ADG_TYPE_ENTITY)
50 enum {
51 PROP_0,
52 PROP_SYMBOL_DRESS,
53 PROP_AXIS_DRESS,
54 PROP_SCHEME
58 static void _adg_get_property (GObject *object,
59 guint param_id,
60 GValue *value,
61 GParamSpec *pspec);
62 static void _adg_set_property (GObject *object,
63 guint param_id,
64 const GValue *value,
65 GParamSpec *pspec);
66 static void _adg_arrange (AdgEntity *entity);
67 static void _adg_render (AdgEntity *entity,
68 cairo_t *cr);
69 static void _adg_arrange_class (AdgProjectionClass *projection_class,
70 AdgProjectionScheme scheme);
73 static void
74 adg_projection_class_init(AdgProjectionClass *klass)
76 GObjectClass *gobject_class;
77 AdgEntityClass *entity_class;
78 GParamSpec *param;
79 AdgProjectionClassPrivate *data_class;
81 gobject_class = (GObjectClass *) klass;
82 entity_class = (AdgEntityClass *) klass;
84 g_type_class_add_private(klass, sizeof(AdgProjectionPrivate));
86 gobject_class->get_property = _adg_get_property;
87 gobject_class->set_property = _adg_set_property;
89 entity_class->arrange = _adg_arrange;
90 entity_class->render = _adg_render;
92 param = adg_param_spec_dress("symbol-dress",
93 P_("Symbol Dress"),
94 P_("The line dress to use for rendering the views of the projection"),
95 ADG_DRESS_LINE,
96 G_PARAM_READWRITE);
97 g_object_class_install_property(gobject_class, PROP_SYMBOL_DRESS, param);
99 param = adg_param_spec_dress("axis-dress",
100 P_("Axis Dress"),
101 P_("The line dress to use for rendering the axis of the projection scheme"),
102 ADG_DRESS_LINE,
103 G_PARAM_READWRITE);
104 g_object_class_install_property(gobject_class, PROP_AXIS_DRESS, param);
106 param = g_param_spec_enum("scheme",
107 P_("Projection Scheme"),
108 P_("The projection scheme to be represented"),
109 ADG_TYPE_PROJECTION_SCHEME,
110 ADG_PROJECTION_UNDEFINED,
111 G_PARAM_READWRITE);
112 g_object_class_install_property(gobject_class, PROP_SCHEME, param);
114 /* Initialize the private class data: the allocated struct is
115 * never freed as this type is registered statically, hence
116 * never destroyed. A better approach would be to use the old
117 * type initialization (no G_TYPE_DEFINE and friends) that
118 * allows to specify a custom class finalization method */
119 data_class = g_new(AdgProjectionClassPrivate, 1);
121 data_class->scheme = ADG_PROJECTION_UNDEFINED;
122 data_class->symbol = NULL;
123 data_class->axis = NULL;
124 data_class->extents.is_defined = FALSE;
126 klass->data_class = data_class;
129 static void
130 adg_projection_init(AdgProjection *projection)
132 AdgProjectionPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(projection, ADG_TYPE_PROJECTION,
133 AdgProjectionPrivate);
135 data->symbol_dress = ADG_DRESS_LINE;
136 data->axis_dress = ADG_DRESS_LINE;
137 data->scheme = ADG_PROJECTION_UNDEFINED;
139 projection->data = data;
142 static void
143 _adg_get_property(GObject *object, guint prop_id,
144 GValue *value, GParamSpec *pspec)
146 AdgProjectionPrivate *data = ((AdgProjection *) object)->data;
148 switch (prop_id) {
149 case PROP_SYMBOL_DRESS:
150 g_value_set_int(value, data->symbol_dress);
151 break;
152 case PROP_AXIS_DRESS:
153 g_value_set_int(value, data->axis_dress);
154 break;
155 case PROP_SCHEME:
156 g_value_set_enum(value, data->scheme);
157 break;
158 default:
159 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
160 break;
164 static void
165 _adg_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;
174 switch (prop_id) {
175 case PROP_SYMBOL_DRESS:
176 data->symbol_dress = g_value_get_int(value);
177 break;
178 case PROP_AXIS_DRESS:
179 data->axis_dress = g_value_get_int(value);
180 break;
181 case PROP_SCHEME:
182 data->scheme = g_value_get_enum(value);
183 adg_entity_invalidate((AdgEntity *) object);
184 break;
185 default:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
187 break;
193 * adg_projection_new:
194 * @scheme: the scheme represented by this projection
196 * Creates a new projection entity representing the selected @scheme.
197 * If @scheme is invalid, a projection symbol without a scheme is
198 * returned, that is #AdgProjection:scheme is set to
199 * #ADG_PROJECTION_UNDEFINED, and a warning is raised.
201 * Returns: the newly created projection entity
203 AdgProjection *
204 adg_projection_new(AdgProjectionScheme scheme)
206 return g_object_new(ADG_TYPE_PROJECTION, "scheme", scheme, NULL);
210 * adg_projection_set_symbol_dress:
211 * @projection: an #AdgProjection
212 * @dress: the new #AdgDress to use
214 * Sets a new line dress for rendering the symbol of @projection. The
215 * new dress must be a line dress: the check is done by calling
216 * adg_dress_are_related() with @dress and the old dress as
217 * arguments. Check out its documentation for further details.
219 * The default dress is a transparent line dress: the rendering
220 * callback will stroke the symbol using the default color with
221 * a predefined thickness.
223 void
224 adg_projection_set_symbol_dress(AdgProjection *projection, AdgDress dress)
226 g_return_if_fail(ADG_IS_PROJECTION(projection));
227 g_object_set(projection, "symbol-dress", dress, NULL);
231 * adg_projection_get_symbol_dress:
232 * @projection: an #AdgProjection
234 * Gets the line dress to be used in stroking the symbol of @projection.
236 * Returns: the requested line dress
238 AdgDress
239 adg_projection_get_symbol_dress(AdgProjection *projection)
241 AdgProjectionPrivate *data;
243 g_return_val_if_fail(ADG_IS_PROJECTION(projection), ADG_DRESS_UNDEFINED);
245 data = projection->data;
247 return data->symbol_dress;
251 * adg_projection_set_axis_dress:
252 * @projection: an #AdgProjection
253 * @dress: the new #AdgDress to use
255 * Sets a new line dress for rendering the axis of @projection.
256 * The new dress must be a line dress: the check is done by
257 * calling adg_dress_are_related() with @dress and the old
258 * dress as arguments. Check out its documentation for
259 * further details.
261 * The default dress is a transparent line dress: the rendering
262 * callback will stroke the axis using the default line style.
264 void
265 adg_projection_set_axis_dress(AdgProjection *projection, AdgDress dress)
267 g_return_if_fail(ADG_IS_PROJECTION(projection));
268 g_object_set(projection, "axis-dress", dress, NULL);
272 * adg_projection_get_axis_dress:
273 * @projection: an #AdgProjection
275 * Gets the line dress to be used in stroking the axis of @projection.
277 * Returns: the requested line dress
279 AdgDress
280 adg_projection_get_axis_dress(AdgProjection *projection)
282 AdgProjectionPrivate *data;
284 g_return_val_if_fail(ADG_IS_PROJECTION(projection), ADG_DRESS_UNDEFINED);
286 data = projection->data;
288 return data->axis_dress;
292 * adg_projection_set_scheme:
293 * @projection: an #AdgProjection
294 * @scheme: the new projection scheme
296 * Sets a new scheme on @projection. If @scheme is different
297 * from the old one, @projection is invalidated.
299 void
300 adg_projection_set_scheme(AdgProjection *projection,
301 AdgProjectionScheme scheme)
303 g_return_if_fail(ADG_IS_PROJECTION(projection));
304 g_object_set(projection, "scheme", scheme, NULL);
308 * adg_projection_get_scheme:
309 * @projection: an #AdgProjection
311 * Gets the scheme represented by @projection.
313 * Returns: the scheme of @projection
315 AdgProjectionScheme
316 adg_projection_get_scheme(AdgProjection *projection)
318 AdgProjectionPrivate *data;
320 g_return_val_if_fail(ADG_IS_PROJECTION(projection),
321 ADG_PROJECTION_UNDEFINED);
323 data = projection->data;
325 return data->scheme;
329 static void
330 _adg_arrange(AdgEntity *entity)
332 AdgProjectionPrivate *data;
333 AdgProjectionClass *projection_class;
334 AdgProjectionClassPrivate *data_class;
335 CpmlExtents extents;
337 data = ((AdgProjection *) entity)->data;
338 projection_class = ADG_PROJECTION_GET_CLASS(entity);
339 data_class = projection_class->data_class;
341 _adg_arrange_class(projection_class, data->scheme);
342 cpml_extents_copy(&extents, &data_class->extents);
344 cpml_extents_transform(&extents, adg_entity_get_local_matrix(entity));
345 cpml_extents_transform(&extents, adg_entity_get_global_matrix(entity));
346 adg_entity_set_extents(entity, &extents);
349 static void
350 _adg_arrange_class(AdgProjectionClass *projection_class,
351 AdgProjectionScheme scheme)
353 AdgProjectionClassPrivate *data_class;
354 AdgPath *symbol, *axis;
356 data_class = projection_class->data_class;
358 if (data_class->scheme == scheme)
359 return;
361 if (data_class->symbol != NULL)
362 g_object_unref(data_class->symbol);
364 if (data_class->axis != NULL)
365 g_object_unref(data_class->axis);
367 data_class->scheme = scheme;
369 switch(scheme) {
370 case ADG_PROJECTION_UNDEFINED:
371 symbol = NULL;
372 axis = NULL;
373 break;
374 case ADG_PROJECTION_FIRST_ANGLE:
375 symbol = adg_path_new();
376 adg_path_move_to_explicit(symbol, 4, 19);
377 adg_path_line_to_explicit(symbol, 24, 24);
378 adg_path_line_to_explicit(symbol, 24, 4);
379 adg_path_line_to_explicit(symbol, 4, 9);
380 adg_path_close(symbol);
381 adg_path_move_to_explicit(symbol, 49, 14);
382 adg_path_arc_to_explicit(symbol, 29, 14, 49, 14);
383 adg_path_move_to_explicit(symbol, 44, 14);
384 adg_path_arc_to_explicit(symbol, 34, 14, 44, 14);
386 axis = adg_path_new();
387 adg_path_move_to_explicit(axis, 0, 14);
388 adg_path_line_to_explicit(axis, 53, 14);
389 adg_path_move_to_explicit(axis, 39, 0);
390 adg_path_line_to_explicit(axis, 39, 28);
391 break;
392 case ADG_PROJECTION_THIRD_ANGLE:
393 symbol = adg_path_new();
394 adg_path_move_to_explicit(symbol, 29, 19);
395 adg_path_line_to_explicit(symbol, 49, 24);
396 adg_path_line_to_explicit(symbol, 49, 4);
397 adg_path_line_to_explicit(symbol, 29, 9);
398 adg_path_close(symbol);
399 adg_path_move_to_explicit(symbol, 24, 14);
400 adg_path_arc_to_explicit(symbol, 4, 14, 24, 14);
401 adg_path_move_to_explicit(symbol, 19, 14);
402 adg_path_arc_to_explicit(symbol, 9, 14, 19, 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, 14, 0);
408 adg_path_line_to_explicit(axis, 14, 28);
409 break;
410 default:
411 g_return_if_reached();
412 break;
415 data_class->symbol = symbol;
416 data_class->axis = axis;
417 data_class->extents.is_defined = FALSE;
419 if (axis != NULL)
420 cpml_extents_add(&data_class->extents,
421 adg_trail_get_extents((AdgTrail *) axis));
423 if (symbol != NULL)
424 cpml_extents_add(&data_class->extents,
425 adg_trail_get_extents((AdgTrail *) symbol));
428 static void
429 _adg_render(AdgEntity *entity, cairo_t *cr)
431 AdgProjectionClassPrivate *data_class;
432 AdgProjectionPrivate *data;
433 const cairo_path_t *cairo_path;
435 data_class = ADG_PROJECTION_GET_CLASS(entity)->data_class;
436 data = ((AdgProjection *) entity)->data;
438 cairo_transform(cr, adg_entity_get_global_matrix(entity));
440 if (data_class->symbol != NULL) {
441 cairo_path = adg_trail_get_cairo_path((AdgTrail *) data_class->symbol);
443 cairo_save(cr);
444 cairo_transform(cr, adg_entity_get_local_matrix(entity));
445 cairo_append_path(cr, cairo_path);
446 cairo_restore(cr);
448 cairo_set_line_width(cr, 2);
449 adg_entity_apply_dress(entity, data->symbol_dress, cr);
451 cairo_stroke(cr);
454 if (data_class->axis != NULL) {
455 const gdouble dashes[] = { 5, 2, 1, 2 };
457 cairo_path = adg_trail_get_cairo_path((AdgTrail *) data_class->axis);
459 cairo_save(cr);
460 cairo_transform(cr, adg_entity_get_local_matrix(entity));
461 cairo_append_path(cr, cairo_path);
462 cairo_restore(cr);
464 cairo_set_line_width(cr, 1);
465 cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), -1.5);
466 adg_entity_apply_dress(entity, data->axis_dress, cr);
468 cairo_stroke(cr);