[CpmlSegment] Implemented a decent offseting curve algorithm
[adg.git] / demo / adg-demo.c
blobfe995d6461a51a17e25e5c39cccd73a2ce8b2543
1 #include <adg/adg.h>
2 #include <gtk/gtk.h>
3 #include <math.h>
6 #ifndef G_SQRT3
7 #define G_SQRT3 1.732050808
8 #endif
10 #define CHAMFER 0.3
12 typedef struct _Piston Piston;
14 struct _Piston {
15 gdouble A, B, C;
16 gdouble D1, D2, D3, D4, D5, D6, D7;
17 gdouble RD34, RD56;
18 gdouble LD2, LD3, LD5, LD6, LD7;
22 static void fill_piston_model (Piston *piston);
23 static void add_piston_dimensions (AdgCanvas *canvas,
24 Piston *piston);
25 static void add_sample_stuff (AdgCanvas *canvas);
26 static void piston_path_extern (AdgEntity *entity,
27 cairo_t *cr,
28 gpointer user_data);
29 static void piston_expose (GtkWidget *widget,
30 GdkEventExpose *event,
31 AdgCanvas *canvas);
32 static void to_pdf (AdgCanvas *canvas,
33 GtkWidget *caller);
34 static void to_png (AdgCanvas *canvas,
35 GtkWidget *caller);
36 static void to_ps (AdgCanvas *canvas,
37 GtkWidget *caller);
38 static void missing_feature (GtkWidget *caller,
39 const gchar *feature);
40 static void file_generated (GtkWidget *caller,
41 const gchar *file);
43 static Piston model;
46 int
47 main(gint argc, gchar **argv)
49 GtkWidget *window;
50 GtkWidget *vbox;
51 GtkWidget *button_box;
52 GtkWidget *widget;
53 AdgCanvas *canvas;
54 AdgEntity *path;
56 gtk_init(&argc, &argv);
58 /* Fill the model structure with some data */
59 fill_piston_model(&model);
61 /* Create the canvas and populate it */
62 canvas = adg_canvas_new();
64 path = adg_path_new(piston_path_extern, NULL);
65 adg_container_add(ADG_CONTAINER(canvas), path);
67 add_piston_dimensions(canvas, &model);
68 add_sample_stuff(canvas);
70 /* User interface stuff */
71 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
72 g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
74 vbox = gtk_vbox_new(FALSE, 0);
76 widget = gtk_drawing_area_new();
77 gtk_widget_set_size_request(widget, 790, 240);
78 g_signal_connect(widget, "expose-event", G_CALLBACK(piston_expose),
79 canvas);
80 gtk_container_add(GTK_CONTAINER(vbox), widget);
82 button_box = gtk_hbutton_box_new();
83 gtk_container_set_border_width(GTK_CONTAINER(button_box), 5);
84 gtk_box_set_spacing(GTK_BOX(button_box), 5);
85 gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END);
86 gtk_box_pack_end(GTK_BOX(vbox), button_box, FALSE, TRUE, 0);
88 widget = gtk_button_new_with_mnemonic("P_NG image");
89 g_signal_connect_swapped(widget, "clicked", G_CALLBACK(to_png), canvas);
90 gtk_container_add(GTK_CONTAINER(button_box), widget);
92 widget = gtk_button_new_with_mnemonic("P_DF file");
93 g_signal_connect_swapped(widget, "clicked", G_CALLBACK(to_pdf), canvas);
94 gtk_container_add(GTK_CONTAINER(button_box), widget);
96 widget = gtk_button_new_with_mnemonic("_PostScript");
97 g_signal_connect_swapped(widget, "clicked", G_CALLBACK(to_ps), canvas);
98 gtk_container_add(GTK_CONTAINER(button_box), widget);
100 widget = gtk_button_new_from_stock(GTK_STOCK_QUIT);
101 g_signal_connect(widget, "clicked", G_CALLBACK(gtk_main_quit), NULL);
102 gtk_container_add(GTK_CONTAINER(button_box), widget);
104 gtk_container_add(GTK_CONTAINER(window), vbox);
105 gtk_widget_show_all(window);
107 gtk_main();
109 return 0;
113 static void
114 fill_piston_model(Piston *piston)
116 piston->A = 62.3;
117 piston->B = 20.6;
118 piston->C = 2;
119 piston->D1 = 9.3;
120 piston->D2 = 6.5;
121 piston->D3 = 11.9;
122 piston->D4 = 6.5;
123 piston->D5 = 4.5;
124 piston->D6 = 7.2;
125 piston->D7 = 3.0;
126 piston->RD34 = 1.0;
127 piston->LD2 = 7.0;
128 piston->LD3 = 3.5;
129 piston->LD5 = 5.0;
130 piston->LD6 = 1.0;
131 piston->LD7 = 0.5;
134 static void
135 add_piston_dimensions(AdgCanvas *canvas, Piston *piston)
137 double A, B, C;
138 double D1, D2, D3, D4, D5, D6, D7;
139 double LD2, LD3, LD5, LD6, LD7;
140 double RD34, RD56;
141 AdgEntity *entity;
142 double x, y;
144 A = piston->A;
145 B = piston->B;
146 C = piston->C;
147 D1 = piston->D1;
148 D2 = piston->D2;
149 D3 = piston->D3;
150 D4 = piston->D4;
151 D5 = piston->D5;
152 D6 = piston->D6;
153 D7 = piston->D7;
154 LD2 = piston->LD2;
155 LD3 = piston->LD3;
156 LD5 = piston->LD5;
157 LD6 = piston->LD6;
158 LD7 = piston->LD7;
159 RD34 = piston->RD34;
160 RD56 = piston->RD56;
163 /* North */
165 /* LD2 */
166 entity =
167 adg_ldim_new_full_explicit(A - B - LD2, -D1 / 2.0, A - B,
168 -D3 / 2.0 + CHAMFER, CPML_DIR_UP, 0.0,
169 -D3 / 2.0);
170 adg_container_add(ADG_CONTAINER(canvas), entity);
172 /* LD3 */
173 entity =
174 adg_ldim_new_full_explicit(A - B, -D3 / 2.0 + CHAMFER, A - B + LD3,
175 -D3 / 2.0 + CHAMFER, CPML_DIR_UP, 0.0,
176 -D3 / 2.0);
177 adg_container_add(ADG_CONTAINER(canvas), entity);
180 /* South */
182 /* B */
183 entity =
184 adg_ldim_new_full_explicit(A - B, D3 / 2.0 - CHAMFER, A, D7 / 2.0,
185 CPML_DIR_DOWN, 0.0, D3 / 2.0);
186 adg_dim_set_tolerances(ADG_DIM(entity), "+0.1", NULL);
187 adg_container_add(ADG_CONTAINER(canvas), entity);
189 /* A */
190 entity =
191 adg_ldim_new_full_explicit(0.0, D1 / 2.0, A, D7 / 2.0,
192 CPML_DIR_DOWN, 0.0, D3 / 2.0);
193 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
194 adg_dim_set_level(ADG_DIM(entity), 2.0);
195 adg_container_add(ADG_CONTAINER(canvas), entity);
198 /* East */
200 /* D3 */
201 x = A - B + LD3 - CHAMFER;
202 entity =
203 adg_ldim_new_full_explicit(x, -D3 / 2.0, x, D3 / 2.0,
204 CPML_DIR_RIGHT, A, 0.0);
205 adg_dim_set_tolerances(ADG_DIM(entity), "-0.25", NULL);
206 adg_dim_set_level(ADG_DIM(entity), 5.0);
207 adg_container_add(ADG_CONTAINER(canvas), entity);
209 /* D6 */
210 x = A - C + LD6;
211 entity =
212 adg_ldim_new_full_explicit(x, -D6 / 2.0, x, D6 / 2.0,
213 CPML_DIR_RIGHT, A, 0.0);
214 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
215 adg_dim_set_level(ADG_DIM(entity), 4.0);
216 adg_container_add(ADG_CONTAINER(canvas), entity);
218 /* D4 */
219 x = A - C - LD5;
220 entity =
221 adg_ldim_new_full_explicit(x, -D4 / 2.0, x, D4 / 2.0,
222 CPML_DIR_RIGHT, A, 0.0);
223 adg_dim_set_level(ADG_DIM(entity), 3.0);
224 adg_container_add(ADG_CONTAINER(canvas), entity);
226 /* D5 */
227 x = A - C;
228 entity =
229 adg_ldim_new_full_explicit(x, -D5 / 2.0, x, D5 / 2.0,
230 CPML_DIR_RIGHT, A, 0.0);
231 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
232 adg_dim_set_level(ADG_DIM(entity), 2.0);
233 adg_container_add(ADG_CONTAINER(canvas), entity);
235 /* D7 */
236 entity =
237 adg_ldim_new_full_explicit(A, -D7 / 2.0, A, D7 / 2.0,
238 CPML_DIR_RIGHT, A, 0.0);
239 adg_container_add(ADG_CONTAINER(canvas), entity);
242 /* West */
244 /* D1 */
245 entity =
246 adg_ldim_new_full_explicit(0.0, -D1 / 2.0, 0.0, D1 / 2.0,
247 CPML_DIR_LEFT, 0.0, 0.0);
248 adg_dim_set_tolerances(ADG_DIM(entity), "+0.05", "-0.05");
249 adg_dim_set_level(ADG_DIM(entity), 2.0);
250 adg_container_add(ADG_CONTAINER(canvas), entity);
252 /* D2 */
253 y = (D1 - D2) / 2.0;
254 x = A - B - LD2 + y * G_SQRT3;
255 entity =
256 adg_ldim_new_full_explicit(x, -D2 / 2.0, x, D2 / 2.0,
257 CPML_DIR_LEFT, 0.0, 0.0);
258 adg_dim_set_tolerances(ADG_DIM(entity), "-0.1", NULL);
259 adg_container_add(ADG_CONTAINER(canvas), entity);
262 static void
263 add_sample_stuff(AdgCanvas *canvas)
265 AdgEntity *toy_text;
267 toy_text = adg_toy_text_new("Horizontal toy_text above the piston");
268 adg_translatable_set_origin_explicit(ADG_TRANSLATABLE(toy_text),
269 0., -4.65,
270 0., -5.);
271 adg_container_add(ADG_CONTAINER(canvas), toy_text);
273 toy_text = adg_toy_text_new("toy_text");
274 adg_translatable_set_origin_explicit(ADG_TRANSLATABLE(toy_text),
275 0., 4.65,
276 0., -5.);
277 adg_rotable_set_angle(ADG_ROTABLE(toy_text), M_PI * 3./2.);
278 adg_container_add(ADG_CONTAINER(canvas), toy_text);
281 static void
282 piston_path_extern(AdgEntity *entity, cairo_t *cr, gpointer user_data)
284 Piston *piston;
285 double A, B, C;
286 double D1, D2, D3, D4, D5, D6, D7;
287 double LD2, LD3, LD5, LD6, LD7;
288 double RD34, RD56;
289 double x, y;
290 cairo_path_t *path;
291 CpmlSegment segment;
292 AdgMatrix matrix;
294 piston = &model;
296 A = piston->A;
297 B = piston->B;
298 C = piston->C;
299 D1 = piston->D1;
300 D2 = piston->D2;
301 D3 = piston->D3;
302 D4 = piston->D4;
303 D5 = piston->D5;
304 D6 = piston->D6;
305 D7 = piston->D7;
306 LD2 = piston->LD2;
307 LD3 = piston->LD3;
308 LD5 = piston->LD5;
309 LD6 = piston->LD6;
310 LD7 = piston->LD7;
311 RD34 = piston->RD34;
312 RD56 = piston->RD56;
314 cairo_move_to(cr, 0, D1 / 2.0);
315 cairo_line_to(cr, A - B - LD2, D1 / 2.0);
316 y = (D1 - D2) / 2.0;
317 cairo_line_to(cr, A - B - LD2 + y * G_SQRT3, D1 / 2.0 - y);
318 cairo_line_to(cr, A - B, D2 / 2.0);
319 cairo_line_to(cr, A - B, D3 / 2.0 - CHAMFER);
320 cairo_line_to(cr, A - B + CHAMFER, D3 / 2.0);
321 cairo_line_to(cr, A - B + LD3 - CHAMFER, D3 / 2.0);
322 cairo_line_to(cr, A - B + LD3, D3 / 2.0 - CHAMFER);
323 x = A - B + LD3 + RD34;
324 y = D4 / 2.0 + RD34;
325 cairo_arc(cr, x, y, RD34, G_PI, 3.0 * G_PI_2);
326 cairo_line_to(cr, A - C - LD5, D4 / 2.0);
327 y = (D4 - D5) / 2.0;
328 cairo_line_to(cr, A - C - LD5 + y, D4 / 2.0 - y);
329 cairo_line_to(cr, A - C, D5 / 2.0);
330 cairo_line_to(cr, A - C, D6 / 2.0);
331 cairo_line_to(cr, A - C + LD6, D6 / 2.0);
332 x = C - LD7 - LD6;
333 y = x / G_SQRT3;
334 cairo_line_to(cr, A - C + LD6 + x, D6 / 2.0 - y);
335 cairo_line_to(cr, A - LD7, D7 / 2.0);
336 cairo_line_to(cr, A, D7 / 2.0);
338 /* Build the shape by reflecting the current path, reversing the order
339 * and joining the result to the current path */
340 path = cairo_copy_path(cr);
341 cpml_segment_init(&segment, path);
342 cpml_segment_reverse(&segment);
343 adg_matrix_init_reflection(&matrix, 0);
344 cpml_segment_transform(&segment, &matrix);
345 path->data[0].header.type = CAIRO_PATH_LINE_TO;
346 cairo_append_path(cr, path);
347 cairo_path_destroy(path);
348 cairo_close_path(cr);
351 static void
352 piston_expose(GtkWidget *widget, GdkEventExpose *event, AdgCanvas *canvas)
354 cairo_t *cr;
355 gint width, height;
356 double scale;
357 AdgMatrix matrix;
359 cr = gdk_cairo_create(widget->window);
360 width = widget->allocation.width;
361 height = widget->allocation.height;
362 scale = (double) (width - 80.0) / 80.0;
364 cairo_matrix_init(&matrix, scale, 0.0, 0.0, scale, scale + 71.0,
365 12.0 * scale);
366 adg_container_set_model_transformation(ADG_CONTAINER(canvas), &matrix);
368 /* Rendering process */
369 adg_entity_render(ADG_ENTITY(canvas), cr);
371 cairo_destroy(cr);
375 #ifdef CAIRO_HAS_PNG_FUNCTIONS
377 static void
378 to_png(AdgCanvas *canvas, GtkWidget *caller)
380 cairo_surface_t *surface;
381 cairo_t *cr;
383 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 800, 600);
384 cr = cairo_create(surface);
385 cairo_surface_destroy(surface);
387 /* Rendering process */
388 adg_entity_render(ADG_ENTITY(canvas), cr);
390 cairo_show_page(cr);
391 cairo_surface_write_to_png(surface, "test.png");
392 cairo_destroy(cr);
394 file_generated(caller, "test.png");
397 #else
399 static void
400 to_png(AdgCanvas *canvas, GtkWidget *caller)
402 missing_feature(caller, "PNG");
405 #endif
408 #ifdef CAIRO_HAS_PDF_SURFACE
410 #include <cairo-pdf.h>
412 static void
413 to_pdf(AdgCanvas *canvas, GtkWidget *caller)
415 cairo_surface_t *surface;
416 cairo_t *cr;
418 surface = cairo_pdf_surface_create("test.pdf", 841, 595);
419 cr = cairo_create(surface);
420 cairo_surface_destroy(surface);
422 adg_entity_render(ADG_ENTITY(canvas), cr);
424 cairo_show_page(cr);
425 cairo_destroy(cr);
427 file_generated(caller, "test.pdf");
430 #else
432 static void
433 to_pdf(AdgCanvas *canvas, GtkWidget *caller)
435 missing_feature(caller, "PDF");
438 #endif
441 #ifdef CAIRO_HAS_PS_SURFACE
443 #include <cairo-ps.h>
445 static void
446 to_ps(AdgCanvas *canvas, GtkWidget *caller)
448 cairo_surface_t *surface;
449 cairo_t *cr;
451 /* Surface creation: A4 size */
452 surface = cairo_ps_surface_create("test.ps", 841, 595);
453 cairo_ps_surface_dsc_comment(surface,
454 "%%Title: Automatic Drawing Generation (Adg) demo");
455 cairo_ps_surface_dsc_comment(surface,
456 "%%Copyright: Copyright (C) 2006 Fontana Nicola");
457 cairo_ps_surface_dsc_comment(surface, "%%Orientation: Portrait");
459 cairo_ps_surface_dsc_begin_setup(surface);
461 cairo_ps_surface_dsc_begin_page_setup(surface);
462 cairo_ps_surface_dsc_comment(surface,
463 "%%IncludeFeature: *PageSize A4");
465 cr = cairo_create(surface);
466 cairo_surface_destroy(surface);
468 adg_entity_render(ADG_ENTITY(canvas), cr);
470 cairo_show_page(cr);
471 cairo_destroy(cr);
473 file_generated(caller, "test.ps");
476 #else
478 static void
479 to_ps(AdgCanvas *canvas, GtkWidget *caller)
481 missing_feature(caller, "PostScript");
484 #endif
487 static void
488 missing_feature(GtkWidget *caller, const gchar *feature)
490 GtkWindow *window;
491 GtkWidget *dialog;
493 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
494 dialog = gtk_message_dialog_new(window, GTK_DIALOG_MODAL,
495 GTK_MESSAGE_WARNING,
496 GTK_BUTTONS_OK,
497 "The provided cairo library\n"
498 "was compiled with no %s support!",
499 feature);
500 gtk_window_set_title(GTK_WINDOW(dialog), "Missing feature");
501 gtk_dialog_run(GTK_DIALOG(dialog));
502 gtk_widget_destroy(dialog);
505 static void
506 file_generated(GtkWidget *caller, const gchar *file)
508 GtkWindow *window;
509 GtkWidget *dialog;
511 window = (GtkWindow *) gtk_widget_get_toplevel(caller);
512 dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_MODAL,
513 GTK_MESSAGE_INFO,
514 GTK_BUTTONS_CLOSE,
515 "The requested operation generated\n"
516 "<b>%s</b> in the current directory.",
517 file);
518 gtk_window_set_title(GTK_WINDOW(dialog), "Operation completed");
519 gtk_dialog_run(GTK_DIALOG(dialog));
520 gtk_widget_destroy(dialog);