[AdgContainer] Updated to new invalidate signal
[adg.git] / demo / adg-demo.c
blob1fac5e9e4b5ec9f174cff4f12e1e73422d3714af
1 #include <adg/adg.h>
2 #include <math.h>
4 #include "demo.h"
7 static AdgCanvas * sample_canvas (void);
8 static AdgCanvas * operations_canvas (void);
9 static void to_pdf (AdgWidget *widget,
10 GtkWidget *caller);
11 static void to_png (AdgWidget *widget,
12 GtkWidget *caller);
13 static void to_ps (AdgWidget *widget,
14 GtkWidget *caller);
17 int
18 main(gint argc, gchar **argv)
20 gchar *path;
21 GtkBuilder *builder;
22 GError *error;
23 GtkWidget *window, *sample, *operations;
25 gtk_init(&argc, &argv);
27 path = demo_find_data_file("adg-demo.ui");
28 if (path == NULL) {
29 g_print("adg-demo.ui not found!\n");
30 return 1;
33 builder = gtk_builder_new();
34 error = NULL;
36 gtk_builder_add_from_file(builder, path, &error);
37 if (error != NULL) {
38 g_print("%s\n", error->message);
39 return 2;
42 window = (GtkWidget *) gtk_builder_get_object(builder, "wndMain");
44 sample = (GtkWidget *) gtk_builder_get_object(builder, "areaSample");
45 adg_widget_set_canvas(ADG_WIDGET(sample), sample_canvas());
47 operations = (GtkWidget *) gtk_builder_get_object(builder, "areaOperations");
48 adg_widget_set_canvas(ADG_WIDGET(operations), operations_canvas());
50 /* Connect signals */
51 g_signal_connect(window, "delete-event",
52 G_CALLBACK(gtk_main_quit), NULL);
53 g_signal_connect(gtk_builder_get_object(builder, "btnQuit"),
54 "clicked", G_CALLBACK(gtk_main_quit), NULL);
55 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPng"),
56 "clicked", G_CALLBACK(to_png), sample);
57 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPdf"),
58 "clicked", G_CALLBACK(to_pdf), sample);
59 g_signal_connect_swapped(gtk_builder_get_object(builder, "btnPs"),
60 "clicked", G_CALLBACK(to_ps), sample);
62 g_object_unref(builder);
64 gtk_widget_show_all(window);
65 gtk_main();
67 return 0;
71 /**********************************************
72 * A sample mechanical part example
73 **********************************************/
75 #define SQRT3 1.732050808
76 #define CHAMFER 0.3
78 typedef struct _SampleData SampleData;
80 struct _SampleData {
81 gdouble A, B, C;
82 gdouble D1, D2, D3, D4, D5, D6, D7;
83 gdouble RD34, RD56;
84 gdouble LD2, LD3, LD5, LD6, LD7;
87 static void sample_get (SampleData *data);
88 static AdgPath *sample_path (const SampleData *data);
89 static void sample_add_dimensions (AdgCanvas *canvas,
90 const SampleData *data);
91 static void sample_add_stuff (AdgCanvas *canvas,
92 const SampleData *data);
95 static AdgCanvas *
96 sample_canvas(void)
98 SampleData data;
99 AdgPath *path;
100 AdgCanvas *canvas;
101 AdgContainer *container;
102 AdgEntity *entity;
103 AdgMatrix map;
105 sample_get(&data);
106 path = sample_path(&data);
107 canvas = adg_canvas_new();
108 container = (AdgContainer *) canvas;
110 entity = adg_stroke_new(path);
111 adg_container_add(container, entity);
113 sample_add_dimensions(canvas, &data);
114 sample_add_stuff(canvas, &data);
116 cairo_matrix_init_translate(&map, 100, 70);
117 cairo_matrix_scale(&map, 6.883, 6.883);
118 cairo_matrix_translate(&map, 0, 10);
119 adg_entity_set_local_map(ADG_ENTITY(container), &map);
121 return canvas;
124 static void
125 sample_get(SampleData *data)
127 data->A = 52.3;
128 data->B = 20.6;
129 data->C = 2;
130 data->D1 = 9.3;
131 data->D2 = 6.5;
132 data->D3 = 11.9;
133 data->D4 = 6.5;
134 data->D5 = 4.5;
135 data->D6 = 7.2;
136 data->D7 = 3.;
137 data->RD34 = 1.;
138 data->LD2 = 7.;
139 data->LD3 = 3.5;
140 data->LD5 = 5.;
141 data->LD6 = 1.;
142 data->LD7 = 0.5;
145 static AdgPath *
146 sample_path(const SampleData *data)
148 AdgPath *path;
149 double x, y;
150 AdgSegment segment_org;
151 AdgSegment *segment;
152 cairo_matrix_t matrix;
154 path = (AdgPath *) adg_path_new();
156 adg_path_move_to(path, 0, data->D1 / 2);
157 adg_path_line_to(path, data->A - data->B - data->LD2, data->D1 / 2);
158 y = (data->D1 - data->D2) / 2;
159 adg_path_line_to(path, data->A - data->B - data->LD2 + y * SQRT3, data->D1 / 2 - y);
160 adg_path_line_to(path, data->A - data->B, data->D2 / 2);
161 adg_path_fillet(path, 0.4);
162 adg_path_line_to(path, data->A - data->B, data->D3 / 2);
163 adg_path_chamfer(path, CHAMFER, CHAMFER);
164 adg_path_line_to(path, data->A - data->B + data->LD3, data->D3 / 2);
165 adg_path_chamfer(path, CHAMFER, CHAMFER);
166 adg_path_line_to(path, data->A - data->B + data->LD3, data->D4 / 2);
167 adg_path_fillet(path, data->RD34);
168 adg_path_line_to(path, data->A - data->C - data->LD5, data->D4 / 2);
169 y = (data->D4 - data->D5) / 2;
170 adg_path_line_to(path, data->A - data->C - data->LD5 + y, data->D4 / 2 - y);
171 adg_path_line_to(path, data->A - data->C, data->D5 / 2);
172 adg_path_fillet(path, 0.2);
173 adg_path_line_to(path, data->A - data->C, data->D6 / 2);
174 adg_path_fillet(path, 0.1);
175 adg_path_line_to(path, data->A - data->C + data->LD6, data->D6 / 2);
176 x = data->C - data->LD7 - data->LD6;
177 y = x / SQRT3;
178 adg_path_line_to(path, data->A - data->C + data->LD6 + x, data->D6 / 2 - y);
179 adg_path_line_to(path, data->A - data->LD7, data->D7 / 2);
180 adg_path_line_to(path, data->A, data->D7 / 2);
182 /* Build the rounded shape by duplicating the first segment of
183 * the current path, reflecting it on the y=0 axis, reversing and
184 * joining it the result to the original path */
185 cpml_segment_from_cairo(&segment_org, adg_path_get_cpml_path(path));
186 segment = adg_segment_deep_dup(&segment_org);
187 cpml_segment_reverse(segment);
188 adg_matrix_init_reflection(&matrix, 0);
189 cpml_segment_transform(segment, &matrix);
190 segment->data[0].header.type = CAIRO_PATH_LINE_TO;
192 adg_path_append_segment(path, segment);
194 g_free(segment);
196 adg_path_close(path);
197 return path;
200 static void
201 sample_add_dimensions(AdgCanvas *canvas, const SampleData *data)
203 AdgEntity *entity;
204 double x, y;
206 /* NORTH */
208 /* LD2 */
209 entity = adg_ldim_new_full_explicit(data->A - data->B - data->LD2, -data->D1 / 2, data->A - data->B,
210 -data->D3 / 2 + CHAMFER, ADG_DIR_UP, 0,
211 -data->D3 / 2);
212 adg_container_add(ADG_CONTAINER(canvas), entity);
214 /* LD3 */
215 entity = adg_ldim_new_full_explicit(data->A - data->B, -data->D3 / 2 + CHAMFER, data->A - data->B + data->LD3,
216 -data->D3 / 2 + CHAMFER, ADG_DIR_UP, 0,
217 -data->D3 / 2);
218 adg_container_add(ADG_CONTAINER(canvas), entity);
220 /* SOUTH */
222 /* B */
223 entity = adg_ldim_new_full_explicit(data->A - data->B, data->D3 / 2 - CHAMFER, data->A, data->D7 / 2,
224 ADG_DIR_DOWN, 0, data->D3 / 2);
225 adg_dim_set_tolerances(ADG_DIM(entity), "+0.1", NULL);
226 adg_container_add(ADG_CONTAINER(canvas), entity);
228 /* A */
229 entity = adg_ldim_new_full_explicit(0, data->D1 / 2, data->A, data->D7 / 2,
230 ADG_DIR_DOWN, 0, data->D3 / 2);
231 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
232 adg_dim_set_level(ADG_DIM(entity), 2);
233 adg_container_add(ADG_CONTAINER(canvas), entity);
235 /* EAST */
237 /* D3 */
238 x = data->A - data->B + data->LD3 - CHAMFER;
239 entity = adg_ldim_new_full_explicit(x, -data->D3 / 2, x, data->D3 / 2,
240 ADG_DIR_RIGHT, data->A, 0);
241 adg_dim_set_tolerances(ADG_DIM(entity), "-0.25", NULL);
242 adg_dim_set_level(ADG_DIM(entity), 5);
243 adg_container_add(ADG_CONTAINER(canvas), entity);
245 /* D6 */
246 x = data->A - data->C + data->LD6;
247 entity = adg_ldim_new_full_explicit(x, -data->D6 / 2, x, data->D6 / 2,
248 ADG_DIR_RIGHT, data->A, 0);
249 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
250 adg_dim_set_level(ADG_DIM(entity), 4);
251 adg_container_add(ADG_CONTAINER(canvas), entity);
253 /* D4 */
254 x = data->A - data->C - data->LD5;
255 entity = adg_ldim_new_full_explicit(x, -data->D4 / 2, x, data->D4 / 2,
256 ADG_DIR_RIGHT, data->A, 0);
257 adg_dim_set_level(ADG_DIM(entity), 3);
258 adg_container_add(ADG_CONTAINER(canvas), entity);
260 /* D5 */
261 x = data->A - data->C;
262 entity = adg_ldim_new_full_explicit(x, -data->D5 / 2, x, data->D5 / 2,
263 ADG_DIR_RIGHT, data->A, 0);
264 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
265 adg_dim_set_level(ADG_DIM(entity), 2);
266 adg_container_add(ADG_CONTAINER(canvas), entity);
268 /* D7 */
269 entity = adg_ldim_new_full_explicit(data->A, -data->D7 / 2, data->A, data->D7 / 2,
270 ADG_DIR_RIGHT, data->A, 0);
271 adg_container_add(ADG_CONTAINER(canvas), entity);
273 /* WEST */
275 /* D1 */
276 entity = adg_ldim_new_full_explicit(0, -data->D1 / 2, 0, data->D1 / 2,
277 ADG_DIR_LEFT, 0, 0);
278 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
279 adg_dim_set_level(ADG_DIM(entity), 2);
280 adg_container_add(ADG_CONTAINER(canvas), entity);
282 /* D2 */
283 y = (data->D1 - data->D2) / 2;
284 x = data->A - data->B - data->LD2 + y * SQRT3;
285 entity = adg_ldim_new_full_explicit(x, -data->D2 / 2, x, data->D2 / 2,
286 ADG_DIR_LEFT, 0, 0);
287 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
288 adg_container_add(ADG_CONTAINER(canvas), entity);
291 static void
292 sample_add_stuff(AdgCanvas *canvas, const SampleData *data)
294 AdgEntity *toy_text;
295 AdgMatrix map;
297 toy_text = adg_toy_text_new("Rotate the mouse wheel to zoom in and out");
298 cairo_matrix_init_translate(&map, 0., data->D3 / 2);
299 adg_entity_set_local_map(toy_text, &map);
300 cairo_matrix_init_translate(&map, 10., 30. + 30. * 2);
301 adg_entity_set_global_map(toy_text, &map);
302 adg_container_add(ADG_CONTAINER(canvas), toy_text);
304 toy_text = adg_toy_text_new("Keep the wheel pressed while dragging the mouse to translate");
305 cairo_matrix_init_translate(&map, 0., data->D3 / 2);
306 adg_entity_set_local_map(toy_text, &map);
307 cairo_matrix_init_translate(&map, 10., 45. + 30. * 2);
308 adg_entity_set_global_map(toy_text, &map);
309 adg_container_add(ADG_CONTAINER(canvas), toy_text);
313 #if defined(CAIRO_HAS_PNG_FUNCTIONS) || defined(CAIRO_HAS_PDF_SURFACE) || defined(CAIRO_HAS_PS_SURFACE)
315 /* Only needed if there is at least one supported surface */
316 static void
317 file_generated(GtkWidget *caller, const gchar *file)
319 GtkWindow *window;
320 GtkWidget *dialog;
322 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
323 dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_MODAL,
324 GTK_MESSAGE_INFO,
325 GTK_BUTTONS_CLOSE,
326 "The requested operation generated\n"
327 "<b>%s</b> in the current directory.",
328 file);
329 gtk_window_set_title(GTK_WINDOW(dialog), "Operation completed");
330 gtk_dialog_run(GTK_DIALOG(dialog));
331 gtk_widget_destroy(dialog);
334 #endif
336 #if !defined(CAIRO_HAS_PNG_FUNCTIONS) || !defined(CAIRO_HAS_PDF_SURFACE) || !defined(CAIRO_HAS_PS_SURFACE)
338 /* Only needed if there is a missing surface */
339 static void
340 missing_feature(GtkWidget *caller, const gchar *feature)
342 GtkWindow *window;
343 GtkWidget *dialog;
345 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
346 dialog = gtk_message_dialog_new(window, GTK_DIALOG_MODAL,
347 GTK_MESSAGE_WARNING,
348 GTK_BUTTONS_OK,
349 "The provided cairo library\n"
350 "was compiled with no %s support!",
351 feature);
352 gtk_window_set_title(GTK_WINDOW(dialog), "Missing feature");
353 gtk_dialog_run(GTK_DIALOG(dialog));
354 gtk_widget_destroy(dialog);
357 #endif
360 #ifdef CAIRO_HAS_PNG_FUNCTIONS
362 static void
363 to_png(AdgWidget *widget, GtkWidget *caller)
365 cairo_surface_t *surface;
366 cairo_t *cr;
368 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 800, 600);
369 cr = cairo_create(surface);
370 cairo_surface_destroy(surface);
372 /* Rendering process */
373 adg_entity_render(ADG_ENTITY(adg_widget_get_canvas(widget)), cr);
375 cairo_show_page(cr);
376 cairo_surface_write_to_png(surface, "test.png");
377 cairo_destroy(cr);
379 file_generated(caller, "test.png");
382 #else
384 static void
385 to_png(AdgWidget *widget, GtkWidget *caller)
387 missing_feature(caller, "PNG");
390 #endif
392 #ifdef CAIRO_HAS_PDF_SURFACE
394 #include <cairo-pdf.h>
396 static void
397 to_pdf(AdgWidget *widget, GtkWidget *caller)
399 cairo_surface_t *surface;
400 cairo_t *cr;
402 surface = cairo_pdf_surface_create("test.pdf", 841, 595);
403 cr = cairo_create(surface);
404 cairo_surface_destroy(surface);
406 adg_entity_render(ADG_ENTITY(adg_widget_get_canvas(widget)), cr);
408 cairo_show_page(cr);
409 cairo_destroy(cr);
411 file_generated(caller, "test.pdf");
414 #else
416 static void
417 to_pdf(AdgWidget *widget, GtkWidget *caller)
419 missing_feature(caller, "PDF");
422 #endif
424 #ifdef CAIRO_HAS_PS_SURFACE
426 #include <cairo-ps.h>
428 static void
429 to_ps(AdgWidget *widget, GtkWidget *caller)
431 cairo_surface_t *surface;
432 cairo_t *cr;
434 /* Surface creation: A4 size */
435 surface = cairo_ps_surface_create("test.ps", 841, 595);
436 cairo_ps_surface_dsc_comment(surface,
437 "%%Title: Automatic Drawing Generation (ADG) demo");
438 cairo_ps_surface_dsc_comment(surface,
439 "%%Copyright: Copyright (C) 2006-2009 Fontana Nicola");
440 cairo_ps_surface_dsc_comment(surface, "%%Orientation: Portrait");
442 cairo_ps_surface_dsc_begin_setup(surface);
444 cairo_ps_surface_dsc_begin_page_setup(surface);
445 cairo_ps_surface_dsc_comment(surface,
446 "%%IncludeFeature: *PageSize A4");
448 cr = cairo_create(surface);
449 cairo_surface_destroy(surface);
451 adg_entity_render(ADG_ENTITY(adg_widget_get_canvas(widget)), cr);
453 cairo_show_page(cr);
454 cairo_destroy(cr);
456 file_generated(caller, "test.ps");
459 #else
461 static void
462 to_ps(AdgWidget *widget, GtkWidget *caller)
464 missing_feature(caller, "PostScript");
467 #endif
470 /**********************************************
471 * Test case for basic operations,
472 * such as chamfer and fillet
473 **********************************************/
475 static AdgPath * operations_chamfer (const AdgPath *path,
476 gdouble delta1,
477 gdouble delta2);
478 static AdgPath * operations_fillet (const AdgPath *path,
479 gdouble radius);
481 static AdgCanvas *
482 operations_canvas(void)
484 AdgPath *path, *chamfer_path, *fillet_path;
485 AdgCanvas *canvas;
486 AdgContainer *container;
487 AdgEntity *entity;
488 AdgMatrix map;
490 /* Build the base model */
491 path = (AdgPath *) adg_path_new();
493 adg_path_move_to(path, 2, 0);
494 adg_path_line_to(path, 0, 5);
495 adg_path_line_to(path, 2, 2);
496 adg_path_line_to(path, 0, 8);
497 adg_path_line_to(path, 2, 8);
498 adg_path_line_to(path, 2, 10);
499 adg_path_line_to(path, 3, 10);
500 adg_path_line_to(path, 10, 9);
501 adg_path_line_to(path, 5, 5);
502 adg_path_line_to(path, 3, 0);
503 adg_path_close(path);
505 /* Build the chamfer model */
506 chamfer_path = operations_chamfer(path, 0.25, 0.25);
508 /* Build the fillet model */
509 fillet_path = operations_fillet(path, 0.20);
511 /* Create the canvas */
512 canvas = adg_canvas_new();
514 /* Add the original shape */
515 container = (AdgContainer *) adg_container_new();
516 adg_container_add(ADG_CONTAINER(canvas), ADG_ENTITY(container));
517 adg_container_add(container, adg_stroke_new(path));
518 entity = adg_toy_text_new("Original shape");
519 cairo_matrix_init_translate(&map, 5, 10);
520 adg_entity_set_local_map(entity, &map);
521 cairo_matrix_init_translate(&map, -50, 20);
522 adg_entity_set_global_map(entity, &map);
523 adg_container_add(ADG_CONTAINER(canvas), entity);
525 /* Add the shape with 0.25x0.25 chamfer */
526 container = (AdgContainer *) adg_container_new();
527 cairo_matrix_init_translate(&map, 15., 0.);
528 adg_entity_set_local_map(ADG_ENTITY(container), &map);
529 adg_container_add(ADG_CONTAINER(canvas), ADG_ENTITY(container));
530 adg_container_add(container, adg_stroke_new(chamfer_path));
531 entity = adg_toy_text_new("Shape with 0.25x0.25 chamfer");
532 cairo_matrix_init_translate(&map, 5, 10);
533 adg_entity_set_local_map(entity, &map);
534 cairo_matrix_init_translate(&map, -120, 20);
535 adg_entity_set_global_map(entity, &map);
536 adg_container_add(container, entity);
538 /* Add the shape with fillets with 0.20 of radius */
539 container = (AdgContainer *) adg_container_new();
540 cairo_matrix_init_translate(&map, 30., 0.);
541 adg_entity_set_local_map(ADG_ENTITY(container), &map);
542 adg_container_add(ADG_CONTAINER(canvas), ADG_ENTITY(container));
543 adg_container_add(container, adg_stroke_new(fillet_path));
544 entity = adg_toy_text_new("Shape with R=20 fillet");
545 cairo_matrix_init_translate(&map, 5, 10);
546 adg_entity_set_local_map(entity, &map);
547 cairo_matrix_init_translate(&map, -90, 20);
548 adg_entity_set_global_map(entity, &map);
549 adg_container_add(container, entity);
551 /* Set a decent start position and zoom */
552 cairo_matrix_init_translate(&map, 10, -140);
553 cairo_matrix_scale(&map, 15, 15);
554 cairo_matrix_translate(&map, 0, 10);
555 adg_entity_set_local_map(ADG_ENTITY(canvas), &map);
557 return canvas;
560 static AdgPath *
561 operations_chamfer(const AdgPath *model, gdouble delta1, gdouble delta2)
563 AdgPath *path;
564 CpmlSegment segment;
565 CpmlPrimitive primitive;
567 path = (AdgPath *) adg_path_new();
568 cpml_segment_from_cairo(&segment, adg_path_get_cpml_path((AdgPath *) model));
569 cpml_primitive_from_segment(&primitive, &segment);
571 adg_path_move_to(path, (primitive.org)->point.x, (primitive.org)->point.y);
573 do {
574 adg_path_append_primitive(path, &primitive);
575 if (primitive.data[0].header.type == CAIRO_PATH_LINE_TO)
576 adg_path_chamfer(path, delta1, delta2);
577 } while (cpml_primitive_next(&primitive));
579 return path;
582 static AdgPath *
583 operations_fillet(const AdgPath *model, gdouble radius)
585 AdgPath *path;
586 CpmlSegment segment;
587 CpmlPrimitive primitive;
589 path = (AdgPath *) adg_path_new();
590 cpml_segment_from_cairo(&segment, adg_path_get_cpml_path((AdgPath *) model));
591 cpml_primitive_from_segment(&primitive, &segment);
593 adg_path_move_to(path, (primitive.org)->point.x, (primitive.org)->point.y);
595 do {
596 adg_path_append_primitive(path, &primitive);
597 if (primitive.data[0].header.type == CAIRO_PATH_LINE_TO)
598 adg_path_fillet(path, radius);
599 } while (cpml_primitive_next(&primitive));
601 return path;