Code

Merging in the changes from the 0.47 release branch. Also updating version numbers...
[inkscape.git] / src / live_effects / lpe-extrude.cpp
1 #define INKSCAPE_LPE_EXTRUDE_CPP
2 /** \file
3  * @brief LPE effect for extruding paths (making them "3D").
4  *
5  */
6 /* Authors:
7  *   Johan Engelen <j.b.c.engelen@utwente.nl>
8  *
9  * Copyright (C) 2009 Authors
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #include "live_effects/lpe-extrude.h"
16 #include <2geom/path.h>
17 #include <2geom/piecewise.h>
18 #include <2geom/transforms.h>
20 namespace Inkscape {
21 namespace LivePathEffect {
23 LPEExtrude::LPEExtrude(LivePathEffectObject *lpeobject) :
24     Effect(lpeobject),
25     extrude_vector(_("Direction"), _("Defines the direction and magnitude of the extrusion"), "extrude_vector", &wr, this, Geom::Point(-10,10))
26 {
27     show_orig_path = true;
28     concatenate_before_pwd2 = false;
30     registerParameter( dynamic_cast<Parameter *>(&extrude_vector) );
31 }
33 LPEExtrude::~LPEExtrude()
34 {
36 }
39 Geom::Piecewise<Geom::D2<Geom::SBasis> >
40 LPEExtrude::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
41 {
42     using namespace Geom;
44     // generate connecting lines (the 'sides' of the extrusion)
45     Path path(Point(0.,0.));
46     path.appendNew<Geom::LineSegment>( extrude_vector.getVector() );
47     Piecewise<D2<SBasis> > connector = path.toPwSb();
49     switch( 1 ) {
50     case 0: {
51         Piecewise<D2<SBasis> > pwd2_out = pwd2_in;
52         // generate extrusion bottom: (just a copy of original path, displaced a bit)
53         pwd2_out.concat( pwd2_in + extrude_vector.getVector() );
55         // connecting lines should be put at start and end of path if it is not closed
56         // it is not possible to check whether a piecewise<T> path is closed, 
57         // so we check whether start and end are close
58         if ( ! are_near(pwd2_in.firstValue(), pwd2_in.lastValue()) ) {
59             pwd2_out.concat( connector + pwd2_in.firstValue() );
60             pwd2_out.concat( connector + pwd2_in.lastValue() );
61         }
62         // connecting lines should be put at cusps
63         Piecewise<D2<SBasis> > deriv = derivative(pwd2_in);
64         std::vector<double> cusps; // = roots(deriv);
65         for (unsigned i = 0; i < cusps.size() ; ++i) {
66             pwd2_out.concat( connector + pwd2_in.valueAt(cusps[i]) );
67         }
68         // connecting lines should be put where the tangent of the path equals the extrude_vector in direction
69         std::vector<double> rts = roots(dot(deriv, rot90(extrude_vector.getVector())));
70         for (unsigned i = 0; i < rts.size() ; ++i) {
71             pwd2_out.concat( connector + pwd2_in.valueAt(rts[i]) );
72         }
73         return pwd2_out;
74     }
76     case 1: {
77         Piecewise<D2<SBasis> > pwd2_out;
78         bool closed_path = are_near(pwd2_in.firstValue(), pwd2_in.lastValue());
79         // split input path in pieces between points where deriv == vector
80         Piecewise<D2<SBasis> > deriv = derivative(pwd2_in);
81         std::vector<double> rts = roots(dot(deriv, rot90(extrude_vector.getVector())));
82         double portion_t = 0.;
83         for (unsigned i = 0; i < rts.size() ; ++i) {
84             Piecewise<D2<SBasis> > cut = portion(pwd2_in, portion_t, rts[i] );
85             portion_t = rts[i];
86             if (closed_path && i == 0) {
87                 // if the path is closed, skip the first cut and add it to the last cut later
88                 continue;
89             }
90             Piecewise<D2<SBasis> > part = cut;
91             part.continuousConcat(connector + cut.lastValue());
92             part.continuousConcat(reverse(cut) + extrude_vector.getVector());
93             part.continuousConcat(reverse(connector) + cut.firstValue());
94             pwd2_out.concat( part );
95         }
96         if (closed_path) {
97             Piecewise<D2<SBasis> > cut = portion(pwd2_in, portion_t, pwd2_in.domain().max() );
98             cut.continuousConcat(portion(pwd2_in, pwd2_in.domain().min(), rts[0] ));
99             Piecewise<D2<SBasis> > part = cut;
100             part.continuousConcat(connector + cut.lastValue());
101             part.continuousConcat(reverse(cut) + extrude_vector.getVector());
102             part.continuousConcat(reverse(connector) + cut.firstValue());
103             pwd2_out.concat( part );
104         } else if (!are_near(portion_t, pwd2_in.domain().max())) {
105             Piecewise<D2<SBasis> > cut = portion(pwd2_in, portion_t, pwd2_in.domain().max() );
106             Piecewise<D2<SBasis> > part = cut;
107             part.continuousConcat(connector + cut.lastValue());
108             part.continuousConcat(reverse(cut) + extrude_vector.getVector());
109             part.continuousConcat(reverse(connector) + cut.firstValue());
110             pwd2_out.concat( part );
111         }
112         return pwd2_out;
113     }
114     }
117 void
118 LPEExtrude::resetDefaults(SPItem * item)
120     Effect::resetDefaults(item);
122     using namespace Geom;
124     Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);
125     if (bbox) {
126         Interval boundingbox_X = (*bbox)[Geom::X];
127         Interval boundingbox_Y = (*bbox)[Geom::Y];
128         extrude_vector.set_and_write_new_values( Geom::Point(boundingbox_X.middle(), boundingbox_Y.middle()), 
129                                                  (boundingbox_X.extent() + boundingbox_Y.extent())*Geom::Point(-0.05,0.2) );
130     }
133 } //namespace LivePathEffect
134 } /* namespace Inkscape */
136 /*
137   Local Variables:
138   mode:c++
139   c-file-style:"stroustrup"
140   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
141   indent-tabs-mode:nil
142   fill-column:99
143   End:
144 */
145 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :