~valavanisalex/ubuntu/oneiric/inkscape/inkscape_0.48.1-2ubuntu4

« back to all changes in this revision

Viewing changes to src/live_effects/effect.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook, Ted Gould, Kees Cook
  • Date: 2009-06-24 14:00:43 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20090624140043-07stp20mry48hqup
Tags: 0.47~pre0-0ubuntu1
* New upstream release

[ Ted Gould ]
* debian/control: Adding libgsl0 and removing version specifics on boost

[ Kees Cook ]
* debian/watch: updated to run uupdate and mangle pre-release versions.
* Dropped patches that have been taken upstream:
  - 01_mips
  - 02-poppler-0.8.3
  - 03-chinese-inkscape
  - 05_fix_latex_patch
  - 06_gcc-4.4
  - 07_cdr2svg
  - 08_skip-bad-utf-on-pdf-import
  - 09_gtk-clist
  - 10_belarussian
  - 11_libpng
  - 12_desktop
  - 13_slider
  - 100_svg_import_improvements
  - 102_sp_pattern_painter_free
  - 103_bitmap_type_print

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
 * Released under GNU GPL, read the file 'COPYING' for more information
7
7
 */
8
8
 
 
9
//#define LPE_ENABLE_TEST_EFFECTS
 
10
 
9
11
#include "live_effects/effect.h"
10
12
 
11
 
#include "display/display-forward.h"
 
13
#ifdef HAVE_CONFIG_H
 
14
# include "config.h"
 
15
#endif
 
16
 
12
17
#include "xml/node-event-vector.h"
13
18
#include "sp-object.h"
14
19
#include "attributes.h"
16
21
#include "desktop.h"
17
22
#include "inkscape.h"
18
23
#include "document.h"
 
24
#include "document-private.h"
 
25
#include "xml/document.h"
19
26
#include <glibmm/i18n.h>
 
27
#include "pen-context.h"
 
28
#include "tools-switch.h"
 
29
#include "message-stack.h"
 
30
#include "desktop.h"
 
31
#include "nodepath.h"
20
32
 
21
33
#include "live_effects/lpeobject.h"
22
34
#include "live_effects/parameter/parameter.h"
23
35
#include <glibmm/ustring.h>
24
 
#include "live_effects/n-art-bpath-2geom.h"
25
36
#include "display/curve.h"
26
37
#include <gtkmm.h>
27
38
 
29
40
 
30
41
#include <2geom/sbasis-to-bezier.h>
31
42
#include <2geom/matrix.h>
32
 
 
 
43
#include <2geom/pathvector.h>
33
44
 
34
45
// include effects:
35
 
#include "live_effects/lpe-skeletalstrokes.h"
36
 
#include "live_effects/lpe-pathalongpath.h"
37
 
#include "live_effects/lpe-slant.h"
 
46
#include "live_effects/lpe-patternalongpath.h"
 
47
#include "live_effects/lpe-bendpath.h"
 
48
#include "live_effects/lpe-sketch.h"
 
49
#include "live_effects/lpe-vonkoch.h"
 
50
#include "live_effects/lpe-knot.h"
 
51
#include "live_effects/lpe-rough-hatches.h"
 
52
#include "live_effects/lpe-dynastroke.h"
38
53
#include "live_effects/lpe-test-doEffect-stack.h"
39
54
#include "live_effects/lpe-gears.h"
40
55
#include "live_effects/lpe-curvestitch.h"
 
56
#include "live_effects/lpe-circle_with_radius.h"
 
57
#include "live_effects/lpe-perspective_path.h"
 
58
#include "live_effects/lpe-spiro.h"
 
59
#include "live_effects/lpe-lattice.h"
 
60
#include "live_effects/lpe-envelope.h"
 
61
#include "live_effects/lpe-constructgrid.h"
 
62
#include "live_effects/lpe-perp_bisector.h"
 
63
#include "live_effects/lpe-tangent_to_curve.h"
 
64
#include "live_effects/lpe-mirror_symmetry.h"
 
65
#include "live_effects/lpe-circle_3pts.h"
 
66
#include "live_effects/lpe-angle_bisector.h"
 
67
#include "live_effects/lpe-parallel.h"
 
68
#include "live_effects/lpe-copy_rotate.h"
 
69
#include "live_effects/lpe-offset.h"
 
70
#include "live_effects/lpe-ruler.h"
 
71
#include "live_effects/lpe-boolops.h"
 
72
#include "live_effects/lpe-interpolate.h"
 
73
#include "live_effects/lpe-text_label.h"
 
74
#include "live_effects/lpe-path_length.h"
 
75
#include "live_effects/lpe-line_segment.h"
 
76
#include "live_effects/lpe-recursiveskeleton.h"
41
77
 
42
 
#include "nodepath.h"
43
78
 
44
79
namespace Inkscape {
45
80
 
46
81
namespace LivePathEffect {
47
82
 
48
 
const Util::EnumData<EffectType> LPETypeData[INVALID_LPE] = {
49
 
    // {constant defined in effect.h, N_("name of your effect"), "name of your effect in SVG"}
50
 
    {PATH_ALONG_PATH,       N_("Bend Path"),             "bend_path"},
51
 
    {SKELETAL_STROKES,      N_("Pattern Along Path"),    "skeletal"},
 
83
const Util::EnumData<EffectType> LPETypeData[] = {
 
84
    // {constant defined in effect-enum.h, N_("name of your effect"), "name of your effect in SVG"}
52
85
#ifdef LPE_ENABLE_TEST_EFFECTS
53
 
    {SLANT,                 N_("Slant"),                 "slant"},
54
 
    {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),   "doeffectstacktest"},
 
86
    {DOEFFECTSTACK_TEST,    N_("doEffect stack test"),     "doeffectstacktest"},
 
87
    {ANGLE_BISECTOR,        N_("Angle bisector"),          "angle_bisector"},
 
88
    // TRANSLATORS: boolean operations
 
89
    {BOOLOPS,               N_("Boolops"),                 "boolops"},
 
90
    {CIRCLE_WITH_RADIUS,    N_("Circle (by center and radius)"),   "circle_with_radius"},
 
91
    {CIRCLE_3PTS,           N_("Circle by 3 points"),      "circle_3pts"},
 
92
    {DYNASTROKE,            N_("Dynamic stroke"),          "dynastroke"},
 
93
    {LATTICE,               N_("Lattice Deformation"),     "lattice"},
 
94
    {LINE_SEGMENT,          N_("Line Segment"),            "line_segment"},
 
95
    {MIRROR_SYMMETRY,       N_("Mirror symmetry"),         "mirror_symmetry"},
 
96
    {OFFSET,                N_("Offset"),                  "offset"},
 
97
    {PARALLEL,              N_("Parallel"),                "parallel"},
 
98
    {PATH_LENGTH,           N_("Path length"),             "path_length"},
 
99
    {PERP_BISECTOR,         N_("Perpendicular bisector"),  "perp_bisector"},
 
100
    {PERSPECTIVE_PATH,      N_("Perspective path"),        "perspective_path"},
 
101
    {COPY_ROTATE,           N_("Rotate copies"),           "copy_rotate"},
 
102
    {RECURSIVE_SKELETON,    N_("Recursive skeleton"),      "recursive_skeleton"},
 
103
    {TANGENT_TO_CURVE,      N_("Tangent to curve"),        "tangent_to_curve"},
 
104
    {TEXT_LABEL,            N_("Text label"),              "text_label"},
55
105
#endif
56
 
    {GEARS,                 N_("Gears"),                 "gears"},
57
 
    {CURVE_STITCH,          N_("Stitch Sub-Paths"),       "curvestitching"},
 
106
/* 0.46 */
 
107
    {BEND_PATH,             N_("Bend"),                     "bend_path"},
 
108
    {GEARS,                 N_("Gears"),                   "gears"},
 
109
    {PATTERN_ALONG_PATH,    N_("Pattern Along Path"),      "skeletal"},   // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG
 
110
    {CURVE_STITCH,          N_("Stitch Sub-Paths"),        "curvestitching"},
 
111
/* 0.47 */
 
112
    {VONKOCH,               N_("VonKoch"),                 "vonkoch"},
 
113
    {KNOT,                  N_("Knot"),                    "knot"},
 
114
    {CONSTRUCT_GRID,        N_("Construct grid"),          "construct_grid"},
 
115
    {SPIRO,                 N_("Spiro spline"),            "spiro"},
 
116
    {ENVELOPE,              N_("Envelope Deformation"),    "envelope"},
 
117
    {INTERPOLATE,           N_("Interpolate Sub-Paths"),   "interpolate"},
 
118
    {ROUGH_HATCHES,         N_("Hatches (rough)"),         "rough_hatches"},
 
119
    {SKETCH,                N_("Sketch"),                  "sketch"},
 
120
    {RULER,                 N_("Ruler"),                   "ruler"},
58
121
};
59
 
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, INVALID_LPE);
 
122
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
 
123
 
 
124
int
 
125
Effect::acceptsNumClicks(EffectType type) {
 
126
    switch (type) {
 
127
        case INVALID_LPE: return -1; // in case we want to distinguish between invalid LPE and valid ones that expect zero clicks
 
128
        case ANGLE_BISECTOR: return 3;
 
129
        case CIRCLE_3PTS: return 3;
 
130
        case CIRCLE_WITH_RADIUS: return 2;
 
131
        case LINE_SEGMENT: return 2;
 
132
        case PERP_BISECTOR: return 2;
 
133
        default: return 0;
 
134
    }
 
135
}
60
136
 
61
137
Effect*
62
138
Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
63
139
{
64
140
    Effect* neweffect = NULL;
65
141
    switch (lpenr) {
66
 
        case SKELETAL_STROKES:
67
 
            neweffect = (Effect*) new LPESkeletalStrokes(lpeobj);
68
 
            break;
69
 
        case PATH_ALONG_PATH:
70
 
            neweffect = (Effect*) new LPEPathAlongPath(lpeobj);
71
 
            break;
72
 
#ifdef LPE_ENABLE_TEST_EFFECTS
73
 
            case SLANT:
74
 
            neweffect = (Effect*) new LPESlant(lpeobj);
75
 
            break;
76
 
        case DOEFFECTSTACK_TEST:
77
 
            neweffect = (Effect*) new LPEdoEffectStackTest(lpeobj);
78
 
            break;
79
 
#endif
 
142
        case PATTERN_ALONG_PATH:
 
143
            neweffect = static_cast<Effect*> ( new LPEPatternAlongPath(lpeobj) );
 
144
            break;
 
145
        case BEND_PATH:
 
146
            neweffect = static_cast<Effect*> ( new LPEBendPath(lpeobj) );
 
147
            break;
 
148
        case SKETCH:
 
149
            neweffect = static_cast<Effect*> ( new LPESketch(lpeobj) );
 
150
            break;
 
151
        case ROUGH_HATCHES:
 
152
            neweffect = static_cast<Effect*> ( new LPERoughHatches(lpeobj) );
 
153
            break;
 
154
        case VONKOCH:
 
155
            neweffect = static_cast<Effect*> ( new LPEVonKoch(lpeobj) );
 
156
            break;
 
157
        case KNOT:
 
158
            neweffect = static_cast<Effect*> ( new LPEKnot(lpeobj) );
 
159
            break;
80
160
        case GEARS:
81
 
            neweffect = (Effect*) new LPEGears(lpeobj);
 
161
            neweffect = static_cast<Effect*> ( new LPEGears(lpeobj) );
82
162
            break;
83
163
        case CURVE_STITCH:
84
 
            neweffect = (Effect*) new LPECurveStitch(lpeobj);
 
164
            neweffect = static_cast<Effect*> ( new LPECurveStitch(lpeobj) );
 
165
            break;
 
166
        case LATTICE:
 
167
            neweffect = static_cast<Effect*> ( new LPELattice(lpeobj) );
 
168
            break;
 
169
        case ENVELOPE:
 
170
            neweffect = static_cast<Effect*> ( new LPEEnvelope(lpeobj) );
 
171
            break;
 
172
        case CIRCLE_WITH_RADIUS:
 
173
            neweffect = static_cast<Effect*> ( new LPECircleWithRadius(lpeobj) );
 
174
            break;
 
175
        case PERSPECTIVE_PATH:
 
176
            neweffect = static_cast<Effect*> ( new LPEPerspectivePath(lpeobj) );
 
177
            break;
 
178
        case SPIRO:
 
179
            neweffect = static_cast<Effect*> ( new LPESpiro(lpeobj) );
 
180
            break;
 
181
        case CONSTRUCT_GRID:
 
182
            neweffect = static_cast<Effect*> ( new LPEConstructGrid(lpeobj) );
 
183
            break;
 
184
        case PERP_BISECTOR:
 
185
            neweffect = static_cast<Effect*> ( new LPEPerpBisector(lpeobj) );
 
186
            break;
 
187
        case TANGENT_TO_CURVE:
 
188
            neweffect = static_cast<Effect*> ( new LPETangentToCurve(lpeobj) );
 
189
            break;
 
190
        case MIRROR_SYMMETRY:
 
191
            neweffect = static_cast<Effect*> ( new LPEMirrorSymmetry(lpeobj) );
 
192
            break;
 
193
        case CIRCLE_3PTS:
 
194
            neweffect = static_cast<Effect*> ( new LPECircle3Pts(lpeobj) );
 
195
            break;
 
196
        case ANGLE_BISECTOR:
 
197
            neweffect = static_cast<Effect*> ( new LPEAngleBisector(lpeobj) );
 
198
            break;
 
199
        case PARALLEL:
 
200
            neweffect = static_cast<Effect*> ( new LPEParallel(lpeobj) );
 
201
            break;
 
202
        case COPY_ROTATE:
 
203
            neweffect = static_cast<Effect*> ( new LPECopyRotate(lpeobj) );
 
204
            break;
 
205
        case OFFSET:
 
206
            neweffect = static_cast<Effect*> ( new LPEOffset(lpeobj) );
 
207
            break;
 
208
        case RULER:
 
209
            neweffect = static_cast<Effect*> ( new LPERuler(lpeobj) );
 
210
            break;
 
211
        case BOOLOPS:
 
212
            neweffect = static_cast<Effect*> ( new LPEBoolops(lpeobj) );
 
213
            break;
 
214
        case INTERPOLATE:
 
215
            neweffect = static_cast<Effect*> ( new LPEInterpolate(lpeobj) );
 
216
            break;
 
217
        case TEXT_LABEL:
 
218
            neweffect = static_cast<Effect*> ( new LPETextLabel(lpeobj) );
 
219
            break;
 
220
        case PATH_LENGTH:
 
221
            neweffect = static_cast<Effect*> ( new LPEPathLength(lpeobj) );
 
222
            break;
 
223
        case LINE_SEGMENT:
 
224
            neweffect = static_cast<Effect*> ( new LPELineSegment(lpeobj) );
 
225
            break;
 
226
        case DOEFFECTSTACK_TEST:
 
227
            neweffect = static_cast<Effect*> ( new LPEdoEffectStackTest(lpeobj) );
 
228
            break;
 
229
        case DYNASTROKE:
 
230
            neweffect = static_cast<Effect*> ( new LPEDynastroke(lpeobj) );
 
231
            break;
 
232
        case RECURSIVE_SKELETON:
 
233
            neweffect = static_cast<Effect*> ( new LPERecursiveSkeleton(lpeobj) );
85
234
            break;
86
235
        default:
87
236
            g_warning("LivePathEffect::Effect::New   called with invalid patheffect type (%d)", lpenr);
96
245
    return neweffect;
97
246
}
98
247
 
 
248
void
 
249
Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item)
 
250
{
 
251
    // Path effect definition
 
252
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
 
253
    Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
 
254
    repr->setAttribute("effect", name);
 
255
 
 
256
    SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
 
257
    const gchar * repr_id = repr->attribute("id");
 
258
    Inkscape::GC::release(repr);
 
259
 
 
260
    gchar *href = g_strdup_printf("#%s", repr_id);
 
261
    sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true);
 
262
    g_free(href);
 
263
}
 
264
 
 
265
void
 
266
Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
 
267
{
 
268
    createAndApply(LPETypeConverter.get_key(type).c_str(), doc, item);
 
269
}
 
270
 
99
271
Effect::Effect(LivePathEffectObject *lpeobject)
 
272
    : oncanvasedit_it(0),
 
273
      is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
 
274
      show_orig_path(false),
 
275
      lpeobj(lpeobject),
 
276
      concatenate_before_pwd2(false),
 
277
      provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
 
278
      is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden
100
279
{
101
 
    lpeobj = lpeobject;
102
 
    oncanvasedit_it = 0;
 
280
    registerParameter( dynamic_cast<Parameter *>(&is_visible) );
103
281
}
104
282
 
105
283
Effect::~Effect()
109
287
Glib::ustring
110
288
Effect::getName()
111
289
{
112
 
    if (lpeobj->effecttype_set && lpeobj->effecttype < INVALID_LPE)
 
290
    if (lpeobj->effecttype_set && LPETypeConverter.is_valid_id(lpeobj->effecttype) )
113
291
        return Glib::ustring( _(LPETypeConverter.get_label(lpeobj->effecttype).c_str()) );
114
292
    else
115
293
        return Glib::ustring( _("No effect") );
116
294
}
117
295
 
 
296
EffectType
 
297
Effect::effectType() {
 
298
    return lpeobj->effecttype;
 
299
}
 
300
 
 
301
/**
 
302
 * Is performed a single time when the effect is freshly applied to a path
 
303
 */
 
304
void
 
305
Effect::doOnApply (SPLPEItem */*lpeitem*/)
 
306
{
 
307
}
 
308
 
 
309
/**
 
310
 * Is performed each time before the effect is updated.
 
311
 */
 
312
void
 
313
Effect::doBeforeEffect (SPLPEItem */*lpeitem*/)
 
314
{
 
315
    //Do nothing for simple effects
 
316
}
 
317
 
 
318
/**
 
319
 * Effects can have a parameter path set before they are applied by accepting a nonzero number of
 
320
 * mouse clicks. This method activates the pen context, which waits for the specified number of
 
321
 * clicks. Override Effect::acceptsNumClicks() to return the number of expected mouse clicks.
 
322
 */
 
323
void
 
324
Effect::doAcceptPathPreparations(SPLPEItem *lpeitem)
 
325
{
 
326
    // switch to pen context
 
327
    SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop?
 
328
    if (!tools_isactive(desktop, TOOLS_FREEHAND_PEN)) {
 
329
        tools_switch(desktop, TOOLS_FREEHAND_PEN);
 
330
    }
 
331
 
 
332
    SPEventContext *ec = desktop->event_context;
 
333
    SPPenContext *pc = SP_PEN_CONTEXT(ec);
 
334
    pc->expecting_clicks_for_LPE = this->acceptsNumClicks();
 
335
    pc->waiting_LPE = this;
 
336
    pc->waiting_item = lpeitem;
 
337
    pc->polylines_only = true;
 
338
 
 
339
    ec->desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE,
 
340
        g_strdup_printf(_("Please specify a parameter path for the LPE '%s' with %d mouse clicks"),
 
341
                        getName().c_str(), acceptsNumClicks()));
 
342
}
 
343
 
 
344
void
 
345
Effect::writeParamsToSVG() {
 
346
    std::vector<Inkscape::LivePathEffect::Parameter *>::iterator p;
 
347
    for (p = param_vector.begin(); p != param_vector.end(); ++p) {
 
348
        (*p)->write_to_SVG();
 
349
    }
 
350
}
 
351
 
 
352
/**
 
353
 * If the effect expects a path parameter (specified by a number of mouse clicks) before it is
 
354
 * applied, this is the method that processes the resulting path. Override it to customize it for
 
355
 * your LPE. But don't forget to call the parent method so that is_ready is set to true!
 
356
 */
 
357
void
 
358
Effect::acceptParamPath (SPPath */*param_path*/) {
 
359
    setReady();
 
360
}
 
361
 
118
362
/*
119
363
 *  Here be the doEffect function chain:
120
364
 */
121
365
void
122
366
Effect::doEffect (SPCurve * curve)
123
367
{
124
 
    NArtBpath *new_bpath = doEffect_nartbpath(SP_CURVE_BPATH(curve));
125
 
 
126
 
    if (new_bpath && new_bpath != SP_CURVE_BPATH(curve)) {        // FIXME, add function to SPCurve to change bpath? or a copy function?
127
 
        if (curve->_bpath) {
128
 
            g_free(curve->_bpath); //delete old bpath
129
 
        }
130
 
        curve->_bpath = new_bpath;
131
 
    }
132
 
}
133
 
 
134
 
NArtBpath *
135
 
Effect::doEffect_nartbpath (NArtBpath * path_in)
136
 
{
137
 
    try {
138
 
        std::vector<Geom::Path> orig_pathv = BPath_to_2GeomPath(path_in);
139
 
 
140
 
        std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
141
 
 
142
 
        NArtBpath *new_bpath = BPath_from_2GeomPath(result_pathv);
143
 
 
144
 
        return new_bpath;
145
 
    }
146
 
    catch (std::exception & e) {
147
 
        g_warning("Exception during LPE %s execution. \n %s", getName().c_str(), e.what());
148
 
        SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
149
 
            _("An exception occurred during execution of the Path Effect.") );
150
 
 
151
 
        NArtBpath *path_out;
152
 
 
153
 
        unsigned ret = 0;
154
 
        while ( path_in[ret].code != NR_END ) {
155
 
            ++ret;
156
 
        }
157
 
        unsigned len = ++ret;
158
 
 
159
 
        path_out = g_new(NArtBpath, len);
160
 
        memcpy(path_out, path_in, len * sizeof(NArtBpath));
161
 
        return path_out;
162
 
    }
 
368
    std::vector<Geom::Path> orig_pathv = curve->get_pathvector();
 
369
 
 
370
    std::vector<Geom::Path> result_pathv = doEffect_path(orig_pathv);
 
371
 
 
372
    curve->set_pathvector(result_pathv);
163
373
}
164
374
 
165
375
std::vector<Geom::Path>
166
 
Effect::doEffect_path (std::vector<Geom::Path> & path_in)
 
376
Effect::doEffect_path (std::vector<Geom::Path> const & path_in)
167
377
{
168
 
    Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
 
378
    std::vector<Geom::Path> path_out;
169
379
 
170
 
    for (unsigned int i=0; i < path_in.size(); i++) {
171
 
        pwd2_in.concat( path_in[i].toPwSb() );
 
380
    if ( !concatenate_before_pwd2 ) {
 
381
        // default behavior
 
382
        for (unsigned int i=0; i < path_in.size(); i++) {
 
383
            Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb();
 
384
            Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
 
385
            std::vector<Geom::Path> path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
 
386
            // add the output path vector to the already accumulated vector:
 
387
            for (unsigned int j=0; j < path.size(); j++) {
 
388
                path_out.push_back(path[j]);
 
389
            }
 
390
        }
 
391
    } else {
 
392
      // concatenate the path into possibly discontinuous pwd2
 
393
        Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in;
 
394
        for (unsigned int i=0; i < path_in.size(); i++) {
 
395
            pwd2_in.concat( path_in[i].toPwSb() );
 
396
        }
 
397
        Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
 
398
        path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
172
399
    }
173
400
 
174
 
    Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
175
 
 
176
 
    std::vector<Geom::Path> path_out = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
177
 
 
178
401
    return path_out;
179
402
}
180
403
 
181
404
Geom::Piecewise<Geom::D2<Geom::SBasis> >
182
 
Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > & pwd2_in)
 
405
Effect::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
183
406
{
184
407
    g_warning("Effect has no doEffect implementation");
185
408
    return pwd2_in;
195
418
        const gchar * value = repr->attribute(key);
196
419
        if (value) {
197
420
            bool accepted = param->param_readSVGValue(value);
198
 
            if (!accepted) { 
 
421
            if (!accepted) {
199
422
                g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key);
200
423
            }
201
424
        } else {
215
438
    if (param) {
216
439
        if (new_value) {
217
440
            bool accepted = param->param_readSVGValue(new_value);
218
 
            if (!accepted) { 
 
441
            if (!accepted) {
219
442
                g_warning("Effect::setParameter - '%s' not accepted for %s", new_value, key);
220
443
            }
221
444
        } else {
231
454
    param_vector.push_back(param);
232
455
}
233
456
 
234
 
/**
235
 
* This *creates* a new widget, management of deletion should be done by the caller
236
 
*/
 
457
// TODO: should we provide a way to alter the handle's appearance?
 
458
void
 
459
Effect::registerKnotHolderHandle(KnotHolderEntity* entity, const char* descr)
 
460
{
 
461
    kh_entity_vector.push_back(std::make_pair(entity, descr));
 
462
}
 
463
 
 
464
/**
 
465
 * Add all registered LPE knotholder handles to the knotholder
 
466
 */
 
467
void
 
468
Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
 
469
    using namespace Inkscape::LivePathEffect;
 
470
 
 
471
    // add handles provided by the effect itself
 
472
    addKnotHolderEntities(knotholder, desktop, item);
 
473
 
 
474
    // add handles provided by the effect's parameters (if any)
 
475
    for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
 
476
        (*p)->addKnotHolderEntities(knotholder, desktop, item);
 
477
    }
 
478
}
 
479
 
 
480
void
 
481
Effect::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
 
482
    // TODO: The entities in kh_entity_vector are already instantiated during the call
 
483
    //       to registerKnotHolderHandle(), but they are recreated here. Also, we must not
 
484
    //       delete them when the knotholder is destroyed, whence the clumsy function
 
485
    //       isDeletable(). If we could create entities of different classes dynamically,
 
486
    //       this would be much nicer. How to do this?
 
487
    std::vector<std::pair<KnotHolderEntity*, const char*> >::iterator i;
 
488
    for (i = kh_entity_vector.begin(); i != kh_entity_vector.end(); ++i) {
 
489
        KnotHolderEntity *entity = i->first;
 
490
        const char *descr = i->second;
 
491
 
 
492
        entity->create(desktop, item, knotholder, descr);
 
493
        knotholder->add(entity);
 
494
    }
 
495
}
 
496
 
 
497
/**
 
498
 * Return a vector of PathVectors which contain all helperpaths that should be drawn by the effect.
 
499
 * This is the function called by external code like SPLPEItem.
 
500
 */
 
501
std::vector<Geom::PathVector>
 
502
Effect::getHelperPaths(SPLPEItem *lpeitem)
 
503
{
 
504
    std::vector<Geom::PathVector> hp_vec;
 
505
 
 
506
    if (!SP_IS_SHAPE(lpeitem)) {
 
507
        g_print ("How to handle helperpaths for non-shapes?\n"); // non-shapes are for example SPGroups.
 
508
        return hp_vec;
 
509
    }
 
510
 
 
511
    // TODO: we can probably optimize this by using a lot more references
 
512
    //       rather than copying PathVectors all over the place
 
513
    if (show_orig_path) {
 
514
        // add original path to helperpaths
 
515
        SPCurve* curve = sp_shape_get_curve (SP_SHAPE(lpeitem));
 
516
        hp_vec.push_back(curve->get_pathvector());
 
517
    }
 
518
 
 
519
    // add other helperpaths provided by the effect itself
 
520
    addCanvasIndicators(lpeitem, hp_vec);
 
521
 
 
522
    // add helperpaths provided by the effect's parameters
 
523
    for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
 
524
        (*p)->addCanvasIndicators(lpeitem, hp_vec);
 
525
    }
 
526
 
 
527
    return hp_vec;
 
528
}
 
529
 
 
530
/**
 
531
 * Add possible canvas indicators (i.e., helperpaths other than the original path) to \a hp_vec
 
532
 * This function should be overwritten by derived effects if they want to provide their own helperpaths.
 
533
 */
 
534
void
 
535
Effect::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/)
 
536
{
 
537
}
 
538
 
 
539
 
 
540
/**
 
541
 * This *creates* a new widget, management of deletion should be done by the caller
 
542
 */
237
543
Gtk::Widget *
238
544
Effect::newWidget(Gtk::Tooltips * tooltips)
239
545
{
295
601
Parameter *
296
602
Effect::getNextOncanvasEditableParam()
297
603
{
 
604
    if (param_vector.size() == 0) // no parameters
 
605
        return NULL;
 
606
 
298
607
    oncanvasedit_it++;
299
 
    if (oncanvasedit_it == static_cast<int>(param_vector.size())) {
 
608
    if (oncanvasedit_it >= static_cast<int>(param_vector.size())) {
300
609
        oncanvasedit_it = 0;
301
610
    }
302
611
    int old_it = oncanvasedit_it;
339
648
void
340
649
Effect::resetDefaults(SPItem * /*item*/)
341
650
{
342
 
    // do nothing for simple effects
 
651
    std::vector<Inkscape::LivePathEffect::Parameter *>::iterator p;
 
652
    for (p = param_vector.begin(); p != param_vector.end(); ++p) {
 
653
        (*p)->param_set_default();
 
654
        (*p)->write_to_SVG();
 
655
    }
343
656
}
344
657
 
345
658
void
346
659
Effect::setup_nodepath(Inkscape::NodePath::Path *np)
347
660
{
348
 
    np->show_helperpath = true;
349
661
    np->helperpath_rgba = 0xff0000ff;
350
662
    np->helperpath_width = 1.0;
351
663
}
360
672
    }
361
673
}
362
674
 
 
675
// TODO: take _all_ parameters into account, not only PointParams
 
676
bool
 
677
Effect::providesKnotholder()
 
678
{
 
679
    // does the effect actively provide any knotholder entities of its own?
 
680
    if (kh_entity_vector.size() > 0)
 
681
        return true;
 
682
 
 
683
    // otherwise: are there any parameters that have knotholderentities?
 
684
    for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
 
685
        if ((*p)->providesKnotHolderEntities()) {
 
686
            return true;
 
687
        }
 
688
    }
 
689
 
 
690
    return false;
 
691
}
 
692
 
363
693
} /* namespace LivePathEffect */
364
694
 
365
695
} /* namespace Inkscape */