~lib2geom-hackers/lib2geom/trunk

« back to all changes in this revision

Viewing changes to toy-cairo.cpp

  • Committer: njh
  • Date: 2006-05-22 11:50:24 UTC
  • Revision ID: svn-v4:4601daaa-0314-0410-9a8b-c964a3c23b6b:trunk/lib2geom:1
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <cstdio>
 
2
#include <cstring>
 
3
#include <cstdlib>
 
4
#include <cmath>
 
5
 
 
6
#include <gtk/gtk.h>
 
7
#include <cassert>
 
8
#include <algorithm>
 
9
#include <sstream>
 
10
#include <iostream>
 
11
#include <vector>
 
12
#include "maybe.h"
 
13
#include "point.h"
 
14
#include "point-ops.h"
 
15
#include "point-fns.h"
 
16
#include "geom.h"
 
17
#include "path.h"
 
18
#include "path-to-polyline.h"
 
19
#include "read-svgd.h"
 
20
#include "path-find-points-of-interest.h"
 
21
#include "rotate.h"
 
22
#include "rotate-ops.h"
 
23
#include "arc-length.h"
 
24
#include "path-intersect.h"
 
25
 
 
26
using std::string;
 
27
using std::vector;
 
28
 
 
29
static GtkWidget *canvas;
 
30
static GdkGC *dash_gc;
 
31
static GdkGC *plain_gc;
 
32
Geom::Path display_path;
 
33
 
 
34
static Geom::Point old_handle_pos;
 
35
static Geom::Point old_mouse_point;
 
36
 
 
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]);
 
40
    cairo_stroke(cr);
 
41
}
 
42
 
 
43
void draw_spot(cairo_t *cr, Geom::Point h) {
 
44
    draw_line_seg(cr, h, h);
 
45
}
 
46
 
 
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);
 
56
}
 
57
 
 
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);
 
63
    cairo_stroke(cr);
 
64
}
 
65
 
 
66
void draw_ray(cairo_t *cr, Geom::Point h, Geom::Point dir) {
 
67
    draw_line_seg(cr, h, h+dir);
 
68
}
 
69
 
 
70
//line_intersection
 
71
/*static kind
 
72
segment_intersect(Geom::Point const &p00, Geom::Point const &p01,
 
73
                                 Geom::Point const &p10, Geom::Point const &p11,
 
74
                                 Geom::Point &result)
 
75
*/
 
76
 
 
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]);
 
82
 
 
83
    Geom::Point c;
 
84
    line_twopoint_intersect(h[0], h[1], h[3], h[4], c);
 
85
    draw_handle(cr, c);
 
86
    
 
87
    Geom::Point old;
 
88
    for(int i = 0; i <= 100; i++) {
 
89
        double t = i/100.0;
 
90
        
 
91
        Geom::Point n = (1-t)*h[0] + t*h[3];
 
92
        Geom::Point c1, c2;
 
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);
 
95
        Geom::Point six;
 
96
        line_twopoint_intersect(c1, h[3], c2, h[1], six);
 
97
        if(i)
 
98
            draw_line_seg(cr, old, six);
 
99
        old = six;
 
100
    }
 
101
}
 
102
 
 
103
void draw_path(cairo_t *cr, Geom::Path p) {
 
104
    path_to_polyline pl(p, 1);
 
105
    
 
106
    Geom::Point old(pl.handles[0]);
 
107
    
 
108
    for(unsigned i = 1; i < pl.handles.size(); i++) {
 
109
        Geom::Point p(pl.handles[i]);
 
110
        draw_line_seg(cr, old, p);
 
111
        old = p;
 
112
    }
 
113
    
 
114
}
 
115
 
 
116
Geom::Point* selected_handle = 0;
 
117
 
 
118
 
 
119
static gboolean
 
120
expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
 
121
{
 
122
    cairo_t *cr = gdk_cairo_create (widget->window);
 
123
    cairo_set_line_width (cr, 1);
 
124
    //draw (clock, cr);
 
125
 
 
126
    int width = 256;
 
127
    int height = 256;
 
128
    std::ostringstream notify;
 
129
    gdk_drawable_get_size(widget->window, &width, &height);
 
130
 
 
131
    for(int i = 0; i < display_path.handles.size(); i++) {
 
132
        draw_handle(cr, display_path.handles[i]);
 
133
    }
 
134
    draw_path(cr, display_path);
 
135
    //draw_elip(cr, handles);
 
136
    
 
137
    Geom::Point dir(1,1);
 
138
    /*
 
139
    vector<Geom::Path::PathLocation> pts = find_vector_extreme_points(display_path, dir);
 
140
    
 
141
    for(int i = 0; i < pts.size(); i++) {
 
142
        draw_circ(cr, display_path.point_at(pts[i]));
 
143
        }*/
 
144
    
 
145
    double dist = INFINITY;
 
146
 
 
147
    cairo_save(cr);
 
148
    cairo_set_source_rgba (cr, 0., 0., 0.5, 0.8);
 
149
 
 
150
    Geom::Path::PathLocation pl = 
 
151
        display_path.nearest_location(old_mouse_point, dist);
 
152
    {
 
153
        Geom::Point pos, tgt, acc;
 
154
        display_path.point_tangent_acc_at (pl, pos, tgt, acc);
 
155
        draw_circ(cr, pos);
 
156
        double kurvature = dot(acc, rot90(tgt))/pow(Geom::L2(tgt),3);
 
157
        
 
158
        if(fabs(kurvature) > 0.001)
 
159
            draw_ray(cr, pos, 
 
160
                     (1./kurvature)*Geom::unit_vector(rot90(tgt)));
 
161
        else // just normal
 
162
            draw_ray(cr, pos, rot90(tgt));
 
163
            
 
164
    }
 
165
    cairo_restore(cr);
 
166
 
 
167
    cairo_save(cr);
 
168
    cairo_set_source_rgba (cr, 0.25, 0.25, 0., 0.8);
 
169
 
 
170
    Geom::Path pth = display_path.subpath(display_path.indexed_elem(2), display_path.end());
 
171
    pth = pth*Geom::translate(Geom::Point(30, 30));
 
172
    draw_path(cr, pth);
 
173
    Bezier a, b;
 
174
    const int curve_seg = 3;
 
175
    Geom::Path::PathElem ai(*display_path.indexed_elem(curve_seg)), bi(*pth.indexed_elem(curve_seg));
 
176
    
 
177
    for(int i = 0; i < 4; i++) {
 
178
        a.p[i] = ai[i];
 
179
        b.p[i] = bi[i];
 
180
    }
 
181
    cairo_restore(cr);
 
182
    
 
183
    std::vector<std::pair <double, double> > ts = Geom::FindIntersections(a, b);
 
184
    cairo_save(cr);
 
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);
 
188
        
 
189
        draw_handle(cr, display_path.point_at(pl));
 
190
        Geom::Path::PathLocation p2(pth.indexed_elem(curve_seg), ts[i].second);
 
191
        
 
192
        draw_circ(cr, display_path.point_at(p2));
 
193
    }
 
194
    cairo_restore(cr);
 
195
    
 
196
    /*
 
197
    vector<Geom::Path::PathLocation> pts = 
 
198
        find_inflection_points(display_path);
 
199
  
 
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);
 
203
        //tgt *= 0.1;
 
204
        //acc *= 0.1;
 
205
        draw_handle(cr, display_path.point_at(pts[i]));
 
206
        draw_circ(cr, pos);
 
207
        
 
208
        //draw_ray(cr, pos+tgt, acc);
 
209
    }
 
210
    */
 
211
    notify << "path length: " << arc_length_integrating(display_path, 1e3) << "\n";
 
212
    
 
213
 
 
214
    {
 
215
        notify << std::ends;
 
216
        PangoLayout *layout = gtk_widget_create_pango_layout(widget, notify.str().c_str());
 
217
        PangoRectangle logical_extent;
 
218
        pango_layout_get_pixel_extents(layout,
 
219
                                       NULL,
 
220
                                       &logical_extent);
 
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());
 
224
        //cairo_stroke (cr);
 
225
        /*pango_cairo_draw_layout(cr,
 
226
          0, height-logical_extent.height, layout);*/
 
227
    }
 
228
    double x, y;
 
229
    x = widget->allocation.x + widget->allocation.width / 2;
 
230
    y = widget->allocation.y + widget->allocation.height / 2;
 
231
 
 
232
    double radius;
 
233
    radius = std::min (widget->allocation.width / 2,
 
234
                       widget->allocation.height / 2) - 5;
 
235
 
 
236
    cairo_destroy (cr);
 
237
    
 
238
    return TRUE;
 
239
}
 
240
 
 
241
static void handle_mouse(GtkWidget* widget) {
 
242
    gtk_widget_queue_draw (widget);
 
243
}
 
244
 
 
245
static gint mouse_motion_event(GtkWidget* widget, GdkEventMotion* e, gpointer data) {
 
246
    Geom::Point mouse(e->x, e->y);
 
247
    
 
248
    if(e->state & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)) {
 
249
        if(selected_handle) {
 
250
            *selected_handle = mouse - old_handle_pos;
 
251
            
 
252
        }
 
253
        handle_mouse(widget);
 
254
    }
 
255
 
 
256
    if(e->state & (GDK_BUTTON2_MASK)) {
 
257
        gtk_widget_queue_draw(widget);
 
258
    }
 
259
    
 
260
    old_mouse_point = mouse;
 
261
 
 
262
    return FALSE;
 
263
}
 
264
 
 
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];
 
272
            }
 
273
        }
 
274
        handle_mouse(window);
 
275
    } else if(e->button == 2) {
 
276
        gtk_widget_queue_draw(window);
 
277
    }
 
278
    old_mouse_point = mouse;
 
279
 
 
280
    return FALSE;
 
281
}
 
282
 
 
283
static gint mouse_release_event(GtkWidget* window, GdkEventButton* e, gpointer data) {
 
284
    selected_handle = 0;
 
285
    return FALSE;
 
286
}
 
287
 
 
288
static gint key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer) {
 
289
    gint ret = FALSE;
 
290
    if (event->keyval == ' ') {
 
291
        ret = TRUE;
 
292
    } else if (event->keyval == 'l') {
 
293
        ret = TRUE;
 
294
    } else if (event->keyval == 'd') {
 
295
        write_svgd(stderr, display_path);
 
296
        ret = TRUE;
 
297
    } else if ('0' <= event->keyval
 
298
               && event->keyval <= '9') {
 
299
        ret = TRUE;
 
300
    } else if ('h' == event->keyval) {
 
301
        ret = TRUE;
 
302
    }
 
303
 
 
304
    if (ret) {
 
305
        gtk_widget_queue_draw(widget);
 
306
    }
 
307
 
 
308
    return ret;
 
309
}
 
310
 
 
311
static gint
 
312
delete_event_cb(GtkWidget* window, GdkEventAny* e, gpointer data)
 
313
{
 
314
    gtk_main_quit();
 
315
    return FALSE;
 
316
}
 
317
 
 
318
#include "translate-ops.h"
 
319
#include "scale-ops.h"
 
320
#include "translate-scale-ops.h"
 
321
 
 
322
 
 
323
int main(int argc, char **argv) {
 
324
    char const *const filename = (argc >= 2
 
325
                                  ? argv[1]
 
326
                                  : "toy.svgd");
 
327
    FILE* f = fopen(filename, "r");
 
328
    if (!f) {
 
329
        perror(filename);
 
330
        return 1;
 
331
    }
 
332
    display_path = read_svgd(f);
 
333
 
 
334
    Geom::Rect r = display_path.bbox();
 
335
    
 
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));
 
339
    
 
340
    gtk_init (&argc, &argv);
 
341
 
 
342
    gdk_rgb_init();
 
343
 
 
344
    GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
345
 
 
346
    gtk_window_set_title(GTK_WINDOW(window), "text toy");
 
347
 
 
348
    gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, TRUE);
 
349
 
 
350
    gtk_signal_connect(GTK_OBJECT(window),
 
351
                       "delete_event",
 
352
                       GTK_SIGNAL_FUNC(delete_event_cb),
 
353
                       NULL);
 
354
 
 
355
    gtk_widget_push_visual(gdk_rgb_get_visual());
 
356
    gtk_widget_push_colormap(gdk_rgb_get_cmap());
 
357
    canvas = gtk_drawing_area_new();
 
358
 
 
359
    gtk_signal_connect(GTK_OBJECT (canvas),
 
360
                       "expose_event",
 
361
                       GTK_SIGNAL_FUNC(expose_event),
 
362
                       0);
 
363
    gtk_widget_add_events(canvas, (GDK_BUTTON_PRESS_MASK |
 
364
                                   GDK_BUTTON_RELEASE_MASK |
 
365
                                   GDK_KEY_PRESS_MASK    |
 
366
                                   GDK_POINTER_MOTION_MASK));
 
367
    gtk_signal_connect(GTK_OBJECT (canvas),
 
368
                       "button_press_event",
 
369
                       GTK_SIGNAL_FUNC(mouse_event),
 
370
                       0);
 
371
    gtk_signal_connect(GTK_OBJECT (canvas),
 
372
                       "button_release_event",
 
373
                       GTK_SIGNAL_FUNC(mouse_release_event),
 
374
                       0);
 
375
    gtk_signal_connect(GTK_OBJECT (canvas),
 
376
                       "motion_notify_event",
 
377
                       GTK_SIGNAL_FUNC(mouse_motion_event),
 
378
                       0);
 
379
    gtk_signal_connect(GTK_OBJECT(canvas),
 
380
                       "key_press_event",
 
381
                       GTK_SIGNAL_FUNC(key_release_event),
 
382
                       0);
 
383
 
 
384
    gtk_widget_pop_colormap();
 
385
    gtk_widget_pop_visual();
 
386
 
 
387
    GtkWidget *vb = gtk_vbox_new(0, 0);
 
388
 
 
389
 
 
390
    gtk_container_add(GTK_CONTAINER(window), vb);
 
391
 
 
392
    gtk_box_pack_start(GTK_BOX(vb), canvas, TRUE, TRUE, 0);
 
393
 
 
394
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
 
395
 
 
396
    gtk_widget_show_all(window);
 
397
 
 
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);
 
401
    GdkColor colour;
 
402
    colour.red = 0xffff;
 
403
    colour.green = 0xffff;
 
404
    colour.blue = 0xffff;
 
405
 
 
406
    plain_gc = gdk_gc_new(canvas->window);
 
407
    
 
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);
 
413
 
 
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));
 
419
 
 
420
    gtk_main();
 
421
 
 
422
    return 0;
 
423
}
 
424
 
 
425
/*
 
426
  Local Variables:
 
427
  mode:c++
 
428
  c-file-style:"stroustrup"
 
429
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
430
  indent-tabs-mode:nil
 
431
  fill-column:99
 
432
  End:
 
433
*/
 
434
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :