Code

Connector tool: make connectors avoid the convex hull of shapes.
[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     default:
77     case 1: {
78         Piecewise<D2<SBasis> > pwd2_out;
79         bool closed_path = are_near(pwd2_in.firstValue(), pwd2_in.lastValue());
80         // split input path in pieces between points where deriv == vector
81         Piecewise<D2<SBasis> > deriv = derivative(pwd2_in);
82         std::vector<double> rts = roots(dot(deriv, rot90(extrude_vector.getVector())));
83         double portion_t = 0.;
84         for (unsigned i = 0; i < rts.size() ; ++i) {
85             Piecewise<D2<SBasis> > cut = portion(pwd2_in, portion_t, rts[i] );
86             portion_t = rts[i];
87             if (closed_path && i == 0) {
88                 // if the path is closed, skip the first cut and add it to the last cut later
89                 continue;
90             }
91             Piecewise<D2<SBasis> > part = cut;
92             part.continuousConcat(connector + cut.lastValue());
93             part.continuousConcat(reverse(cut) + extrude_vector.getVector());
94             part.continuousConcat(reverse(connector) + cut.firstValue());
95             pwd2_out.concat( part );
96         }
97         if (closed_path) {
98             Piecewise<D2<SBasis> > cut = portion(pwd2_in, portion_t, pwd2_in.domain().max() );
99             cut.continuousConcat(portion(pwd2_in, pwd2_in.domain().min(), rts[0] ));
100             Piecewise<D2<SBasis> > part = cut;
101             part.continuousConcat(connector + cut.lastValue());
102             part.continuousConcat(reverse(cut) + extrude_vector.getVector());
103             part.continuousConcat(reverse(connector) + cut.firstValue());
104             pwd2_out.concat( part );
105         } else if (!are_near(portion_t, pwd2_in.domain().max())) {
106             Piecewise<D2<SBasis> > cut = portion(pwd2_in, portion_t, pwd2_in.domain().max() );
107             Piecewise<D2<SBasis> > part = cut;
108             part.continuousConcat(connector + cut.lastValue());
109             part.continuousConcat(reverse(cut) + extrude_vector.getVector());
110             part.continuousConcat(reverse(connector) + cut.firstValue());
111             pwd2_out.concat( part );
112         }
113         return pwd2_out;
114     }
115     }
118 void
119 LPEExtrude::resetDefaults(SPItem * item)
121     Effect::resetDefaults(item);
123     using namespace Geom;
125     Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX);
126     if (bbox) {
127         Interval boundingbox_X = (*bbox)[Geom::X];
128         Interval boundingbox_Y = (*bbox)[Geom::Y];
129         extrude_vector.set_and_write_new_values( Geom::Point(boundingbox_X.middle(), boundingbox_Y.middle()), 
130                                                  (boundingbox_X.extent() + boundingbox_Y.extent())*Geom::Point(-0.05,0.2) );
131     }
134 } //namespace LivePathEffect
135 } /* namespace Inkscape */
137 /*
138   Local Variables:
139   mode:c++
140   c-file-style:"stroustrup"
141   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
142   indent-tabs-mode:nil
143   fill-column:99
144   End:
145 */
146 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :