Code

move undo commits closer to the UI
[inkscape.git] / src / live_effects / lpe-perspective_path.cpp
1 #define INKSCAPE_LPE_PERSPECTIVE_PATH_CPP
2 /** \file
3  * LPE <perspective_path> implementation, used as an example for a base starting class
4  * when implementing new LivePathEffects.
5  *
6  * In vi, three global search-and-replaces will let you rename everything
7  * in this and the .h file:
8  *
9  *   :%s/PERSPECTIVE_PATH/YOURNAME/g
10  *   :%s/PerspectivePath/Yourname/g
11  *   :%s/perspective_path/yourname/g
12  */
13 /*
14  * Authors:
15  *   Johan Engelen
16  *   Maximilian Albert
17  *
18  * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
19  * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>
20  *
21  * Released under GNU GPL, read the file 'COPYING' for more information
22  */
24 #include "persp3d.h"
25 //#include "transf_mat_3x4.h"
26 #include "document.h"
28 #include "live_effects/lpe-perspective_path.h"
29 #include "sp-item-group.h"
31 #include "inkscape.h"
33 #include <2geom/path.h>
35 namespace Inkscape {
36 namespace LivePathEffect {
38 namespace PP {
40 class KnotHolderEntityOffset : public KnotHolderEntity
41 {
42 public:
43     virtual bool isLPEParam() { return true; }
45     virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state);
46     virtual NR::Point knot_get();
47 };
49 } // namespace PP
51 LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) :
52     Effect(lpeobject),
53     // initialise your parameters here:
54     scalex(_("Scale x"), _("Scale factor in x direction"), "scalex", &wr, this, 1.0),
55     scaley(_("Scale y"), _("Scale factor in y direction"), "scaley", &wr, this, 1.0),
56     offsetx(_("Offset x"), _("Offset in x direction"), "offsetx", &wr, this, 0.0),
57     offsety(_("Offset y"), _("Offset in y direction"), "offsety", &wr, this, 0.0),
58     uses_plane_xy(_("Uses XY plane?"), _("If true, put the path on the left side of an imaginary box, otherwise on the right side"), "uses_plane_xy", &wr, this, true)
59 {
60     // register all your parameters here, so Inkscape knows which parameters this effect has:
61     registerParameter( dynamic_cast<Parameter *>(&scalex) );
62     registerParameter( dynamic_cast<Parameter *>(&scaley) );
63     registerParameter( dynamic_cast<Parameter *>(&offsetx) );
64     registerParameter( dynamic_cast<Parameter *>(&offsety) );
65     registerParameter( dynamic_cast<Parameter *>(&uses_plane_xy) );
67     registerKnotHolderHandle(new PP::KnotHolderEntityOffset(), _("Adjust the origin"));
69     concatenate_before_pwd2 = true; // don't split the path into its subpaths
71     Persp3D *persp = persp3d_document_first_persp(inkscape_active_document());
73     Proj::TransfMat3x4 pmat = persp->tmat;
75     pmat.copy_tmat(tmat);
76 }
78 LPEPerspectivePath::~LPEPerspectivePath()
79 {
81 }
83 void
84 LPEPerspectivePath::doBeforeEffect (SPLPEItem *lpeitem)
85 {
86     original_bbox(lpeitem, true);
87 }
89 Geom::Piecewise<Geom::D2<Geom::SBasis> >
90 LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
91 {
92     using namespace Geom;
94     Piecewise<D2<SBasis> > path_a_pw = pwd2_in;
96     // FIXME: the minus sign is there because the SVG coordinate system goes down;
97     //        remove this once we have unified coordinate systems
98     path_a_pw = path_a_pw + Geom::Point(offsetx, -offsety);
100     D2<Piecewise<SBasis> > B = make_cuts_independent(path_a_pw);
101     Piecewise<SBasis> preimage[4];
103     //Geom::Point orig = Geom::Point(bounds_X.min(), bounds_Y.middle());
104     //orig = Geom::Point(orig[X], sp_document_height(inkscape_active_document()) - orig[Y]);
106     //double offset = uses_plane_xy ? boundingbox_X.extent() : 0.0;
108     orig = Point(uses_plane_xy ? boundingbox_X.max() : boundingbox_X.min(), boundingbox_Y.middle());
110     /**
111     g_print ("Orig: (%8.2f, %8.2f)\n", orig[X], orig[Y]);
113     g_print ("B[1] - orig[1]: %8.2f\n", (B[1] - orig[1])[0].valueAt(0));
114     g_print ("B[0] - orig[0]: %8.2f\n", (B[0] - orig[0])[0].valueAt(0));
115     **/
117     if (uses_plane_xy) {
118         preimage[0] =  (-B[0] + orig[0]) * scalex / 200.0;
119         preimage[1] =  ( B[1] - orig[1]) * scaley / 400.0;
120         preimage[2] =  B[0] - B[0]; // hack!
121     } else {
122         preimage[0] =  B[0] - B[0]; // hack!
123         preimage[1] =  (B[1] - orig[1]) * scaley / 400.0;
124         preimage[2] =  (B[0] - orig[0]) * scalex / 200.0;
125     }
127     /* set perspective origin to first point of path */
128     tmat[0][3] = orig[0];
129     tmat[1][3] = orig[1];
131     /**
132     g_print ("preimage[1]: %8.2f\n", preimage[1][0].valueAt(0));
133     g_print ("preimage[2]: %8.2f\n", preimage[2][0].valueAt(0));
134     **/
136     Piecewise<SBasis> res[3];
137     for (int j = 0; j < 3; ++j) {
138         res[j] =
139               preimage[0] * tmat[j][0]
140             + preimage[1] * tmat[j][1]
141             + preimage[2] * tmat[j][2]
142             +               tmat[j][3];
143     }
144     D2<Piecewise<SBasis> > result(divide(res[0],res[2], 3),
145                                   divide(res[1],res[2], 3));
147     Piecewise<D2<SBasis> > output = sectionize(result);
149     return output;
152 namespace PP {
154 // TODO: make this more generic
155 static LPEPerspectivePath *
156 get_effect(SPItem *item)
158     Effect *effect = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item));
159     if (effect->effectType() != PERSPECTIVE_PATH) {
160         g_print ("Warning: Effect is not of type LPEPerspectivePath!\n");
161         return NULL;
162     }
163     return static_cast<LPEPerspectivePath *>(effect);
166 void
167 KnotHolderEntityOffset::knot_set(NR::Point const &p, NR::Point const &origin, guint /*state*/)
169     using namespace Geom;
170  
171     LPEPerspectivePath* lpe = get_effect(item);
173     lpe->offsetx.param_set_value((p - origin)[NR::X]);
174     lpe->offsety.param_set_value(-(p - origin)[NR::Y]); // additional minus sign is due to coordinate system flipping
176     // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
177     sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
180 NR::Point
181 KnotHolderEntityOffset::knot_get()
183     LPEPerspectivePath* lpe = get_effect(item);
184     return lpe->orig + Geom::Point(lpe->offsetx, -lpe->offsety);
187 } // namespace PP
189 } //namespace LivePathEffect
190 } /* namespace Inkscape */
192 /*
193   Local Variables:
194   mode:c++
195   c-file-style:"stroustrup"
196   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
197   indent-tabs-mode:nil
198   fill-column:99
199   End:
200 */
201 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :