[AdgTable] Prefixed internal symbols
[adg.git] / demo / cpml-demo.c
blob60830c58c3d7b79c1cf8ebff63adf884ae44883b
1 #include "demo.h"
3 #include <cpml.h>
4 #include <math.h>
7 static void parse_args (gint *p_argc,
8 gchar **p_argv[]);
9 static cairo_path_t *
10 duplicate_and_stroke (cairo_t *cr);
11 static void stroke_and_destroy (cairo_t *cr,
12 cairo_path_t *path);
14 static void browsing (GtkWidget *widget,
15 GdkEventExpose *event,
16 gpointer user_data);
17 static void browsing_segment (GtkToggleButton*togglebutton,
18 gpointer user_data);
19 static void browsing_primitive (GtkToggleButton*togglebutton,
20 gpointer user_data);
21 static void browsing_reset (GtkButton *button,
22 gpointer user_data);
23 static void browsing_next (GtkButton *button,
24 gpointer user_data);
26 static void arcs (GtkWidget *widget,
27 GdkEventExpose *event,
28 gpointer user_data);
29 static void arc3p (cairo_t *cr,
30 double x1,
31 double y1,
32 double x2,
33 double y2,
34 double x3,
35 double y3);
37 static void intersections (GtkWidget *widget,
38 GdkEventExpose *event,
39 gpointer user_data);
41 static void offset_curves (GtkWidget *widget,
42 GdkEventExpose *event,
43 gpointer user_data);
45 static void offset_segments (GtkWidget *widget,
46 GdkEventExpose *event,
47 gpointer user_data);
49 static void circle_callback (cairo_t *cr);
50 static void piston_callback (cairo_t *cr);
51 static void curve1_callback (cairo_t *cr);
52 static void line1_callback (cairo_t *cr);
54 static struct {
55 GtkWidget *area;
56 cairo_path_t *cairo_path;
57 gboolean use_segment;
58 CpmlSegment segment;
59 CpmlPrimitive primitive;
60 } browsing_data = {
61 NULL,
64 static CpmlPair bezier_samples[][4] = {
65 { { 0, 0 }, { 0, 40 }, { 120, 40 }, { 120, 0 } }, /* Simmetric low */
66 { { 40, 0 }, { 40, 160 }, { 80, 160 }, { 80, 0 } }, /* Simmetric high */
67 { { 0, 0 }, { 33.1371, 33.1371 }, { 86.8629, 33.1371 }, { 120, 0 } },
68 /* Arc approximation */
69 { { 0, 0 }, { 70, 120 }, { 50, 120 }, { 120, 0 } }, /* Twisted controls */
71 { { 0, 0 }, { 0, 120 }, { 60, 120 }, { 120, 0 } }, /* Vertical p1-p2 */
72 { { 0, 0 }, { 60, 120 }, { 120, 120 }, { 120, 0 } },/* Vertical p3-p4 */
73 { { 0, 120 }, { 120, 120 }, { 120, 60 }, { 0, 0 } },/* Horizontal p1-p2 */
74 { { 0, 120 }, { 120, 60 }, { 120, 0 }, { 0, 0 } }, /* Horizontal p3-p4 */
76 { { 0, 0 }, { 0, 120 }, { 120, 120 }, { 120, 0 } }, /* Down */
77 { { 0, 120 }, { 120, 120 }, { 120, 0 }, { 0, 0 } }, /* Right */
78 { { 0, 120 }, { 0, 0 }, { 120, 0 }, { 120, 120 } }, /* Up */
79 { { 120, 120 }, { 0, 120 }, { 0, 0 }, { 120, 0 } }, /* Left */
81 { { 0, 60 }, { 60, 120 }, { 120, 60 }, { 60, 0 } }, /* Down-right */
82 { { 60, 120 }, { 120, 60 }, { 60, 0 }, { 0, 60 } }, /* Up-right */
83 { { 120, 60 }, { 60, 0 }, { 0, 60 }, { 60, 120 } }, /* Up-left */
84 { { 60, 0 }, { 0, 60 }, { 60, 120 }, { 120, 60 } }, /* Down-left*/
86 { { 0, 0 }, { 60, 0 }, { 60, 120 }, { 120, 120 } }, /* Step left */
87 { { 120, 0 }, { 60, 0 }, { 60, 120 }, { 0, 120 } }, /* Step right */
88 { { 0, 0 }, { 60, 90 }, { 90, 120 }, { 120, 90 } }, /* Unbalanced opened */
89 { { 0, 0 }, { 40, 120 }, { 120, 120 }, { 60, 80 } } /* Unbalanced closed */
92 static void (*path_samples[]) (cairo_t *cr) = {
93 circle_callback,
94 piston_callback,
95 curve1_callback,
96 line1_callback,
101 main(gint argc, gchar **argv)
103 gchar *path;
104 GtkBuilder *builder;
105 GError *error;
106 GtkWidget *window;
108 parse_args(&argc, &argv);
110 path = demo_find_data_file("cpml-demo.ui", argv[0]);
111 if (path == NULL) {
112 g_print("cpml-demo.ui not found!\n");
113 return 1;
116 builder = gtk_builder_new();
117 error = NULL;
119 gtk_builder_add_from_file(builder, path, &error);
120 if (error != NULL) {
121 g_print("%s\n", error->message);
122 return 2;
125 window = (GtkWidget *) gtk_builder_get_object(builder, "wndMain");
127 /* Connect signals */
128 g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
129 g_signal_connect(gtk_builder_get_object(builder, "areaBrowsing"),
130 "expose-event", G_CALLBACK(browsing), NULL);
131 g_signal_connect(gtk_builder_get_object(builder, "optBrowsingSegment"),
132 "toggled", G_CALLBACK(browsing_segment), NULL);
133 g_signal_connect(gtk_builder_get_object(builder, "optBrowsingPrimitive"),
134 "toggled", G_CALLBACK(browsing_primitive), NULL);
135 g_signal_connect(gtk_builder_get_object(builder, "btnBrowsingReset"),
136 "clicked", G_CALLBACK(browsing_reset), NULL);
137 g_signal_connect(gtk_builder_get_object(builder, "btnBrowsingNext"),
138 "clicked", G_CALLBACK(browsing_next), NULL);
139 g_signal_connect(gtk_builder_get_object(builder, "areaArcs"),
140 "expose-event", G_CALLBACK(arcs), NULL);
141 g_signal_connect(gtk_builder_get_object(builder, "areaIntersections"),
142 "expose-event", G_CALLBACK(intersections), NULL);
143 g_signal_connect(gtk_builder_get_object(builder, "areaOffsetCurves"),
144 "expose-event", G_CALLBACK(offset_curves), NULL);
145 g_signal_connect(gtk_builder_get_object(builder, "areaOffsetSegments"),
146 "expose-event", G_CALLBACK(offset_segments), NULL);
147 g_signal_connect(gtk_builder_get_object(builder, "btnQuit"),
148 "clicked", G_CALLBACK(gtk_main_quit), NULL);
150 g_object_unref(builder);
152 gtk_widget_show_all(window);
153 gtk_main();
155 return 0;
159 /**********************************************
160 * Command line options parser
161 **********************************************/
163 static void
164 version(void)
166 g_print("cpml-demo " PACKAGE_VERSION "\n");
167 exit(0);
170 static void
171 parse_args(gint *p_argc, gchar **p_argv[])
173 GError *error = NULL;
174 GOptionEntry entries[] = {
175 {"version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, version,
176 "Display version information", NULL},
177 {NULL}
180 gtk_init_with_args(p_argc, p_argv, "- CPML demonstration program",
181 entries, NULL, &error);
183 if (error != NULL) {
184 gint error_code = error->code;
186 g_printerr("%s\n", error->message);
188 g_error_free(error);
189 exit(error_code);
194 static cairo_path_t *
195 duplicate_and_stroke(cairo_t *cr)
197 cairo_path_t *path = cairo_copy_path(cr);
199 cairo_set_line_width(cr, 2.);
200 cairo_stroke(cr);
202 return path;
205 static void
206 stroke_and_destroy(cairo_t *cr, cairo_path_t *path)
208 cairo_append_path(cr, path);
209 cairo_path_destroy(path);
211 cairo_set_line_width(cr, 1.);
212 cairo_stroke(cr);
216 static void
217 browsing(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
219 cairo_t *cr;
220 int n;
222 cr = gdk_cairo_create(widget->window);
224 if (browsing_data.area == NULL) {
225 /* Initialize browsing_data */
226 browsing_data.area = widget;
227 browsing_data.use_segment = TRUE;
229 /* Append all the path samples to the cairo context */
230 cairo_save(cr);
231 cairo_translate(cr, 270.5, -120.5);
232 for (n = 0; n < G_N_ELEMENTS(path_samples); ++n) {
233 if ((n & 1) == 0) {
234 cairo_translate(cr, -270., 240.);
235 } else {
236 cairo_translate(cr, 270., 0.);
239 (path_samples[n]) (cr);
242 cairo_restore(cr);
243 browsing_data.cairo_path = cairo_copy_path(cr);
244 cpml_segment_from_cairo(&browsing_data.segment,
245 browsing_data.cairo_path);
246 cpml_primitive_from_segment(&browsing_data.primitive,
247 &browsing_data.segment);
248 } else {
249 cairo_append_path(cr, browsing_data.cairo_path);
252 cairo_set_line_width(cr, 2.);
253 cairo_stroke(cr);
255 cairo_set_source_rgb(cr, 1., 0.4, 0.);
256 cairo_set_line_width(cr, 5.);
258 if (browsing_data.use_segment)
259 cpml_segment_to_cairo(&browsing_data.segment, cr);
260 else
261 cpml_primitive_to_cairo(&browsing_data.primitive, cr);
263 cairo_stroke(cr);
264 cairo_destroy(cr);
267 static void
268 browsing_segment(GtkToggleButton *togglebutton, gpointer user_data)
270 if (!gtk_toggle_button_get_active(togglebutton))
271 return;
273 browsing_data.use_segment = TRUE;
274 gtk_widget_queue_draw(browsing_data.area);
277 static void
278 browsing_primitive(GtkToggleButton*togglebutton, gpointer user_data)
280 if (!gtk_toggle_button_get_active(togglebutton))
281 return;
283 browsing_data.use_segment = FALSE;
284 gtk_widget_queue_draw(browsing_data.area);
287 static void
288 browsing_reset(GtkButton *button, gpointer user_data)
290 if (browsing_data.use_segment) {
291 cpml_segment_reset(&browsing_data.segment);
292 cpml_primitive_from_segment(&browsing_data.primitive,
293 &browsing_data.segment);
294 } else {
295 cpml_primitive_reset(&browsing_data.primitive);
298 gtk_widget_queue_draw(browsing_data.area);
301 static void
302 browsing_next(GtkButton *button, gpointer user_data)
304 if (browsing_data.use_segment) {
305 cpml_segment_next(&browsing_data.segment);
306 cpml_primitive_from_segment(&browsing_data.primitive,
307 &browsing_data.segment);
308 } else {
309 cpml_primitive_next(&browsing_data.primitive);
312 gtk_widget_queue_draw(browsing_data.area);
316 static void
317 arcs(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
319 cairo_t *cr = gdk_cairo_create(widget->window);
321 cairo_translate(cr, 100.5, 100.5);
322 arc3p(cr, 0, 0, 0, 120, 120, 120);
324 cairo_translate(cr, 200, 0.);
325 arc3p(cr, 0, 0, 120, 0, 120, 120);
327 cairo_translate(cr, 200, 0.);
328 arc3p(cr, 60, 0, 0, 120, 120, 120);
330 cairo_translate(cr, -400, 200);
331 arc3p(cr, 0, 50, -2, 85, 120, 0);
333 cairo_translate(cr, 200, 0);
334 arc3p(cr, -2, 85, 0, 50, 120, 0);
336 cairo_destroy(cr);
339 static void
340 arc3p(cairo_t *cr, double x1, double y1,
341 double x2, double y2, double x3, double y3)
343 CpmlPrimitive arc;
344 cairo_path_data_t p[4];
345 CpmlPair center;
346 double r, start, end;
348 arc.segment = NULL;
349 arc.org = &p[0];
350 arc.data = &p[1];
352 p[1].header.type = CPML_ARC;
353 p[1].header.length = 3;
355 p[0].point.x = x1;
356 p[0].point.y = y1;
357 p[2].point.x = x2;
358 p[2].point.y = y2;
359 p[3].point.x = x3;
360 p[3].point.y = y3;
362 cpml_primitive_to_cairo(&arc, cr);
364 cairo_set_line_width(cr, 1.);
365 cairo_stroke(cr);
367 /* Add an arc generated by cairo, just for reference */
368 if (!cpml_arc_info(&arc, &center, &r, &start, &end)) {
369 g_print("Unable to get arc info (%lf, %lf) (%lf, %lf) (%lf, %lf)\n",
370 x1, y1, x2, y2, x3, y3);
371 return;
374 if (start < end)
375 cairo_arc(cr, center.x, center.y, r-5., start, end);
376 else
377 cairo_arc_negative(cr, center.x, center.y, r-5., start, end);
379 /* Show the inscribed triangle */
380 cairo_move_to(cr, x1, y1);
381 cairo_line_to(cr, x2, y2);
382 cairo_line_to(cr, x3, y3);
384 cairo_set_line_width(cr, 0.5);
385 cairo_stroke(cr);
389 static void
390 intersections(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
392 cairo_t *cr;
393 cairo_path_t *path;
394 CpmlSegment segment1, segment2;
395 CpmlPair intersection;
397 cr = gdk_cairo_create(widget->window);
398 cairo_translate(cr, 10.5, 120.5);
400 line1_callback(cr);
402 path = cairo_copy_path(cr);
404 cairo_set_line_width(cr, 1.);
405 cairo_stroke(cr);
407 cpml_segment_from_cairo(&segment1, path);
408 cpml_segment_from_cairo(&segment2, path);
410 while (cpml_segment_next(&segment2)) {
411 cpml_segment_put_intersections(&segment1, &segment2, 1, &intersection);
413 cairo_arc(cr, intersection.x, intersection.y, 2.5, 0, 2 * M_PI);
414 cairo_fill(cr);
416 cpml_segment_next(&segment1);
419 cairo_path_destroy(path);
420 cairo_destroy(cr);
424 static void
425 offset_curves(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
427 cairo_t *cr;
428 gint n;
429 CpmlPair *bezier;
430 cairo_path_t *path, *path_copy;
431 CpmlSegment segment;
432 CpmlPrimitive primitive;
433 CpmlPair pair;
434 CpmlVector vector;
435 double t;
437 cr = gdk_cairo_create(widget->window);
439 /* Add the Bézier curve samples */
440 for (n = 0; n < G_N_ELEMENTS(bezier_samples); ++n) {
441 bezier = &bezier_samples[n][0];
443 /* The samples are arranged in a 4x? matrix of 200x150 cells */
444 if (n == 0)
445 cairo_translate(cr, 25., 25.);
446 else if (n % 4 == 0)
447 cairo_translate(cr, -600., 150.);
448 else
449 cairo_translate(cr, 200., 0.);
451 /* Draw the Bézier curve */
452 cairo_move_to(cr, bezier[0].x, bezier[0].y);
453 cairo_curve_to(cr, bezier[1].x, bezier[1].y,
454 bezier[2].x, bezier[2].y, bezier[3].x, bezier[3].y);
456 /* Create a copy, to be used after */
457 path_copy = cairo_copy_path(cr);
459 path = duplicate_and_stroke(cr);
460 cpml_segment_from_cairo(&segment, path);
461 cpml_segment_offset(&segment, 20.);
462 stroke_and_destroy(cr, path);
464 cpml_segment_from_cairo(&segment, path_copy);
465 cpml_primitive_from_segment(&primitive, &segment);
467 /* Checking cpml_curve_put_pair_at_time and cpml_curve_put_vector_at_time */
468 cairo_set_line_width(cr, 1.);
469 for (t = 0; t < 1; t += 0.1) {
470 cpml_curve_put_pair_at_time(&primitive, t, &pair);
471 cpml_curve_put_vector_at_time(&primitive, t, &vector);
472 cpml_vector_set_length(&vector, 20.);
473 cpml_vector_normal(&vector);
475 cairo_new_sub_path(cr);
476 cairo_arc(cr, pair.x, pair.y, 2.5, 0, M_PI*2);
477 cairo_fill(cr);
479 cairo_move_to(cr, pair.x, pair.y);
480 cairo_line_to(cr, pair.x + vector.x, pair.y + vector.y);
481 cairo_stroke(cr);
484 cairo_path_destroy(path_copy);
487 cairo_destroy(cr);
491 static void
492 offset_segments(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
494 cairo_t *cr;
495 cairo_path_t *path;
496 CpmlSegment segment;
497 int n;
499 cr = gdk_cairo_create(widget->window);
500 cairo_translate(cr, 270.5, -120.5);
502 /* Offset the path samples */
503 for (n = 0; n < G_N_ELEMENTS(path_samples); ++n) {
504 if ((n & 1) == 0) {
505 cairo_translate(cr, -270., 240.);
506 } else {
507 cairo_translate(cr, 270., 0.);
510 /* Call the path callback */
511 (path_samples[n]) (cr);
513 path = duplicate_and_stroke(cr);
514 cpml_segment_from_cairo(&segment, path);
515 cpml_segment_offset(&segment, 15.);
516 stroke_and_destroy(cr, path);
519 cairo_destroy(cr);
523 static void
524 circle_callback(cairo_t *cr)
526 cairo_new_sub_path(cr);
527 cairo_arc(cr, 120., 0., 100., 0., M_PI*2);
530 static void
531 piston_callback(cairo_t *cr)
533 cairo_path_t *old_path, *path;
534 cairo_matrix_t matrix;
535 CpmlSegment segment;
537 /* Save the previous path, if any */
538 old_path = cairo_copy_path(cr);
540 cairo_new_path(cr);
541 cairo_move_to(cr, 0., 46.5);
542 cairo_line_to(cr, 210., 46.5);
543 cairo_line_to(cr, 222.5, 35.);
544 cairo_line_to(cr, 270., 35.);
545 cairo_line_to(cr, 270., 56.);
546 cairo_line_to(cr, 273., 59.);
547 cairo_line_to(cr, 302., 59.);
548 cairo_line_to(cr, 305., 56.);
549 cairo_arc(cr, 325., 52.5, 20., G_PI, 3. * G_PI_2);
550 cairo_line_to(cr, 400., 32.5);
551 cairo_line_to(cr, 410., 22.5);
552 cairo_line_to(cr, 450., 22.5);
553 cairo_arc_negative(cr,
554 452., 34., 2., G_PI, G_PI_2);
555 cairo_line_to(cr, 460., 36.);
556 cairo_line_to(cr, 470., 30.);
557 cairo_line_to(cr, 472., 12.5);
559 /* Mirror a reversed copy of the current path on the y = 0 axis */
560 path = cairo_copy_path(cr);
561 cpml_segment_from_cairo(&segment, path);
563 cpml_segment_reverse(&segment);
564 cairo_matrix_init_scale(&matrix, 1., -1.);
565 cpml_segment_transform(&segment, &matrix);
567 /* Join the mirrored path to the old path... */
568 path->data[0].header.type = CPML_LINE;
569 cairo_append_path(cr, path);
570 cairo_path_destroy(path);
572 /* ...and close the shape */
573 cairo_close_path(cr);
575 /* Save the resulting path and clear the path memory */
576 path = cairo_copy_path(cr);
577 cairo_new_path(cr);
579 /* Restore the previous path and reappend the new path */
580 cairo_append_path(cr, old_path);
581 cairo_path_destroy(old_path);
582 cairo_append_path(cr, path);
583 cairo_path_destroy(path);
586 static void
587 curve1_callback(cairo_t *cr)
589 cairo_move_to(cr, 30., 0.);
590 cairo_curve_to(cr, 120., 120., 180., 100., 180., 20.);
591 cairo_curve_to(cr, 180., -20., 50., 40., 150., 40.);
592 cairo_curve_to(cr, 220., 40., 190., -60., 150., -60.);
593 cairo_curve_to(cr, 100., -60., 80., -40., 60., -60.);
596 static void
597 line1_callback(cairo_t *cr)
599 cairo_move_to(cr, 0, -50);
600 cairo_line_to(cr, 100, 50);
602 cairo_move_to(cr, 100, -50);
603 cairo_line_to(cr, 0, 50);
605 cairo_move_to(cr, 120, -50);
606 cairo_line_to(cr, 200, -10);
608 cairo_move_to(cr, 120, 50);
609 cairo_line_to(cr, 200, 10);
611 cairo_move_to(cr, 220, 0);
612 cairo_line_to(cr, 280, 0);
614 cairo_move_to(cr, 270, -40);
615 cairo_line_to(cr, 270, 20);
617 cairo_move_to(cr, 320, 60);
618 cairo_line_to(cr, 380, 60);
620 cairo_move_to(cr, 300, -40);
621 cairo_line_to(cr, 340, 0);
623 cairo_move_to(cr, 480, 10);
624 cairo_line_to(cr, 400, 40);
626 cairo_move_to(cr, 400, 40);
627 cairo_line_to(cr, 450, -40);