~centralelyon2010/inkscape/imagelinks2

5526 by joncruz
Added missing eraser files
1
/*
2
 * Eraser drawing mode
3
 *
4
 * Authors:
5
 *   Mitsuru Oka <oka326@parkcity.ne.jp>
6
 *   Lauris Kaplinski <lauris@kaplinski.com>
7
 *   bulia byak <buliabyak@users.sf.net>
8
 *   MenTaLguY <mental@rydia.net>
9
 *   Jon A. Cruz <jon@joncruz.org>
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
10
 *   Abhishek Sharma
5526 by joncruz
Added missing eraser files
11
 *
12
 * The original dynadraw code:
13
 *   Paul Haeberli <paul@sgi.com>
14
 *
15
 * Copyright (C) 1998 The Free Software Foundation
16
 * Copyright (C) 1999-2005 authors
17
 * Copyright (C) 2001-2002 Ximian, Inc.
18
 * Copyright (C) 2005-2007 bulia byak
19
 * Copyright (C) 2006 MenTaLguY
20
 * Copyright (C) 2008 Jon A. Cruz
21
 *
22
 * Released under GNU GPL, read the file 'COPYING' for more information
23
 */
24
25
#define noERASER_VERBOSE
26
27
#include "config.h"
28
29
#include <gtk/gtk.h>
30
#include <gdk/gdkkeysyms.h>
31
#include <glibmm/i18n.h>
32
#include <string>
33
#include <cstring>
34
#include <numeric>
35
36
#include "svg/svg.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
37
#include "display/sp-canvas.h"
5526 by joncruz
Added missing eraser files
38
#include "display/canvas-bpath.h"
6983 by johanengelen
use 2geom bezier fitting (is copy of inkscape's)
39
#include <2geom/bezier-utils.h>
5526 by joncruz
Added missing eraser files
40
41
#include <glib/gmem.h>
42
#include "macros.h"
43
#include "document.h"
44
#include "selection.h"
45
#include "desktop.h"
46
#include "desktop-events.h"
47
#include "desktop-handles.h"
48
#include "desktop-style.h"
49
#include "message-context.h"
6885 by Ted Gould
From trunk
50
#include "preferences.h"
5526 by joncruz
Added missing eraser files
51
#include "pixmaps/cursor-eraser.xpm"
52
#include "xml/repr.h"
53
#include "context-fns.h"
54
#include "sp-item.h"
55
#include "color.h"
5593 by joncruz
Initial cut of touch-delete mode
56
#include "rubberband.h"
5526 by joncruz
Added missing eraser files
57
#include "splivarot.h"
58
#include "sp-item-group.h"
59
#include "sp-shape.h"
60
#include "sp-path.h"
61
#include "sp-text.h"
62
#include "display/canvas-bpath.h"
63
#include "display/canvas-arena.h"
64
#include "livarot/Shape.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
65
#include <2geom/math-utils.h>
6228 by johanengelen
* 2geomify polygon svg writing
66
#include <2geom/pathvector.h>
5526 by joncruz
Added missing eraser files
67
68
#include "eraser-context.h"
69
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
70
using Inkscape::DocumentUndo;
71
5526 by joncruz
Added missing eraser files
72
#define ERC_RED_RGBA 0xff0000ff
73
74
#define TOLERANCE_ERASER 0.1
75
76
#define ERASER_EPSILON 0.5e-6
77
#define ERASER_EPSILON_START 0.5e-2
78
#define ERASER_VEL_START 1e-5
79
80
#define DRAG_MIN 0.0
81
#define DRAG_DEFAULT 1.0
82
#define DRAG_MAX 1.0
83
84
85
static void sp_eraser_context_class_init(SPEraserContextClass *klass);
86
static void sp_eraser_context_init(SPEraserContext *erc);
87
static void sp_eraser_context_dispose(GObject *object);
88
89
static void sp_eraser_context_setup(SPEventContext *ec);
6885 by Ted Gould
From trunk
90
static void sp_eraser_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val);
5526 by joncruz
Added missing eraser files
91
static gint sp_eraser_context_root_handler(SPEventContext *ec, GdkEvent *event);
92
93
static void clear_current(SPEraserContext *dc);
94
static void set_to_accumulated(SPEraserContext *dc);
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
95
static void add_cap(SPCurve *curve, Geom::Point const &pre, Geom::Point const &from, Geom::Point const &to, Geom::Point const &post, double rounding);
5526 by joncruz
Added missing eraser files
96
static void accumulate_eraser(SPEraserContext *dc);
97
98
static void fit_and_split(SPEraserContext *erc, gboolean release);
99
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
100
static void sp_eraser_reset(SPEraserContext *erc, Geom::Point p);
101
static Geom::Point sp_eraser_get_npoint(SPEraserContext const *erc, Geom::Point v);
102
static Geom::Point sp_eraser_get_vpoint(SPEraserContext const *erc, Geom::Point n);
5526 by joncruz
Added missing eraser files
103
static void draw_temporary_box(SPEraserContext *dc);
104
105
5717 by joncruz
Refactoring begining
106
static SPEventContextClass *eraser_parent_class = 0;
5526 by joncruz
Added missing eraser files
107
5717 by joncruz
Refactoring begining
108
GType sp_eraser_context_get_type(void)
5526 by joncruz
Added missing eraser files
109
{
110
    static GType type = 0;
111
    if (!type) {
112
        GTypeInfo info = {
113
            sizeof(SPEraserContextClass),
5717 by joncruz
Refactoring begining
114
            0, // base_init
115
            0, // base_finalize
116
            (GClassInitFunc)sp_eraser_context_class_init,
117
            0, // class_finalize
118
            0, // class_data
5526 by joncruz
Added missing eraser files
119
            sizeof(SPEraserContext),
5717 by joncruz
Refactoring begining
120
            0, // n_preallocs
121
            (GInstanceInitFunc)sp_eraser_context_init,
122
            0 // value_table
5526 by joncruz
Added missing eraser files
123
        };
5759 by joncruz
Refactoring out common code
124
        type = g_type_register_static(SP_TYPE_COMMON_CONTEXT, "SPEraserContext", &info, static_cast<GTypeFlags>(0));
5526 by joncruz
Added missing eraser files
125
    }
126
    return type;
127
}
128
129
static void
130
sp_eraser_context_class_init(SPEraserContextClass *klass)
131
{
132
    GObjectClass *object_class = (GObjectClass *) klass;
133
    SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
134
5717 by joncruz
Refactoring begining
135
    eraser_parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass);
5526 by joncruz
Added missing eraser files
136
137
    object_class->dispose = sp_eraser_context_dispose;
138
139
    event_context_class->setup = sp_eraser_context_setup;
140
    event_context_class->set = sp_eraser_context_set;
141
    event_context_class->root_handler = sp_eraser_context_root_handler;
142
}
143
144
static void
145
sp_eraser_context_init(SPEraserContext *erc)
146
{
5759 by joncruz
Refactoring out common code
147
    erc->cursor_shape = cursor_eraser_xpm;
148
    erc->hot_x = 4;
149
    erc->hot_y = 4;
5526 by joncruz
Added missing eraser files
150
}
151
152
static void
153
sp_eraser_context_dispose(GObject *object)
154
{
5759 by joncruz
Refactoring out common code
155
    //SPEraserContext *erc = SP_ERASER_CONTEXT(object);
5526 by joncruz
Added missing eraser files
156
5717 by joncruz
Refactoring begining
157
    G_OBJECT_CLASS(eraser_parent_class)->dispose(object);
5526 by joncruz
Added missing eraser files
158
}
159
160
static void
161
sp_eraser_context_setup(SPEventContext *ec)
162
{
163
    SPEraserContext *erc = SP_ERASER_CONTEXT(ec);
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
164
    SPDesktop *desktop = ec->desktop;
5526 by joncruz
Added missing eraser files
165
5717 by joncruz
Refactoring begining
166
    if (((SPEventContextClass *) eraser_parent_class)->setup)
167
        ((SPEventContextClass *) eraser_parent_class)->setup(ec);
5526 by joncruz
Added missing eraser files
168
6339 by johanengelen
convert all SPCurve's points and matrices arguments and return types to 2Geom
169
    erc->accumulated = new SPCurve();
170
    erc->currentcurve = new SPCurve();
5526 by joncruz
Added missing eraser files
171
6339 by johanengelen
convert all SPCurve's points and matrices arguments and return types to 2Geom
172
    erc->cal1 = new SPCurve();
173
    erc->cal2 = new SPCurve();
5526 by joncruz
Added missing eraser files
174
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
175
    erc->currentshape = sp_canvas_item_new(sp_desktop_sketch(desktop), SP_TYPE_CANVAS_BPATH, NULL);
5526 by joncruz
Added missing eraser files
176
    sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(erc->currentshape), ERC_RED_RGBA, SP_WIND_RULE_EVENODD);
177
    sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(erc->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
178
    /* fixme: Cannot we cascade it to root more clearly? */
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
179
    g_signal_connect(G_OBJECT(erc->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), desktop);
5526 by joncruz
Added missing eraser files
180
181
/*
182
static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = {
183
    {"mass",0.02, 0.0, 1.0},
184
    {"wiggle",0.0, 0.0, 1.0},
185
    {"angle",30.0, -90.0, 90.0},
186
    {"thinning",0.1, -1.0, 1.0},
187
    {"tremor",0.0, 0.0, 1.0},
188
    {"flatness",0.9, 0.0, 1.0},
189
    {"cap_rounding",0.0, 0.0, 5.0}
190
};
191
*/
192
193
    sp_event_context_read(ec, "mass");
194
    sp_event_context_read(ec, "wiggle");
195
    sp_event_context_read(ec, "angle");
196
    sp_event_context_read(ec, "width");
197
    sp_event_context_read(ec, "thinning");
198
    sp_event_context_read(ec, "tremor");
199
    sp_event_context_read(ec, "flatness");
200
    sp_event_context_read(ec, "tracebackground");
201
    sp_event_context_read(ec, "usepressure");
202
    sp_event_context_read(ec, "usetilt");
203
    sp_event_context_read(ec, "abs_width");
204
    sp_event_context_read(ec, "cap_rounding");
205
206
    erc->is_drawing = false;
207
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
208
    erc->_message_context = new Inkscape::MessageContext(desktop->messageStack());
5526 by joncruz
Added missing eraser files
209
6885 by Ted Gould
From trunk
210
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
211
    if (prefs->getBool("/tools/eraser/selcue", 0) != 0) {
5526 by joncruz
Added missing eraser files
212
        ec->enableSelectionCue();
213
    }
214
// TODO temp force:
215
    ec->enableSelectionCue();
216
217
}
218
219
static void
6885 by Ted Gould
From trunk
220
sp_eraser_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val)
5526 by joncruz
Added missing eraser files
221
{
5780 by joncruz
Pass through more calls to parent contexts, and added more common property handling.
222
    //pass on up to parent class to handle common attributes.
223
    if ( eraser_parent_class->set ) {
6885 by Ted Gould
From trunk
224
        eraser_parent_class->set(ec, val);
5526 by joncruz
Added missing eraser files
225
    }
226
}
227
228
static double
229
flerp(double f0, double f1, double p)
230
{
231
    return f0 + ( f1 - f0 ) * p;
232
}
233
234
/* Get normalized point */
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
235
static Geom::Point
236
sp_eraser_get_npoint(SPEraserContext const *dc, Geom::Point v)
5526 by joncruz
Added missing eraser files
237
{
6839 by cilix42
Next roud of NR ==> Geom conversion
238
    Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area();
239
    double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] );
240
    return Geom::Point(( v[Geom::X] - drect.min()[Geom::X] ) / max,  ( v[Geom::Y] - drect.min()[Geom::Y] ) / max);
5526 by joncruz
Added missing eraser files
241
}
242
243
/* Get view point */
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
244
static Geom::Point
245
sp_eraser_get_vpoint(SPEraserContext const *dc, Geom::Point n)
5526 by joncruz
Added missing eraser files
246
{
6839 by cilix42
Next roud of NR ==> Geom conversion
247
    Geom::Rect drect = SP_EVENT_CONTEXT(dc)->desktop->get_display_area();
248
    double const max = MAX ( drect.dimensions()[Geom::X], drect.dimensions()[Geom::Y] );
249
    return Geom::Point(n[Geom::X] * max + drect.min()[Geom::X], n[Geom::Y] * max + drect.min()[Geom::Y]);
5526 by joncruz
Added missing eraser files
250
}
251
252
static void
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
253
sp_eraser_reset(SPEraserContext *dc, Geom::Point p)
5526 by joncruz
Added missing eraser files
254
{
255
    dc->last = dc->cur = sp_eraser_get_npoint(dc, p);
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
256
    dc->vel = Geom::Point(0,0);
5526 by joncruz
Added missing eraser files
257
    dc->vel_max = 0;
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
258
    dc->acc = Geom::Point(0,0);
259
    dc->ang = Geom::Point(0,0);
260
    dc->del = Geom::Point(0,0);
5526 by joncruz
Added missing eraser files
261
}
262
263
static void
264
sp_eraser_extinput(SPEraserContext *dc, GdkEvent *event)
265
{
266
    if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &dc->pressure))
267
        dc->pressure = CLAMP (dc->pressure, ERC_MIN_PRESSURE, ERC_MAX_PRESSURE);
268
    else
269
        dc->pressure = ERC_DEFAULT_PRESSURE;
270
271
    if (gdk_event_get_axis (event, GDK_AXIS_XTILT, &dc->xtilt))
272
        dc->xtilt = CLAMP (dc->xtilt, ERC_MIN_TILT, ERC_MAX_TILT);
273
    else
274
        dc->xtilt = ERC_DEFAULT_TILT;
275
276
    if (gdk_event_get_axis (event, GDK_AXIS_YTILT, &dc->ytilt))
277
        dc->ytilt = CLAMP (dc->ytilt, ERC_MIN_TILT, ERC_MAX_TILT);
278
    else
279
        dc->ytilt = ERC_DEFAULT_TILT;
280
}
281
282
283
static gboolean
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
284
sp_eraser_apply(SPEraserContext *dc, Geom::Point p)
5526 by joncruz
Added missing eraser files
285
{
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
286
    Geom::Point n = sp_eraser_get_npoint(dc, p);
5526 by joncruz
Added missing eraser files
287
288
    /* Calculate mass and drag */
289
    double const mass = flerp(1.0, 160.0, dc->mass);
290
    double const drag = flerp(0.0, 0.5, dc->drag * dc->drag);
291
292
    /* Calculate force and acceleration */
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
293
    Geom::Point force = n - dc->cur;
5526 by joncruz
Added missing eraser files
294
295
    // If force is below the absolute threshold ERASER_EPSILON,
296
    // or we haven't yet reached ERASER_VEL_START (i.e. at the beginning of stroke)
297
    // _and_ the force is below the (higher) ERASER_EPSILON_START threshold,
298
    // discard this move. 
299
    // This prevents flips, blobs, and jerks caused by microscopic tremor of the tablet pen,
300
    // especially bothersome at the start of the stroke where we don't yet have the inertia to
301
    // smooth them out.
6885 by Ted Gould
From trunk
302
    if ( Geom::L2(force) < ERASER_EPSILON || (dc->vel_max < ERASER_VEL_START && Geom::L2(force) < ERASER_EPSILON_START)) {
5526 by joncruz
Added missing eraser files
303
        return FALSE;
304
    }
305
306
    dc->acc = force / mass;
307
308
    /* Calculate new velocity */
309
    dc->vel += dc->acc;
310
6885 by Ted Gould
From trunk
311
    if (Geom::L2(dc->vel) > dc->vel_max)
312
        dc->vel_max = Geom::L2(dc->vel);
5526 by joncruz
Added missing eraser files
313
314
    /* Calculate angle of drawing tool */
315
316
    double a1;
317
    if (dc->usetilt) {
318
        // 1a. calculate nib angle from input device tilt:
319
        gdouble length = std::sqrt(dc->xtilt*dc->xtilt + dc->ytilt*dc->ytilt);;
320
321
        if (length > 0) {
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
322
            Geom::Point ang1 = Geom::Point(dc->ytilt/length, dc->xtilt/length);
5526 by joncruz
Added missing eraser files
323
            a1 = atan2(ang1);
324
        }
325
        else
326
            a1 = 0.0;
327
    }
328
    else {
329
        // 1b. fixed dc->angle (absolutely flat nib):
330
        double const radians = ( (dc->angle - 90) / 180.0 ) * M_PI;
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
331
        Geom::Point ang1 = Geom::Point(-sin(radians),  cos(radians));
5526 by joncruz
Added missing eraser files
332
        a1 = atan2(ang1);
333
    }
334
335
    // 2. perpendicular to dc->vel (absolutely non-flat nib):
6954 by johanengelen
2geom eraser tool
336
    gdouble const mag_vel = Geom::L2(dc->vel);
5526 by joncruz
Added missing eraser files
337
    if ( mag_vel < ERASER_EPSILON ) {
338
        return FALSE;
339
    }
6954 by johanengelen
2geom eraser tool
340
    Geom::Point ang2 = Geom::rot90(dc->vel) / mag_vel;
5526 by joncruz
Added missing eraser files
341
342
    // 3. Average them using flatness parameter:
343
    // calculate angles
344
    double a2 = atan2(ang2);
345
    // flip a2 to force it to be in the same half-circle as a1
346
    bool flipped = false;
347
    if (fabs (a2-a1) > 0.5*M_PI) {
348
        a2 += M_PI;
349
        flipped = true;
350
    }
351
    // normalize a2
352
    if (a2 > M_PI)
353
        a2 -= 2*M_PI;
354
    if (a2 < -M_PI)
355
        a2 += 2*M_PI;
356
    // find the flatness-weighted bisector angle, unflip if a2 was flipped
357
    // FIXME: when dc->vel is oscillating around the fixed angle, the new_ang flips back and forth. How to avoid this?
358
    double new_ang = a1 + (1 - dc->flatness) * (a2 - a1) - (flipped? M_PI : 0);
359
360
    // Try to detect a sudden flip when the new angle differs too much from the previous for the
361
    // current velocity; in that case discard this move
6954 by johanengelen
2geom eraser tool
362
    double angle_delta = Geom::L2(Geom::Point (cos (new_ang), sin (new_ang)) - dc->ang);
363
    if ( angle_delta / Geom::L2(dc->vel) > 4000 ) {
5526 by joncruz
Added missing eraser files
364
        return FALSE;
365
    }
366
367
    // convert to point
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
368
    dc->ang = Geom::Point (cos (new_ang), sin (new_ang));
5526 by joncruz
Added missing eraser files
369
6954 by johanengelen
2geom eraser tool
370
//    g_print ("force %g  acc %g  vel_max %g  vel %g  a1 %g  a2 %g  new_ang %g\n", Geom::L2(force), Geom::L2(dc->acc), dc->vel_max, Geom::L2(dc->vel), a1, a2, new_ang);
5526 by joncruz
Added missing eraser files
371
372
    /* Apply drag */
373
    dc->vel *= 1.0 - drag;
374
375
    /* Update position */
376
    dc->last = dc->cur;
377
    dc->cur += dc->vel;
378
379
    return TRUE;
380
}
381
382
static void
383
sp_eraser_brush(SPEraserContext *dc)
384
{
385
    g_assert( dc->npoints >= 0 && dc->npoints < SAMPLING_SIZE );
386
387
    // How much velocity thins strokestyle
388
    double vel_thin = flerp (0, 160, dc->vel_thin);
389
390
    // Influence of pressure on thickness
391
    double pressure_thick = (dc->usepressure ? dc->pressure : 1.0);
392
393
    // get the real brush point, not the same as pointer (affected by hatch tracking and/or mass
394
    // drag)
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
395
    Geom::Point brush = sp_eraser_get_vpoint(dc, dc->cur);
396
    Geom::Point brush_w = SP_EVENT_CONTEXT(dc)->desktop->d2w(brush); 
5526 by joncruz
Added missing eraser files
397
398
    double trace_thick = 1;
399
6954 by johanengelen
2geom eraser tool
400
    double width = (pressure_thick * trace_thick - vel_thin * Geom::L2(dc->vel)) * dc->width;
5526 by joncruz
Added missing eraser files
401
402
    double tremble_left = 0, tremble_right = 0;
403
    if (dc->tremor > 0) {
404
        // obtain two normally distributed random variables, using polar Box-Muller transform
405
        double x1, x2, w, y1, y2;
406
        do {
407
            x1 = 2.0 * g_random_double_range(0,1) - 1.0;
408
            x2 = 2.0 * g_random_double_range(0,1) - 1.0;
409
            w = x1 * x1 + x2 * x2;
410
        } while ( w >= 1.0 );
411
        w = sqrt( (-2.0 * log( w ) ) / w );
412
        y1 = x1 * w;
413
        y2 = x2 * w;
414
415
        // deflect both left and right edges randomly and independently, so that:
416
        // (1) dc->tremor=1 corresponds to sigma=1, decreasing dc->tremor narrows the bell curve;
417
        // (2) deflection depends on width, but is upped for small widths for better visual uniformity across widths;
418
        // (3) deflection somewhat depends on speed, to prevent fast strokes looking
419
        // comparatively smooth and slow ones excessively jittery
6954 by johanengelen
2geom eraser tool
420
        tremble_left  = (y1)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel));
421
        tremble_right = (y2)*dc->tremor * (0.15 + 0.8*width) * (0.35 + 14*Geom::L2(dc->vel));
5526 by joncruz
Added missing eraser files
422
    }
423
424
    if ( width < 0.02 * dc->width ) {
425
        width = 0.02 * dc->width;
426
    }
427
428
    double dezoomify_factor = 0.05 * 1000;
429
    if (!dc->abs_width) {
430
        dezoomify_factor /= SP_EVENT_CONTEXT(dc)->desktop->current_zoom();
431
    }
432
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
433
    Geom::Point del_left = dezoomify_factor * (width + tremble_left) * dc->ang;
434
    Geom::Point del_right = dezoomify_factor * (width + tremble_right) * dc->ang;
5526 by joncruz
Added missing eraser files
435
436
    dc->point1[dc->npoints] = brush + del_left;
437
    dc->point2[dc->npoints] = brush - del_right;
438
439
    dc->del = 0.5*(del_left + del_right);
440
441
    dc->npoints++;
442
}
443
444
void
445
sp_erc_update_toolbox (SPDesktop *desktop, const gchar *id, double value)
446
{
447
    desktop->setToolboxAdjustmentValue (id, value);
448
}
449
450
static void
451
eraser_cancel(SPEraserContext *dc)
452
{
453
    SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop;
454
    dc->dragging = FALSE;
455
    dc->is_drawing = false;
456
    sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), 0);
457
            /* Remove all temporary line segments */
458
            while (dc->segments) {
459
                gtk_object_destroy(GTK_OBJECT(dc->segments->data));
460
                dc->segments = g_slist_remove(dc->segments, dc->segments->data);
461
            }
462
            /* reset accumulated curve */
5609 by johanengelen
struct SPCurve => class SPCurve
463
            dc->accumulated->reset();
5526 by joncruz
Added missing eraser files
464
            clear_current(dc);
465
            if (dc->repr) {
466
                dc->repr = NULL;
467
            }
468
}
469
470
471
gint
472
sp_eraser_context_root_handler(SPEventContext *event_context,
473
                                  GdkEvent *event)
474
{
475
    SPEraserContext *dc = SP_ERASER_CONTEXT(event_context);
476
    SPDesktop *desktop = event_context->desktop;
477
478
    gint ret = FALSE;
479
480
    switch (event->type) {
481
        case GDK_BUTTON_PRESS:
482
            if (event->button.button == 1 && !event_context->space_panning) {
483
484
                if (Inkscape::have_viable_layer(desktop, dc->_message_context) == false) {
485
                    return TRUE;
486
                }
487
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
488
                Geom::Point const button_w(event->button.x,
5526 by joncruz
Added missing eraser files
489
                                         event->button.y);
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
490
                Geom::Point const button_dt(desktop->w2d(button_w));
5526 by joncruz
Added missing eraser files
491
                sp_eraser_reset(dc, button_dt);
492
                sp_eraser_extinput(dc, event);
493
                sp_eraser_apply(dc, button_dt);
5609 by johanengelen
struct SPCurve => class SPCurve
494
                dc->accumulated->reset();
5526 by joncruz
Added missing eraser files
495
                if (dc->repr) {
496
                    dc->repr = NULL;
497
                }
498
6630 by cilix42
Removal of SP_ACTIVE_DESKTOP, next take
499
                Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
500
                Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH);
5593 by joncruz
Initial cut of touch-delete mode
501
5526 by joncruz
Added missing eraser files
502
                /* initialize first point */
503
                dc->npoints = 0;
504
505
                sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
506
                                    ( GDK_KEY_PRESS_MASK |
507
                                      GDK_BUTTON_RELEASE_MASK |
508
                                      GDK_POINTER_MOTION_MASK |
509
                                      GDK_BUTTON_PRESS_MASK ),
510
                                    NULL,
511
                                    event->button.time);
512
513
                ret = TRUE;
514
515
                sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3);
516
                dc->is_drawing = true;
517
            }
518
            break;
519
        case GDK_MOTION_NOTIFY:
520
        {
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
521
            Geom::Point const motion_w(event->motion.x,
5526 by joncruz
Added missing eraser files
522
                                     event->motion.y);
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
523
            Geom::Point motion_dt(desktop->w2d(motion_w));
5526 by joncruz
Added missing eraser files
524
            sp_eraser_extinput(dc, event);
525
526
            dc->_message_context->clear();
527
528
            if ( dc->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) {
529
                dc->dragging = TRUE;
530
5593 by joncruz
Initial cut of touch-delete mode
531
                dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> an eraser stroke"));
5526 by joncruz
Added missing eraser files
532
533
                if (!sp_eraser_apply(dc, motion_dt)) {
534
                    ret = TRUE;
535
                    break;
536
                }
537
538
                if ( dc->cur != dc->last ) {
539
                    sp_eraser_brush(dc);
540
                    g_assert( dc->npoints > 0 );
541
                    fit_and_split(dc, FALSE);
542
                }
543
                ret = TRUE;
544
            }
6630 by cilix42
Removal of SP_ACTIVE_DESKTOP, next take
545
            Inkscape::Rubberband::get(desktop)->move(motion_dt);
5526 by joncruz
Added missing eraser files
546
        }
547
        break;
548
549
550
    case GDK_BUTTON_RELEASE:
551
    {
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
552
        Geom::Point const motion_w(event->button.x, event->button.y);
553
        Geom::Point const motion_dt(desktop->w2d(motion_w));
5526 by joncruz
Added missing eraser files
554
555
        sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);
556
        sp_canvas_end_forced_full_redraws(desktop->canvas);
557
        dc->is_drawing = false;
558
559
        if (dc->dragging && event->button.button == 1 && !event_context->space_panning) {
560
            dc->dragging = FALSE;
561
562
            sp_eraser_apply(dc, motion_dt);
563
564
            /* Remove all temporary line segments */
565
            while (dc->segments) {
566
                gtk_object_destroy(GTK_OBJECT(dc->segments->data));
567
                dc->segments = g_slist_remove(dc->segments, dc->segments->data);
568
            }
569
570
            /* Create object */
571
            fit_and_split(dc, TRUE);
572
            accumulate_eraser(dc);
573
            set_to_accumulated(dc); // performs document_done
574
575
            /* reset accumulated curve */
5609 by johanengelen
struct SPCurve => class SPCurve
576
            dc->accumulated->reset();
5526 by joncruz
Added missing eraser files
577
578
            clear_current(dc);
579
            if (dc->repr) {
580
                dc->repr = NULL;
581
            }
582
583
            dc->_message_context->clear();
584
            ret = TRUE;
585
        }
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
586
        if (Inkscape::Rubberband::get(desktop)->is_started()) {
587
            Inkscape::Rubberband::get(desktop)->stop();
588
        }
589
            
5526 by joncruz
Added missing eraser files
590
        break;
591
    }
592
593
    case GDK_KEY_PRESS:
594
        switch (get_group0_keyval (&event->key)) {
595
        case GDK_Up:
596
        case GDK_KP_Up:
597
            if (!MOD__CTRL_ONLY) {
598
                dc->angle += 5.0;
599
                if (dc->angle > 90.0)
600
                    dc->angle = 90.0;
601
                sp_erc_update_toolbox (desktop, "eraser-angle", dc->angle);
602
                ret = TRUE;
603
            }
604
            break;
605
        case GDK_Down:
606
        case GDK_KP_Down:
607
            if (!MOD__CTRL_ONLY) {
608
                dc->angle -= 5.0;
609
                if (dc->angle < -90.0)
610
                    dc->angle = -90.0;
611
                sp_erc_update_toolbox (desktop, "eraser-angle", dc->angle);
612
                ret = TRUE;
613
            }
614
            break;
615
        case GDK_Right:
616
        case GDK_KP_Right:
617
            if (!MOD__CTRL_ONLY) {
618
                dc->width += 0.01;
619
                if (dc->width > 1.0)
620
                    dc->width = 1.0;
621
                sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100); // the same spinbutton is for alt+x
622
                ret = TRUE;
623
            }
624
            break;
625
        case GDK_Left:
626
        case GDK_KP_Left:
627
            if (!MOD__CTRL_ONLY) {
628
                dc->width -= 0.01;
629
                if (dc->width < 0.01)
630
                    dc->width = 0.01;
631
                sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100);
632
                ret = TRUE;
633
            }
634
            break;
635
        case GDK_Home:
636
        case GDK_KP_Home:
637
            dc->width = 0.01;
638
            sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100);
639
            ret = TRUE;
640
            break;
641
        case GDK_End:
642
        case GDK_KP_End:
643
            dc->width = 1.0;
644
            sp_erc_update_toolbox (desktop, "altx-eraser", dc->width * 100);
645
            ret = TRUE;
646
            break;
647
        case GDK_x:
648
        case GDK_X:
649
            if (MOD__ALT_ONLY) {
650
                desktop->setToolboxFocusTo ("altx-eraser");
651
                ret = TRUE;
652
            }
653
            break;
654
        case GDK_Escape:
6630 by cilix42
Removal of SP_ACTIVE_DESKTOP, next take
655
            Inkscape::Rubberband::get(desktop)->stop();
5526 by joncruz
Added missing eraser files
656
            if (dc->is_drawing) {
657
                // if drawing, cancel, otherwise pass it up for deselecting
658
                eraser_cancel (dc);
659
                ret = TRUE;
660
            }
661
            break;
662
        case GDK_z:
663
        case GDK_Z:
664
            if (MOD__CTRL_ONLY && dc->is_drawing) {
665
                // if drawing, cancel, otherwise pass it up for undo
666
                eraser_cancel (dc);
667
                ret = TRUE;
668
            }
669
            break;
670
        default:
671
            break;
672
        }
673
        break;
674
675
    case GDK_KEY_RELEASE:
676
        switch (get_group0_keyval(&event->key)) {
677
            case GDK_Control_L:
678
            case GDK_Control_R:
679
                dc->_message_context->clear();
680
                break;
681
            default:
682
                break;
683
        }
684
685
    default:
686
        break;
687
    }
688
689
    if (!ret) {
5717 by joncruz
Refactoring begining
690
        if (((SPEventContextClass *) eraser_parent_class)->root_handler) {
691
            ret = ((SPEventContextClass *) eraser_parent_class)->root_handler(event_context, event);
5526 by joncruz
Added missing eraser files
692
        }
693
    }
694
695
    return ret;
696
}
697
698
699
static void
700
clear_current(SPEraserContext *dc)
701
{
5593 by joncruz
Initial cut of touch-delete mode
702
    // reset bpath
5526 by joncruz
Added missing eraser files
703
    sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), NULL);
5593 by joncruz
Initial cut of touch-delete mode
704
705
    // reset curve
5609 by johanengelen
struct SPCurve => class SPCurve
706
    dc->currentcurve->reset();
707
    dc->cal1->reset();
708
    dc->cal2->reset();
5593 by joncruz
Initial cut of touch-delete mode
709
710
    // reset points
5526 by joncruz
Added missing eraser files
711
    dc->npoints = 0;
712
}
713
714
static void
715
set_to_accumulated(SPEraserContext *dc)
716
{
717
    SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop;
5529 by joncruz
Reduce undo history items when nothing is selected
718
    bool workDone = false;
5526 by joncruz
Added missing eraser files
719
5609 by johanengelen
struct SPCurve => class SPCurve
720
    if (!dc->accumulated->is_empty()) {
5526 by joncruz
Added missing eraser files
721
        if (!dc->repr) {
722
            /* Create object */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
723
            Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
5526 by joncruz
Added missing eraser files
724
            Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
725
726
            /* Set style */
6885 by Ted Gould
From trunk
727
            sp_desktop_apply_style_tool (desktop, repr, "/tools/eraser", false);
5526 by joncruz
Added missing eraser files
728
729
            dc->repr = repr;
730
731
            SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(dc->repr));
732
            Inkscape::GC::release(dc->repr);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
733
            item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
5526 by joncruz
Added missing eraser files
734
            item->updateRepr();
735
        }
7478 by speleo3
remove desktop-affine.h and refactor sp_desktop_dt2doc_* calls
736
        Geom::PathVector pathv = dc->accumulated->get_pathvector() * desktop->dt2doc();
6228 by johanengelen
* 2geomify polygon svg writing
737
        gchar *str = sp_svg_write_path(pathv);
5526 by joncruz
Added missing eraser files
738
        g_assert( str != NULL );
739
        dc->repr->setAttribute("d", str);
740
        g_free(str);
741
742
        if ( dc->repr ) {
5535 by joncruz
Refining eraser
743
            bool wasSelection = false;
5526 by joncruz
Added missing eraser files
744
            Inkscape::Selection *selection = sp_desktop_selection(desktop);
6885 by Ted Gould
From trunk
745
            Inkscape::Preferences *prefs = Inkscape::Preferences::get();
746
            
747
            gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
748
            Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
5535 by joncruz
Refining eraser
749
750
            SPItem* acid = SP_ITEM(desktop->doc()->getObjectByRepr(dc->repr));
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
751
            Geom::OptRect eraserBbox = acid->visualBounds();
6839 by cilix42
Next roud of NR ==> Geom conversion
752
            Geom::Rect bounds = (*eraserBbox) * desktop->doc2dt();
5535 by joncruz
Refining eraser
753
            std::vector<SPItem*> remainingItems;
754
            GSList* toWorkOn = 0;
755
            if (selection->isEmpty()) {
5593 by joncruz
Initial cut of touch-delete mode
756
                if ( eraserMode ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
757
                    toWorkOn = sp_desktop_document(desktop)->getItemsPartiallyInBox(desktop->dkey, bounds);
5593 by joncruz
Initial cut of touch-delete mode
758
                } else {
9012.1.255 by Josh Andler
Patch by Daniel_J for 522327
759
                    Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
760
                    toWorkOn = sp_desktop_document(desktop)->getItemsAtPoints(desktop->dkey, r->getPoints());
5593 by joncruz
Initial cut of touch-delete mode
761
                }
5535 by joncruz
Refining eraser
762
                toWorkOn = g_slist_remove( toWorkOn, acid );
763
            } else {
764
                toWorkOn = g_slist_copy(const_cast<GSList*>(selection->itemList()));
765
                wasSelection = true;
766
            }
767
768
            if ( g_slist_length(toWorkOn) > 0 ) {
5593 by joncruz
Initial cut of touch-delete mode
769
                if ( eraserMode ) {
770
                    for (GSList *i = toWorkOn ; i ; i = i->next ) {
771
                        SPItem *item = SP_ITEM(i->data);
772
                        if ( eraserMode ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
773
                            Geom::OptRect bbox = item->visualBounds();
5593 by joncruz
Initial cut of touch-delete mode
774
                            if (bbox && bbox->intersects(*eraserBbox)) {
775
                                Inkscape::XML::Node* dup = dc->repr->duplicate(xml_doc);
776
                                dc->repr->parent()->appendChild(dup);
777
                                Inkscape::GC::release(dup); // parent takes over
5526 by joncruz
Added missing eraser files
778
5593 by joncruz
Initial cut of touch-delete mode
779
                                selection->set(item);
780
                                selection->add(dup);
6633 by cilix42
Eliminate more of SP_ACTIVE_DESKTOP
781
                                sp_selected_path_diff_skip_undo(desktop);
5593 by joncruz
Initial cut of touch-delete mode
782
                                workDone = true; // TODO set this only if something was cut.
783
                                if ( !selection->isEmpty() ) {
784
                                    // If the item was not completely erased, track the new remainder.
785
                                    GSList *nowSel = g_slist_copy(const_cast<GSList *>(selection->itemList()));
786
                                    for (GSList const *i2 = nowSel ; i2 ; i2 = i2->next ) {
787
                                        remainingItems.push_back(SP_ITEM(i2->data));
788
                                    }
789
                                    g_slist_free(nowSel);
790
                                }
791
                            } else {
792
                                remainingItems.push_back(item);
5526 by joncruz
Added missing eraser files
793
                            }
794
                        }
5593 by joncruz
Initial cut of touch-delete mode
795
                    }
796
                } else {
797
                    for (GSList *i = toWorkOn ; i ; i = i->next ) {
798
                        sp_object_ref( SP_ITEM(i->data), 0 );
799
                    }
800
                    for (GSList *i = toWorkOn ; i ; i = i->next ) {
801
                        SPItem *item = SP_ITEM(i->data);
802
                        item->deleteObject(true);
803
                        sp_object_unref(item);
804
                        workDone = true;
5535 by joncruz
Refining eraser
805
                    }
806
                }
807
808
                g_slist_free(toWorkOn);
809
5593 by joncruz
Initial cut of touch-delete mode
810
                if ( !eraserMode ) {
6629 by cilix42
Get rid of a whole bunch of further instances of SP_ACTIVE_DESKTOP (where the desktop is readily available in the calling function)
811
                    //sp_selection_delete(desktop);
5593 by joncruz
Initial cut of touch-delete mode
812
                    remainingItems.clear();
813
                }
814
5535 by joncruz
Refining eraser
815
                selection->clear();
816
                if ( wasSelection ) {
817
                    if ( !remainingItems.empty() ) {
818
                        selection->add(remainingItems.begin(), remainingItems.end());
819
                    }
820
                }
5526 by joncruz
Added missing eraser files
821
            }
822
823
            // Remove the eraser stroke itself:
824
            sp_repr_unparent( dc->repr );
825
            dc->repr = 0;
826
        }
827
    } else {
828
        if (dc->repr) {
829
            sp_repr_unparent(dc->repr);
830
            dc->repr = 0;
831
        }
832
    }
833
5529 by joncruz
Reduce undo history items when nothing is selected
834
835
    if ( workDone ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
836
        DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ERASER, 
837
                           _("Draw eraser stroke"));
5529 by joncruz
Reduce undo history items when nothing is selected
838
    } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
839
        DocumentUndo::cancel(sp_desktop_document(desktop));
5529 by joncruz
Reduce undo history items when nothing is selected
840
    }
5526 by joncruz
Added missing eraser files
841
}
842
843
static void
844
add_cap(SPCurve *curve,
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
845
        Geom::Point const &pre, Geom::Point const &from,
846
        Geom::Point const &to, Geom::Point const &post,
5526 by joncruz
Added missing eraser files
847
        double rounding)
848
{
6954 by johanengelen
2geom eraser tool
849
    Geom::Point vel = rounding * Geom::rot90( to - from ) / sqrt(2.0);
850
    double mag = Geom::L2(vel);
5526 by joncruz
Added missing eraser files
851
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
852
    Geom::Point v_in = from - pre;
6954 by johanengelen
2geom eraser tool
853
    double mag_in = Geom::L2(v_in);
5526 by joncruz
Added missing eraser files
854
    if ( mag_in > ERASER_EPSILON ) {
855
        v_in = mag * v_in / mag_in;
856
    } else {
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
857
        v_in = Geom::Point(0, 0);
5526 by joncruz
Added missing eraser files
858
    }
859
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
860
    Geom::Point v_out = to - post;
6954 by johanengelen
2geom eraser tool
861
    double mag_out = Geom::L2(v_out);
5526 by joncruz
Added missing eraser files
862
    if ( mag_out > ERASER_EPSILON ) {
863
        v_out = mag * v_out / mag_out;
864
    } else {
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
865
        v_out = Geom::Point(0, 0);
5526 by joncruz
Added missing eraser files
866
    }
867
6954 by johanengelen
2geom eraser tool
868
    if ( Geom::L2(v_in) > ERASER_EPSILON || Geom::L2(v_out) > ERASER_EPSILON ) {
5609 by johanengelen
struct SPCurve => class SPCurve
869
        curve->curveto(from + v_in, to + v_out, to);
5526 by joncruz
Added missing eraser files
870
    }
871
}
872
873
static void
874
accumulate_eraser(SPEraserContext *dc)
875
{
5609 by johanengelen
struct SPCurve => class SPCurve
876
    if ( !dc->cal1->is_empty() && !dc->cal2->is_empty() ) {
877
        dc->accumulated->reset(); /*  Is this required ?? */
5636 by johanengelen
- try to use more forward declarations for less dependencies on display/curve.h
878
        SPCurve *rev_cal2 = dc->cal2->create_reverse();
5526 by joncruz
Added missing eraser files
879
6204 by johanengelen
change part of calligraphic/eraser code to 2geom.
880
        g_assert(dc->cal1->get_segment_count() > 0);
881
        g_assert(rev_cal2->get_segment_count() > 0);
882
        g_assert( ! dc->cal1->first_path()->closed() );
883
        g_assert( ! rev_cal2->first_path()->closed() );
884
885
        Geom::CubicBezier const * dc_cal1_firstseg  = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->first_segment() );
886
        Geom::CubicBezier const * rev_cal2_firstseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->first_segment() );
887
        Geom::CubicBezier const * dc_cal1_lastseg   = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->last_segment() );
888
        Geom::CubicBezier const * rev_cal2_lastseg  = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->last_segment() );
889
        g_assert( dc_cal1_firstseg );
890
        g_assert( rev_cal2_firstseg );
891
        g_assert( dc_cal1_lastseg );
892
        g_assert( rev_cal2_lastseg );
5526 by joncruz
Added missing eraser files
893
5609 by johanengelen
struct SPCurve => class SPCurve
894
        dc->accumulated->append(dc->cal1, FALSE);
5526 by joncruz
Added missing eraser files
895
6237 by johanengelen
fix calligraphy and erasertools bugs introduced by rev19197
896
        add_cap(dc->accumulated, (*dc_cal1_lastseg)[2], (*dc_cal1_lastseg)[3], (*rev_cal2_firstseg)[0], (*rev_cal2_firstseg)[1], dc->cap_rounding);
5526 by joncruz
Added missing eraser files
897
5609 by johanengelen
struct SPCurve => class SPCurve
898
        dc->accumulated->append(rev_cal2, TRUE);
5526 by joncruz
Added missing eraser files
899
6237 by johanengelen
fix calligraphy and erasertools bugs introduced by rev19197
900
        add_cap(dc->accumulated, (*rev_cal2_lastseg)[2], (*rev_cal2_lastseg)[3], (*dc_cal1_firstseg)[0], (*dc_cal1_firstseg)[1], dc->cap_rounding);
5526 by joncruz
Added missing eraser files
901
5609 by johanengelen
struct SPCurve => class SPCurve
902
        dc->accumulated->closepath();
903
904
        rev_cal2->unref();
905
906
        dc->cal1->reset();
907
        dc->cal2->reset();
5526 by joncruz
Added missing eraser files
908
    }
909
}
910
911
static double square(double const x)
912
{
913
    return x * x;
914
}
915
916
static void
917
fit_and_split(SPEraserContext *dc, gboolean release)
918
{
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
919
    SPDesktop *desktop = SP_EVENT_CONTEXT(dc)->desktop;
920
6839 by cilix42
Next roud of NR ==> Geom conversion
921
    double const tolerance_sq = square( desktop->w2d().descrim() * TOLERANCE_ERASER );
5526 by joncruz
Added missing eraser files
922
923
#ifdef ERASER_VERBOSE
924
    g_print("[F&S:R=%c]", release?'T':'F');
925
#endif
926
927
    if (!( dc->npoints > 0 && dc->npoints < SAMPLING_SIZE ))
928
        return; // just clicked
929
930
    if ( dc->npoints == SAMPLING_SIZE - 1 || release ) {
931
#define BEZIER_SIZE       4
932
#define BEZIER_MAX_BEZIERS  8
933
#define BEZIER_MAX_LENGTH ( BEZIER_SIZE * BEZIER_MAX_BEZIERS )
934
935
#ifdef ERASER_VERBOSE
936
        g_print("[F&S:#] dc->npoints:%d, release:%s\n",
937
                dc->npoints, release ? "TRUE" : "FALSE");
938
#endif
939
940
        /* Current eraser */
6301 by johanengelen
dyna-draw-context and eraser-context: replace check for empty path with 2geomified method of spcurve
941
        if ( dc->cal1->is_empty() || dc->cal2->is_empty() ) {
5526 by joncruz
Added missing eraser files
942
            /* dc->npoints > 0 */
943
            /* g_print("erasers(1|2) reset\n"); */
5609 by johanengelen
struct SPCurve => class SPCurve
944
            dc->cal1->reset();
945
            dc->cal2->reset();
5526 by joncruz
Added missing eraser files
946
5609 by johanengelen
struct SPCurve => class SPCurve
947
            dc->cal1->moveto(dc->point1[0]);
948
            dc->cal2->moveto(dc->point2[0]);
5526 by joncruz
Added missing eraser files
949
        }
950
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
951
        Geom::Point b1[BEZIER_MAX_LENGTH];
6983 by johanengelen
use 2geom bezier fitting (is copy of inkscape's)
952
        gint const nb1 = Geom::bezier_fit_cubic_r(b1, dc->point1, dc->npoints,
5526 by joncruz
Added missing eraser files
953
                                               tolerance_sq, BEZIER_MAX_BEZIERS);
954
        g_assert( nb1 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b1)) );
955
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
956
        Geom::Point b2[BEZIER_MAX_LENGTH];
6983 by johanengelen
use 2geom bezier fitting (is copy of inkscape's)
957
        gint const nb2 = Geom::bezier_fit_cubic_r(b2, dc->point2, dc->npoints,
5526 by joncruz
Added missing eraser files
958
                                               tolerance_sq, BEZIER_MAX_BEZIERS);
959
        g_assert( nb2 * BEZIER_SIZE <= gint(G_N_ELEMENTS(b2)) );
960
961
        if ( nb1 != -1 && nb2 != -1 ) {
962
            /* Fit and draw and reset state */
963
#ifdef ERASER_VERBOSE
964
            g_print("nb1:%d nb2:%d\n", nb1, nb2);
965
#endif
966
            /* CanvasShape */
967
            if (! release) {
5609 by johanengelen
struct SPCurve => class SPCurve
968
                dc->currentcurve->reset();
969
                dc->currentcurve->moveto(b1[0]);
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
970
                for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) {
5609 by johanengelen
struct SPCurve => class SPCurve
971
                    dc->currentcurve->curveto(bp1[1],
5526 by joncruz
Added missing eraser files
972
                                     bp1[2], bp1[3]);
973
                }
5609 by johanengelen
struct SPCurve => class SPCurve
974
                dc->currentcurve->lineto(b2[BEZIER_SIZE*(nb2-1) + 3]);
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
975
                for (Geom::Point *bp2 = b2 + BEZIER_SIZE * ( nb2 - 1 ); bp2 >= b2; bp2 -= BEZIER_SIZE) {
5609 by johanengelen
struct SPCurve => class SPCurve
976
                    dc->currentcurve->curveto(bp2[2], bp2[1], bp2[0]);
5526 by joncruz
Added missing eraser files
977
                }
978
                // FIXME: dc->segments is always NULL at this point??
979
                if (!dc->segments) { // first segment
980
                    add_cap(dc->currentcurve, b2[1], b2[0], b1[0], b1[1], dc->cap_rounding);
981
                }
5609 by johanengelen
struct SPCurve => class SPCurve
982
                dc->currentcurve->closepath();
5526 by joncruz
Added missing eraser files
983
                sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve);
984
            }
985
986
            /* Current eraser */
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
987
            for (Geom::Point *bp1 = b1; bp1 < b1 + BEZIER_SIZE * nb1; bp1 += BEZIER_SIZE) {
5609 by johanengelen
struct SPCurve => class SPCurve
988
                dc->cal1->curveto(bp1[1], bp1[2], bp1[3]);
5526 by joncruz
Added missing eraser files
989
            }
6835 by cilix42
Some NR::Point ==> Geom::Point replacements
990
            for (Geom::Point *bp2 = b2; bp2 < b2 + BEZIER_SIZE * nb2; bp2 += BEZIER_SIZE) {
5609 by johanengelen
struct SPCurve => class SPCurve
991
                dc->cal2->curveto(bp2[1], bp2[2], bp2[3]);
5526 by joncruz
Added missing eraser files
992
            }
993
        } else {
994
            /* fixme: ??? */
995
#ifdef ERASER_VERBOSE
996
            g_print("[fit_and_split] failed to fit-cubic.\n");
997
#endif
998
            draw_temporary_box(dc);
999
1000
            for (gint i = 1; i < dc->npoints; i++) {
5609 by johanengelen
struct SPCurve => class SPCurve
1001
                dc->cal1->lineto(dc->point1[i]);
5526 by joncruz
Added missing eraser files
1002
            }
1003
            for (gint i = 1; i < dc->npoints; i++) {
5609 by johanengelen
struct SPCurve => class SPCurve
1004
                dc->cal2->lineto(dc->point2[i]);
5526 by joncruz
Added missing eraser files
1005
            }
1006
        }
1007
1008
        /* Fit and draw and copy last point */
1009
#ifdef ERASER_VERBOSE
1010
        g_print("[%d]Yup\n", dc->npoints);
1011
#endif
1012
        if (!release) {
6885 by Ted Gould
From trunk
1013
            Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1014
            gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
5609 by johanengelen
struct SPCurve => class SPCurve
1015
            g_assert(!dc->currentcurve->is_empty());
5526 by joncruz
Added missing eraser files
1016
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
1017
            SPCanvasItem *cbp = sp_canvas_item_new(sp_desktop_sketch(desktop),
5526 by joncruz
Added missing eraser files
1018
                                                   SP_TYPE_CANVAS_BPATH,
1019
                                                   NULL);
5609 by johanengelen
struct SPCurve => class SPCurve
1020
            SPCurve *curve = dc->currentcurve->copy();
5526 by joncruz
Added missing eraser files
1021
            sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH (cbp), curve);
5609 by johanengelen
struct SPCurve => class SPCurve
1022
            curve->unref();
5526 by joncruz
Added missing eraser files
1023
6885 by Ted Gould
From trunk
1024
            guint32 fillColor = sp_desktop_get_color_tool (desktop, "/tools/eraser", true);
1025
            //guint32 strokeColor = sp_desktop_get_color_tool (desktop, "/tools/eraser", false);
1026
            double opacity = sp_desktop_get_master_opacity_tool (desktop, "/tools/eraser");
1027
            double fillOpacity = sp_desktop_get_opacity_tool (desktop, "/tools/eraser", true);
1028
            //double strokeOpacity = sp_desktop_get_opacity_tool (desktop, "/tools/eraser", false);
5526 by joncruz
Added missing eraser files
1029
            sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cbp), ((fillColor & 0xffffff00) | SP_COLOR_F_TO_U(opacity*fillOpacity)), SP_WIND_RULE_EVENODD);
1030
            //on second thougtht don't do stroke yet because we don't have stoke-width yet and because stoke appears between segments while drawing
1031
            //sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cbp), ((strokeColor & 0xffffff00) | SP_COLOR_F_TO_U(opacity*strokeOpacity)), 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
1032
            sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cbp), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
1033
            /* fixme: Cannot we cascade it to root more clearly? */
6621 by cilix42
Remove a few more instances of SP_ACTIVE_DESKTOP
1034
            g_signal_connect(G_OBJECT(cbp), "event", G_CALLBACK(sp_desktop_root_handler), desktop);
5526 by joncruz
Added missing eraser files
1035
1036
            dc->segments = g_slist_prepend(dc->segments, cbp);
5593 by joncruz
Initial cut of touch-delete mode
1037
1038
            if ( !eraserMode ) {
1039
                sp_canvas_item_hide(cbp);
1040
                sp_canvas_item_hide(dc->currentshape);
1041
            }
5526 by joncruz
Added missing eraser files
1042
        }
1043
1044
        dc->point1[0] = dc->point1[dc->npoints - 1];
1045
        dc->point2[0] = dc->point2[dc->npoints - 1];
1046
        dc->npoints = 1;
1047
    } else {
1048
        draw_temporary_box(dc);
1049
    }
1050
}
1051
1052
static void
1053
draw_temporary_box(SPEraserContext *dc)
1054
{
5609 by johanengelen
struct SPCurve => class SPCurve
1055
    dc->currentcurve->reset();
5526 by joncruz
Added missing eraser files
1056
5609 by johanengelen
struct SPCurve => class SPCurve
1057
    dc->currentcurve->moveto(dc->point1[dc->npoints-1]);
5526 by joncruz
Added missing eraser files
1058
    for (gint i = dc->npoints-2; i >= 0; i--) {
5609 by johanengelen
struct SPCurve => class SPCurve
1059
        dc->currentcurve->lineto(dc->point1[i]);
5526 by joncruz
Added missing eraser files
1060
    }
1061
    for (gint i = 0; i < dc->npoints; i++) {
5609 by johanengelen
struct SPCurve => class SPCurve
1062
        dc->currentcurve->lineto(dc->point2[i]);
5526 by joncruz
Added missing eraser files
1063
    }
1064
    if (dc->npoints >= 2) {
1065
        add_cap(dc->currentcurve, dc->point2[dc->npoints-2], dc->point2[dc->npoints-1], dc->point1[dc->npoints-1], dc->point1[dc->npoints-2], dc->cap_rounding);
1066
    }
1067
5609 by johanengelen
struct SPCurve => class SPCurve
1068
    dc->currentcurve->closepath();
5526 by joncruz
Added missing eraser files
1069
    sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(dc->currentshape), dc->currentcurve);
1070
}
1071
1072
/*
1073
  Local Variables:
1074
  mode:c++
1075
  c-file-style:"stroustrup"
1076
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1077
  indent-tabs-mode:nil
1078
  fill-column:99
1079
  End:
1080
*/
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1081
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :