14
#include "point-ops.h"
15
#include "point-fns.h"
18
#include "path-to-polyline.h"
19
#include "read-svgd.h"
20
#include "path-find-points-of-interest.h"
22
#include "rotate-ops.h"
23
#include "arc-length.h"
24
#include "path-intersect.h"
29
static GtkWidget *canvas;
30
static GdkGC *dash_gc;
31
static GdkGC *plain_gc;
32
Geom::Path display_path;
34
static Geom::Point old_handle_pos;
35
static Geom::Point old_mouse_point;
37
void draw_line_seg(cairo_t *cr, Geom::Point a, Geom::Point b) {
38
cairo_move_to(cr, a[0], a[1]);
39
cairo_line_to(cr, b[0], b[1]);
43
void draw_spot(cairo_t *cr, Geom::Point h) {
44
draw_line_seg(cr, h, h);
47
void draw_handle(cairo_t *cr, Geom::Point h, string name = string("")) {
48
double x = h[Geom::X];
49
double y = h[Geom::Y];
50
cairo_move_to(cr, x-3, y);
51
cairo_line_to(cr, x+3, y);
52
cairo_move_to(cr, x, y-3);
53
cairo_line_to(cr, x, y+3);
54
//templayout.set_text(name);
55
//w.draw_layout(g, x, y, templayout);
58
void draw_circ(cairo_t *cr, Geom::Point h) {
59
int x = int(h[Geom::X]);
60
int y = int(h[Geom::Y]);
61
cairo_new_sub_path(cr);
62
cairo_arc(cr, x, y, 3, 0, M_PI*2);
66
void draw_ray(cairo_t *cr, Geom::Point h, Geom::Point dir) {
67
draw_line_seg(cr, h, h+dir);
72
segment_intersect(Geom::Point const &p00, Geom::Point const &p01,
73
Geom::Point const &p10, Geom::Point const &p11,
77
void draw_elip(cairo_t *cr, Geom::Point *h) {
78
draw_line_seg(cr, h[0], h[1]);
79
draw_line_seg(cr, h[3], h[4]);
80
draw_line_seg(cr, h[3], h[2]);
81
draw_line_seg(cr, h[2], h[1]);
84
line_twopoint_intersect(h[0], h[1], h[3], h[4], c);
88
for(int i = 0; i <= 100; i++) {
91
Geom::Point n = (1-t)*h[0] + t*h[3];
93
line_twopoint_intersect(2*c-n, n, h[0], h[2], c1);
94
line_twopoint_intersect(2*c-n, n, h[4], h[2], c2);
96
line_twopoint_intersect(c1, h[3], c2, h[1], six);
98
draw_line_seg(cr, old, six);
103
void draw_path(cairo_t *cr, Geom::Path p) {
104
path_to_polyline pl(p, 1);
106
Geom::Point old(pl.handles[0]);
108
for(unsigned i = 1; i < pl.handles.size(); i++) {
109
Geom::Point p(pl.handles[i]);
110
draw_line_seg(cr, old, p);
116
Geom::Point* selected_handle = 0;
120
expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
122
cairo_t *cr = gdk_cairo_create (widget->window);
123
cairo_set_line_width (cr, 1);
128
std::ostringstream notify;
129
gdk_drawable_get_size(widget->window, &width, &height);
131
for(int i = 0; i < display_path.handles.size(); i++) {
132
draw_handle(cr, display_path.handles[i]);
134
draw_path(cr, display_path);
135
//draw_elip(cr, handles);
137
Geom::Point dir(1,1);
139
vector<Geom::Path::PathLocation> pts = find_vector_extreme_points(display_path, dir);
141
for(int i = 0; i < pts.size(); i++) {
142
draw_circ(cr, display_path.point_at(pts[i]));
145
double dist = INFINITY;
148
cairo_set_source_rgba (cr, 0., 0., 0.5, 0.8);
150
Geom::Path::PathLocation pl =
151
display_path.nearest_location(old_mouse_point, dist);
153
Geom::Point pos, tgt, acc;
154
display_path.point_tangent_acc_at (pl, pos, tgt, acc);
156
double kurvature = dot(acc, rot90(tgt))/pow(Geom::L2(tgt),3);
158
if(fabs(kurvature) > 0.001)
160
(1./kurvature)*Geom::unit_vector(rot90(tgt)));
162
draw_ray(cr, pos, rot90(tgt));
168
cairo_set_source_rgba (cr, 0.25, 0.25, 0., 0.8);
170
Geom::Path pth = display_path.subpath(display_path.indexed_elem(2), display_path.end());
171
pth = pth*Geom::translate(Geom::Point(30, 30));
174
const int curve_seg = 3;
175
Geom::Path::PathElem ai(*display_path.indexed_elem(curve_seg)), bi(*pth.indexed_elem(curve_seg));
177
for(int i = 0; i < 4; i++) {
183
std::vector<std::pair <double, double> > ts = Geom::FindIntersections(a, b);
185
cairo_set_source_rgba (cr, 0, 0.5, 0., 0.8);
186
for(int i = 0; i < ts.size(); i++) {
187
Geom::Path::PathLocation pl(display_path.indexed_elem(curve_seg), ts[i].first);
189
draw_handle(cr, display_path.point_at(pl));
190
Geom::Path::PathLocation p2(pth.indexed_elem(curve_seg), ts[i].second);
192
draw_circ(cr, display_path.point_at(p2));
197
vector<Geom::Path::PathLocation> pts =
198
find_inflection_points(display_path);
200
for(int i = 0; i < pts.size(); i++) {
201
Geom::Point pos, tgt, acc;
202
display_path.point_tangent_acc_at (pts[i], pos, tgt, acc);
205
draw_handle(cr, display_path.point_at(pts[i]));
208
//draw_ray(cr, pos+tgt, acc);
211
notify << "path length: " << arc_length_integrating(display_path, 1e3) << "\n";
216
PangoLayout *layout = gtk_widget_create_pango_layout(widget, notify.str().c_str());
217
PangoRectangle logical_extent;
218
pango_layout_get_pixel_extents(layout,
221
cairo_move_to(cr, 0, height-logical_extent.height);
222
cairo_show_text (cr, notify.str().c_str());
223
//cairo_text_path(cr, notify.str().c_str());
225
/*pango_cairo_draw_layout(cr,
226
0, height-logical_extent.height, layout);*/
229
x = widget->allocation.x + widget->allocation.width / 2;
230
y = widget->allocation.y + widget->allocation.height / 2;
233
radius = std::min (widget->allocation.width / 2,
234
widget->allocation.height / 2) - 5;
241
static void handle_mouse(GtkWidget* widget) {
242
gtk_widget_queue_draw (widget);
245
static gint mouse_motion_event(GtkWidget* widget, GdkEventMotion* e, gpointer data) {
246
Geom::Point mouse(e->x, e->y);
248
if(e->state & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)) {
249
if(selected_handle) {
250
*selected_handle = mouse - old_handle_pos;
253
handle_mouse(widget);
256
if(e->state & (GDK_BUTTON2_MASK)) {
257
gtk_widget_queue_draw(widget);
260
old_mouse_point = mouse;
265
static gint mouse_event(GtkWidget* window, GdkEventButton* e, gpointer data) {
266
Geom::Point mouse(e->x, e->y);
267
if(e->button == 1 || e->button == 3) {
268
for(int i = 0; i < display_path.handles.size(); i++) {
269
if(Geom::L2(mouse - display_path.handles[i]) < 5) {
270
selected_handle = &display_path.handles[i];
271
old_handle_pos = mouse - display_path.handles[i];
274
handle_mouse(window);
275
} else if(e->button == 2) {
276
gtk_widget_queue_draw(window);
278
old_mouse_point = mouse;
283
static gint mouse_release_event(GtkWidget* window, GdkEventButton* e, gpointer data) {
288
static gint key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer) {
290
if (event->keyval == ' ') {
292
} else if (event->keyval == 'l') {
294
} else if (event->keyval == 'd') {
295
write_svgd(stderr, display_path);
297
} else if ('0' <= event->keyval
298
&& event->keyval <= '9') {
300
} else if ('h' == event->keyval) {
305
gtk_widget_queue_draw(widget);
312
delete_event_cb(GtkWidget* window, GdkEventAny* e, gpointer data)
318
#include "translate-ops.h"
319
#include "scale-ops.h"
320
#include "translate-scale-ops.h"
323
int main(int argc, char **argv) {
324
char const *const filename = (argc >= 2
327
FILE* f = fopen(filename, "r");
332
display_path = read_svgd(f);
334
Geom::Rect r = display_path.bbox();
336
display_path = display_path*Geom::translate(-r.min());
337
Geom::scale sc(r.max() - r.min());
338
display_path = display_path*(sc.inverse()*Geom::scale(500,500));
340
gtk_init (&argc, &argv);
344
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
346
gtk_window_set_title(GTK_WINDOW(window), "text toy");
348
gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
350
gtk_signal_connect(GTK_OBJECT(window),
352
GTK_SIGNAL_FUNC(delete_event_cb),
355
gtk_widget_push_visual(gdk_rgb_get_visual());
356
gtk_widget_push_colormap(gdk_rgb_get_cmap());
357
canvas = gtk_drawing_area_new();
359
gtk_signal_connect(GTK_OBJECT (canvas),
361
GTK_SIGNAL_FUNC(expose_event),
363
gtk_widget_add_events(canvas, (GDK_BUTTON_PRESS_MASK |
364
GDK_BUTTON_RELEASE_MASK |
366
GDK_POINTER_MOTION_MASK));
367
gtk_signal_connect(GTK_OBJECT (canvas),
368
"button_press_event",
369
GTK_SIGNAL_FUNC(mouse_event),
371
gtk_signal_connect(GTK_OBJECT (canvas),
372
"button_release_event",
373
GTK_SIGNAL_FUNC(mouse_release_event),
375
gtk_signal_connect(GTK_OBJECT (canvas),
376
"motion_notify_event",
377
GTK_SIGNAL_FUNC(mouse_motion_event),
379
gtk_signal_connect(GTK_OBJECT(canvas),
381
GTK_SIGNAL_FUNC(key_release_event),
384
gtk_widget_pop_colormap();
385
gtk_widget_pop_visual();
387
GtkWidget *vb = gtk_vbox_new(0, 0);
390
gtk_container_add(GTK_CONTAINER(window), vb);
392
gtk_box_pack_start(GTK_BOX(vb), canvas, TRUE, TRUE, 0);
394
gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
396
gtk_widget_show_all(window);
398
dash_gc = gdk_gc_new(canvas->window);
399
gint8 dash_list[] = {4, 4};
400
gdk_gc_set_dashes(dash_gc, 0, dash_list, 2);
403
colour.green = 0xffff;
404
colour.blue = 0xffff;
406
plain_gc = gdk_gc_new(canvas->window);
408
//gdk_gc_set_rgb_fg_color(dash_gc, &colour);
409
gdk_rgb_find_color(gtk_widget_get_colormap(canvas), &colour);
410
gdk_window_set_background(canvas->window, &colour);
411
gdk_gc_set_line_attributes(dash_gc, 1, GDK_LINE_ON_OFF_DASH,
412
GDK_CAP_BUTT,GDK_JOIN_MITER);
414
/* Make sure the canvas can receive key press events. */
415
GTK_WIDGET_SET_FLAGS(canvas, GTK_CAN_FOCUS);
416
assert(GTK_WIDGET_CAN_FOCUS(canvas));
417
gtk_widget_grab_focus(canvas);
418
assert(gtk_widget_is_focus(canvas));
428
c-file-style:"stroustrup"
429
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
434
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :