9 duplicate_and_stroke (cairo_t
*cr
);
10 static void stroke_and_destroy (cairo_t
*cr
,
13 static void browsing (GtkWidget
*widget
,
14 GdkEventExpose
*event
,
16 static void browsing_segment (GtkToggleButton
*togglebutton
,
18 static void browsing_primitive (GtkToggleButton
*togglebutton
,
20 static void browsing_reset (GtkButton
*button
,
22 static void browsing_next (GtkButton
*button
,
25 static void intersections (GtkWidget
*widget
,
26 GdkEventExpose
*event
,
29 static void offset_curves (GtkWidget
*widget
,
30 GdkEventExpose
*event
,
33 static void offset_segments (GtkWidget
*widget
,
34 GdkEventExpose
*event
,
37 static void circle_callback (cairo_t
*cr
);
38 static void piston_callback (cairo_t
*cr
);
39 static void curve1_callback (cairo_t
*cr
);
40 static void line1_callback (cairo_t
*cr
);
44 cairo_path_t
*cairo_path
;
47 CpmlPrimitive primitive
;
52 static CpmlPair bezier_samples
[][4] = {
53 { { 0, 0 }, { 0, 40 }, { 120, 40 }, { 120, 0 } }, /* Simmetric low */
54 { { 40, 0 }, { 40, 160 }, { 80, 160 }, { 80, 0 } }, /* Simmetric high */
55 { { 0, 0 }, { 33.1371, 33.1371 }, { 86.8629, 33.1371 }, { 120, 0 } },
56 /* Arc approximation */
57 { { 0, 0 }, { 70, 120 }, { 50, 120 }, { 120, 0 } }, /* Twisted controls */
59 { { 0, 0 }, { 0, 120 }, { 60, 120 }, { 120, 0 } }, /* Vertical p1-p2 */
60 { { 0, 0 }, { 60, 120 }, { 120, 120 }, { 120, 0 } },/* Vertical p3-p4 */
61 { { 0, 120 }, { 120, 120 }, { 120, 60 }, { 0, 0 } },/* Horizontal p1-p2 */
62 { { 0, 120 }, { 120, 60 }, { 120, 0 }, { 0, 0 } }, /* Horizontal p3-p4 */
64 { { 0, 0 }, { 0, 120 }, { 120, 120 }, { 120, 0 } }, /* Down */
65 { { 0, 120 }, { 120, 120 }, { 120, 0 }, { 0, 0 } }, /* Right */
66 { { 0, 120 }, { 0, 0 }, { 120, 0 }, { 120, 120 } }, /* Up */
67 { { 120, 120 }, { 0, 120 }, { 0, 0 }, { 120, 0 } }, /* Left */
69 { { 0, 60 }, { 60, 120 }, { 120, 60 }, { 60, 0 } }, /* Down-right */
70 { { 60, 120 }, { 120, 60 }, { 60, 0 }, { 0, 60 } }, /* Up-right */
71 { { 120, 60 }, { 60, 0 }, { 0, 60 }, { 60, 120 } }, /* Up-left */
72 { { 60, 0 }, { 0, 60 }, { 60, 120 }, { 120, 60 } }, /* Down-left*/
74 { { 0, 0 }, { 60, 0 }, { 60, 120 }, { 120, 120 } }, /* Step left */
75 { { 120, 0 }, { 60, 0 }, { 60, 120 }, { 0, 120 } }, /* Step right */
76 { { 0, 0 }, { 60, 90 }, { 90, 120 }, { 120, 90 } }, /* Unbalanced opened */
77 { { 0, 0 }, { 40, 120 }, { 120, 120 }, { 60, 80 } } /* Unbalanced closed */
80 static void (*path_samples
[]) (cairo_t
*cr
) = {
89 main(gint argc
, gchar
**argv
)
96 gtk_init(&argc
, &argv
);
98 path
= demo_find_data_file("cpml-demo.ui");
100 g_print("cpml-demo.ui not found!\n");
104 builder
= gtk_builder_new();
107 gtk_builder_add_from_file(builder
, path
, &error
);
109 g_print("%s\n", error
->message
);
113 window
= (GtkWidget
*) gtk_builder_get_object(builder
, "wndMain");
115 /* Connect signals */
116 g_signal_connect(window
, "delete-event", G_CALLBACK(gtk_main_quit
), NULL
);
117 g_signal_connect(gtk_builder_get_object(builder
, "areaBrowsing"),
118 "expose-event", G_CALLBACK(browsing
), NULL
);
119 g_signal_connect(gtk_builder_get_object(builder
, "optBrowsingSegment"),
120 "toggled", G_CALLBACK(browsing_segment
), NULL
);
121 g_signal_connect(gtk_builder_get_object(builder
, "optBrowsingPrimitive"),
122 "toggled", G_CALLBACK(browsing_primitive
), NULL
);
123 g_signal_connect(gtk_builder_get_object(builder
, "btnBrowsingReset"),
124 "clicked", G_CALLBACK(browsing_reset
), NULL
);
125 g_signal_connect(gtk_builder_get_object(builder
, "btnBrowsingNext"),
126 "clicked", G_CALLBACK(browsing_next
), NULL
);
127 g_signal_connect(gtk_builder_get_object(builder
, "areaIntersections"),
128 "expose-event", G_CALLBACK(intersections
), NULL
);
129 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetCurves"),
130 "expose-event", G_CALLBACK(offset_curves
), NULL
);
131 g_signal_connect(gtk_builder_get_object(builder
, "areaOffsetSegments"),
132 "expose-event", G_CALLBACK(offset_segments
), NULL
);
133 g_signal_connect(gtk_builder_get_object(builder
, "btnQuit"),
134 "clicked", G_CALLBACK(gtk_main_quit
), NULL
);
136 g_object_unref(builder
);
138 gtk_widget_show_all(window
);
145 static cairo_path_t
*
146 duplicate_and_stroke(cairo_t
*cr
)
148 cairo_path_t
*path
= cairo_copy_path(cr
);
150 cairo_set_line_width(cr
, 2.);
157 stroke_and_destroy(cairo_t
*cr
, cairo_path_t
*path
)
159 cairo_append_path(cr
, path
);
160 cairo_path_destroy(path
);
162 cairo_set_line_width(cr
, 1.);
168 browsing(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
173 cr
= gdk_cairo_create(widget
->window
);
175 if (browsing_data
.area
== NULL
) {
176 /* Initialize browsing_data */
177 browsing_data
.area
= widget
;
178 browsing_data
.use_segment
= TRUE
;
180 /* Append all the path samples to the cairo context */
182 cairo_translate(cr
, 270.5, -120.5);
183 for (n
= 0; n
< G_N_ELEMENTS(path_samples
); ++n
) {
185 cairo_translate(cr
, -270., 240.);
187 cairo_translate(cr
, 270., 0.);
190 (path_samples
[n
]) (cr
);
194 browsing_data
.cairo_path
= cairo_copy_path(cr
);
195 cpml_segment_from_cairo(&browsing_data
.segment
,
196 browsing_data
.cairo_path
);
197 cpml_primitive_from_segment(&browsing_data
.primitive
,
198 &browsing_data
.segment
);
200 cairo_append_path(cr
, browsing_data
.cairo_path
);
203 cairo_set_line_width(cr
, 2.);
206 cairo_set_source_rgb(cr
, 1., 0.4, 0.);
207 cairo_set_line_width(cr
, 5.);
209 if (browsing_data
.use_segment
)
210 cpml_segment_to_cairo(&browsing_data
.segment
, cr
);
212 cpml_primitive_to_cairo(&browsing_data
.primitive
, cr
);
219 browsing_segment(GtkToggleButton
*togglebutton
, gpointer user_data
)
221 if (!gtk_toggle_button_get_active(togglebutton
))
224 browsing_data
.use_segment
= TRUE
;
225 gtk_widget_queue_draw(browsing_data
.area
);
229 browsing_primitive(GtkToggleButton
*togglebutton
, gpointer user_data
)
231 if (!gtk_toggle_button_get_active(togglebutton
))
234 browsing_data
.use_segment
= FALSE
;
235 gtk_widget_queue_draw(browsing_data
.area
);
239 browsing_reset(GtkButton
*button
, gpointer user_data
)
241 if (browsing_data
.use_segment
) {
242 cpml_segment_reset(&browsing_data
.segment
);
243 cpml_primitive_from_segment(&browsing_data
.primitive
,
244 &browsing_data
.segment
);
246 cpml_primitive_reset(&browsing_data
.primitive
);
249 gtk_widget_queue_draw(browsing_data
.area
);
253 browsing_next(GtkButton
*button
, gpointer user_data
)
255 if (browsing_data
.use_segment
) {
256 cpml_segment_next(&browsing_data
.segment
);
257 cpml_primitive_from_segment(&browsing_data
.primitive
,
258 &browsing_data
.segment
);
260 cpml_primitive_next(&browsing_data
.primitive
);
263 gtk_widget_queue_draw(browsing_data
.area
);
268 intersections(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
272 CpmlSegment segment1
, segment2
;
273 CpmlPair intersection
;
275 cr
= gdk_cairo_create(widget
->window
);
276 cairo_translate(cr
, 10.5, 120.5);
280 path
= cairo_copy_path(cr
);
282 cairo_set_line_width(cr
, 1.);
285 cpml_segment_from_cairo(&segment1
, path
);
286 cpml_segment_from_cairo(&segment2
, path
);
288 while (cpml_segment_next(&segment2
)) {
289 cpml_segment_intersection(&segment1
, &segment2
, &intersection
, 1);
291 cairo_arc(cr
, intersection
.x
, intersection
.y
, 2.5, 0, 2 * M_PI
);
294 cpml_segment_next(&segment1
);
297 cairo_path_destroy(path
);
303 offset_curves(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
308 cairo_path_t
*path
, *path_copy
;
310 CpmlPrimitive primitive
;
315 cr
= gdk_cairo_create(widget
->window
);
317 /* Add the Bézier curve samples */
318 for (n
= 0; n
< G_N_ELEMENTS(bezier_samples
); ++n
) {
319 bezier
= &bezier_samples
[n
][0];
321 /* The samples are arranged in a 4x? matrix of 200x150 cells */
323 cairo_translate(cr
, 25., 25.);
325 cairo_translate(cr
, -600., 150.);
327 cairo_translate(cr
, 200., 0.);
329 /* Draw the Bézier curve */
330 cairo_move_to(cr
, bezier
[0].x
, bezier
[0].y
);
331 cairo_curve_to(cr
, bezier
[1].x
, bezier
[1].y
,
332 bezier
[2].x
, bezier
[2].y
, bezier
[3].x
, bezier
[3].y
);
334 /* Create a copy, to be used after */
335 path_copy
= cairo_copy_path(cr
);
337 path
= duplicate_and_stroke(cr
);
338 cpml_segment_from_cairo(&segment
, path
);
339 cpml_segment_offset(&segment
, 20.);
340 stroke_and_destroy(cr
, path
);
342 cpml_segment_from_cairo(&segment
, path_copy
);
343 cpml_primitive_from_segment(&primitive
, &segment
);
345 /* Checking cpml_curve_pair_at_time and cpml_curve_vector_at_time */
346 cairo_set_line_width(cr
, 1.);
347 for (t
= 0; t
< 1; t
+= 0.1) {
348 cpml_curve_pair_at_time(&primitive
, &pair
, t
);
349 cpml_curve_vector_at_time(&primitive
, &vector
, t
);
350 cpml_vector_set_length(&vector
, 20.);
351 cpml_vector_normal(&vector
);
353 cairo_new_sub_path(cr
);
354 cairo_arc(cr
, pair
.x
, pair
.y
, 2.5, 0, M_PI
*2);
357 cairo_move_to(cr
, pair
.x
, pair
.y
);
358 cairo_line_to(cr
, pair
.x
+ vector
.x
, pair
.y
+ vector
.y
);
362 cairo_path_destroy(path_copy
);
370 offset_segments(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
377 cr
= gdk_cairo_create(widget
->window
);
378 cairo_translate(cr
, 270.5, -120.5);
380 /* Offset the path samples */
381 for (n
= 0; n
< G_N_ELEMENTS(path_samples
); ++n
) {
383 cairo_translate(cr
, -270., 240.);
385 cairo_translate(cr
, 270., 0.);
388 /* Call the path callback */
389 (path_samples
[n
]) (cr
);
391 path
= duplicate_and_stroke(cr
);
392 cpml_segment_from_cairo(&segment
, path
);
393 cpml_segment_offset(&segment
, 15.);
394 stroke_and_destroy(cr
, path
);
402 circle_callback(cairo_t
*cr
)
404 cairo_new_sub_path(cr
);
405 cairo_arc(cr
, 120., 0., 100., 0., M_PI
*2);
409 piston_callback(cairo_t
*cr
)
411 cairo_path_t
*old_path
, *path
;
412 cairo_matrix_t matrix
;
415 /* Save the previous path, if any */
416 old_path
= cairo_copy_path(cr
);
419 cairo_move_to(cr
, 0., 46.5);
420 cairo_line_to(cr
, 210., 46.5);
421 cairo_line_to(cr
, 222.5, 35.);
422 cairo_line_to(cr
, 270., 35.);
423 cairo_line_to(cr
, 270., 56.);
424 cairo_line_to(cr
, 273., 59.);
425 cairo_line_to(cr
, 302., 59.);
426 cairo_line_to(cr
, 305., 56.);
427 cairo_arc(cr
, 325., 52.5, 20., G_PI
, 3. * G_PI_2
);
428 cairo_line_to(cr
, 400., 32.5);
429 cairo_line_to(cr
, 410., 22.5);
430 cairo_line_to(cr
, 450., 22.5);
431 cairo_arc_negative(cr
,
432 452., 34., 2., G_PI
, G_PI_2
);
433 cairo_line_to(cr
, 460., 36.);
434 cairo_line_to(cr
, 470., 30.);
435 cairo_line_to(cr
, 472., 12.5);
437 /* Mirror a reversed copy of the current path on the y = 0 axis */
438 path
= cairo_copy_path(cr
);
439 cpml_segment_from_cairo(&segment
, path
);
441 cpml_segment_reverse(&segment
);
442 cairo_matrix_init_scale(&matrix
, 1., -1.);
443 cpml_segment_transform(&segment
, &matrix
);
445 /* Join the mirrored path to the old path... */
446 path
->data
[0].header
.type
= CAIRO_PATH_LINE_TO
;
447 cairo_append_path(cr
, path
);
448 cairo_path_destroy(path
);
450 /* ...and close the shape */
451 cairo_close_path(cr
);
453 /* Save the resulting path and clear the path memory */
454 path
= cairo_copy_path(cr
);
457 /* Restore the previous path and reappend the new path */
458 cairo_append_path(cr
, old_path
);
459 cairo_path_destroy(old_path
);
460 cairo_append_path(cr
, path
);
461 cairo_path_destroy(path
);
465 curve1_callback(cairo_t
*cr
)
467 cairo_move_to(cr
, 30., 0.);
468 cairo_curve_to(cr
, 120., 120., 180., 100., 180., 20.);
469 cairo_curve_to(cr
, 180., -20., 50., 40., 150., 40.);
470 cairo_curve_to(cr
, 220., 40., 190., -60., 150., -60.);
471 cairo_curve_to(cr
, 100., -60., 80., -40., 60., -60.);
475 line1_callback(cairo_t
*cr
)
477 cairo_move_to(cr
, 0, -50);
478 cairo_line_to(cr
, 100, 50);
480 cairo_move_to(cr
, 100, -50);
481 cairo_line_to(cr
, 0, 50);
483 cairo_move_to(cr
, 120, -50);
484 cairo_line_to(cr
, 200, -10);
486 cairo_move_to(cr
, 120, 50);
487 cairo_line_to(cr
, 200, 10);
489 cairo_move_to(cr
, 220, 0);
490 cairo_line_to(cr
, 280, 0);
492 cairo_move_to(cr
, 270, -40);
493 cairo_line_to(cr
, 270, 20);
495 cairo_move_to(cr
, 320, 60);
496 cairo_line_to(cr
, 380, 60);
498 cairo_move_to(cr
, 300, -40);
499 cairo_line_to(cr
, 340, 0);
501 cairo_move_to(cr
, 480, 10);
502 cairo_line_to(cr
, 400, 40);
504 cairo_move_to(cr
, 400, 40);
505 cairo_line_to(cr
, 450, -40);