Code

0268cec33c6192c01c16b117791ee5d5915d02f9
[inkscape.git] / src / live_effects / lpe-curvestitch.cpp
1 #define INKSCAPE_LPE_CURVESTITCH_CPP
2 /** \file
3  * SVG <skeleton> implementation, used as an example for a base starting class
4  * when implementing new LivePathEffects.
5  *
6  */
7 /*
8  * Authors:
9  *   Johan Engelen
10 *
11 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #include "live_effects/lpe-curvestitch.h"
17 #include "display/curve.h"
18 #include <libnr/n-art-bpath.h>
19 #include "sp-item.h"
20 #include "sp-path.h"
21 #include "live_effects/n-art-bpath-2geom.h"
23 #include <2geom/path.h>
24 #include <2geom/piecewise.h>
25 #include <2geom/sbasis.h>
26 #include <2geom/sbasis-geometric.h>
27 #include <2geom/bezier-to-sbasis.h>
28 #include <2geom/sbasis-to-bezier.h>
29 #include <2geom/d2.h>
30 #include <2geom/matrix.h>
33 #include "ui/widget/scalar.h"
34 #include "libnr/nr-values.h"
36 namespace Inkscape {
37 namespace LivePathEffect {
39 using namespace Geom;
41 LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) :
42     Effect(lpeobject),
43     strokepath(_("Stroke path"), _("The path that will be used as stitch."), "strokepath", &wr, this, "M0,0 L1,0"),
44     nrofpaths(_("Nr of paths"), _("The number of paths that will be generated."), "count", &wr, this, 5),
45     startpoint_variation(_("Startpoint variation"), _("..."), "startpoint_variation", &wr, this, 0),
46     endpoint_variation(_("Endpoint variation"), _("..."), "endpoint_variation", &wr, this, 0),
47     prop_scale(_("Scale width"), _("Scaling of the width of the stroke path"), "prop_scale", &wr, this, 1),
48     scale_y_rel(_("Scale width relative"), _("Scale the width of the stroke path relative to its length"), "scale_y_rel", &wr, this, false)
49 {
50     registerParameter( dynamic_cast<Parameter *>(&nrofpaths) );
51     registerParameter( dynamic_cast<Parameter *>(&startpoint_variation) );
52     registerParameter( dynamic_cast<Parameter *>(&endpoint_variation) );
53     registerParameter( dynamic_cast<Parameter *>(&strokepath) );
54     registerParameter( dynamic_cast<Parameter *>(&prop_scale) );
55     registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) );
57     nrofpaths.param_make_integer();
58     nrofpaths.param_set_range(2, NR_HUGE);
60     prop_scale.param_set_digits(3);
61     prop_scale.param_set_increments(0.01, 0.10);
62 }
64 LPECurveStitch::~LPECurveStitch()
65 {
67 }
69 std::vector<Geom::Path>
70 LPECurveStitch::doEffect (std::vector<Geom::Path> & path_in)
71 {
72     if (path_in.size() >= 2) {
73         startpoint_variation.resetRandomizer();
74         endpoint_variation.resetRandomizer();
76         D2<Piecewise<SBasis> > stroke = make_cuts_independant(strokepath);
77         Interval bndsStroke = bounds_exact(stroke[0]);
78         gdouble scaling = bndsStroke.max() - bndsStroke.min();
79         Interval bndsStrokeY = bounds_exact(stroke[1]);
80         Point stroke_origin(bndsStroke.min(), (bndsStrokeY.max()+bndsStrokeY.min())/2);
82         std::vector<Geom::Path> path_out (nrofpaths);
84         // do this for all permutations if there are more than 2 paths? realllly cool!
85         Piecewise<D2<SBasis> > A = arc_length_parametrization(Piecewise<D2<SBasis> >(path_in[0].toPwSb()),2,.1);
86         Piecewise<D2<SBasis> > B = arc_length_parametrization(Piecewise<D2<SBasis> >(path_in[1].toPwSb()),2,.1);
87         Interval bndsA = A.domain();
88         Interval bndsB = B.domain();
89         gdouble incrementA = (bndsA.max()-bndsA.min()) / (nrofpaths-1);
90         gdouble incrementB = (bndsB.max()-bndsB.min()) / (nrofpaths-1);
91         gdouble tA = bndsA.min();
92         gdouble tB = bndsB.min();
93         for (int i = 0; i < nrofpaths; i++) {
94             Point start = A(tA);
95             Point end = B(tB);
96             if (startpoint_variation.get_value() != 0)
97                 start = start + startpoint_variation * (end - start);
98             if (endpoint_variation.get_value() != 0)
99                 end = end + endpoint_variation * (end - start);
100     
101             gdouble scaling_y = 1.0;
102             if (scale_y_rel.get_value()) {
103                 scaling_y = (L2(end-start)/scaling)*prop_scale;
104             } else {
105                 scaling_y = prop_scale;
106             }
108             Matrix transform;
109             transform.setXAxis( (end-start) / scaling );
110             transform.setYAxis( rot90(unit_vector(end-start)) * scaling_y);
111             transform.setTranslation( start );
112             Piecewise<D2<SBasis> > pwd2_out = (strokepath-stroke_origin) * transform;
113             // add stuff to one big pw<d2<sbasis> > and then outside the loop convert to path?
114             std::vector<Path> result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE);
115             path_out[i] = result[0];
116             tA += incrementA;
117             tB += incrementB;
118         }
120         return path_out;
121     } else {
122         return path_in;
123     }
126 void
127 LPECurveStitch::resetDefaults(SPItem * item)
129     if (!SP_IS_PATH(item)) return;
131     using namespace Geom;
133     // set the stroke path to run horizontally in the middle of the bounding box of the original path
134     Piecewise<D2<SBasis> > pwd2;
135     std::vector<Path> temppath = SVGD_to_2GeomPath( SP_OBJECT_REPR(item)->attribute("inkscape:original-d"));
136     for (unsigned int i=0; i < temppath.size(); i++) {
137         pwd2.concat( temppath[i].toPwSb() );
138     }
140     D2<Piecewise<SBasis> > d2pw = make_cuts_independant(pwd2);
141     Interval bndsX = bounds_exact(d2pw[0]);
142     Interval bndsY = bounds_exact(d2pw[1]);
143     Point start(bndsX.min(), (bndsY.max()+bndsY.min())/2);
144     Point end(bndsX.max(), (bndsY.max()+bndsY.min())/2);
146     Geom::Path path;
147     path.start( start );
148     path.appendNew<Geom::LineSegment>( end );
149     strokepath.param_set_and_write_new_value( path.toPwSb() );
152 } //namespace LivePathEffect
153 } /* namespace Inkscape */
155 /*
156   Local Variables:
157   mode:c++
158   c-file-style:"stroustrup"
159   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
160   indent-tabs-mode:nil
161   fill-column:99
162   End:
163 */
164 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :