summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
authorLiam P. White <inkscapebronyat-signgmaildotcom>2014-06-06 16:12:41 +0000
committerLiam P. White <inkscapebronyat-signgmaildotcom>2014-06-06 16:12:41 +0000
commitfa06e2deb21ba6d362ebd7d34b0ae59a614b5e3c (patch)
tree84bb8f6071e403525d68a04c6589eb633176e774 /src/live_effects
parentUpdate to trunk (r13379) (diff)
parentupdate clang format spec for latest clangformat version (diff)
downloadinkscape-fa06e2deb21ba6d362ebd7d34b0ae59a614b5e3c.tar.gz
inkscape-fa06e2deb21ba6d362ebd7d34b0ae59a614b5e3c.zip
Update to experimental r13389
(bzr r13090.1.81)
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/CMakeLists.txt3
-rw-r--r--src/live_effects/Makefile_insert4
-rw-r--r--src/live_effects/effect-enum.h1
-rw-r--r--src/live_effects/effect.cpp6
-rw-r--r--src/live_effects/lpe-envelope-perspective.cpp414
-rw-r--r--src/live_effects/lpe-envelope-perspective.h76
6 files changed, 503 insertions, 1 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index c7547ded3..c3ce31cfc 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -15,6 +15,7 @@ set(live_effects_SRC
lpe-dynastroke.cpp
lpe-ellipse-5pts.cpp
lpe-envelope.cpp
+ lpe-envelope-perspective.cpp
lpe-extrude.cpp
lpe-fill-between-many.cpp
lpe-fill-between-strokes.cpp
@@ -43,6 +44,7 @@ set(live_effects_SRC
lpe-bspline.cpp
lpe-text_label.cpp
lpe-vonkoch.cpp
+ lpe-envelope-perspective.cpp
lpegroupbbox.cpp
lpeobject-reference.cpp
lpeobject.cpp
@@ -113,6 +115,7 @@ set(live_effects_SRC
lpe-bspline.h
lpe-text_label.h
lpe-vonkoch.h
+ lpe-envelope-perspective.h
lpegroupbbox.h
lpeobject-reference.h
lpeobject.h
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index 922a4a966..3d474d00c 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -104,4 +104,6 @@ ink_common_sources += \
live_effects/lpe-jointype.cpp \
live_effects/lpe-jointype.h \
live_effects/lpe-taperstroke.cpp \
- live_effects/lpe-taperstroke.h
+ live_effects/lpe-taperstroke.h \
+ live_effects/lpe-envelope-perspective.cpp \
+ live_effects/lpe-envelope-perspective.h
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index 82ce36225..92f35fc72 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -60,6 +60,7 @@ enum EffectType {
BOUNDING_BOX,
JOIN_TYPE,
TAPER_STROKE,
+ ENVELOPE_PERSPECTIVE,
INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan)
};
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index 3c13ee9a9..4157e14d7 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -57,6 +57,7 @@
#include "live_effects/lpe-bounding-box.h"
#include "live_effects/lpe-jointype.h"
#include "live_effects/lpe-taperstroke.h"
+#include "live_effects/lpe-envelope-perspective.h"
#include "xml/node-event-vector.h"
#include "sp-object.h"
@@ -144,6 +145,7 @@ const Util::EnumData<EffectType> LPETypeData[] = {
/* 0.91 */
{SIMPLIFY, N_("Simplify"), "simplify"},
{LATTICE2, N_("Lattice Deformation 2"), "lattice2"},
+ {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"},
};
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
@@ -290,12 +292,16 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
break;
case TAPER_STROKE:
neweffect = static_cast<Effect*> ( new LPETaperStroke(lpeobj) );
+ break;
case SIMPLIFY:
neweffect = static_cast<Effect*> ( new LPESimplify(lpeobj) );
break;
case LATTICE2:
neweffect = static_cast<Effect*> ( new LPELattice2(lpeobj) );
break;
+ case ENVELOPE_PERSPECTIVE:
+ neweffect = static_cast<Effect*> ( new LPEEnvelopePerspective(lpeobj) );
+ break;
default:
g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);
neweffect = NULL;
diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp
new file mode 100644
index 000000000..bfd6e56d7
--- /dev/null
+++ b/src/live_effects/lpe-envelope-perspective.cpp
@@ -0,0 +1,414 @@
+/** \file
+ * LPE <envelope-perspective> implementation
+
+ */
+/*
+ * Authors:
+ * Jabiertxof Code migration from python extensions envelope and perspective
+ * Aaron Spike, aaron@ekips.org from envelope and perspective phyton code
+ * Dmitry Platonov, shadowjack@mail.ru, 2006 perspective approach & math
+ * Jose Hevia (freon) Transform algorithm from envelope
+ *
+ * Copyright (C) 2007-2014 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/lpe-envelope-perspective.h"
+#include "helper/geom.h"
+#include "display/curve.h"
+#include "svg/svg.h"
+#include <gtkmm/separator.h>
+#include <gtkmm/stock.h>
+#include <tools-switch.h>
+#include <gsl/gsl_linalg.h>
+#include "desktop.h"
+
+using namespace Geom;
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPEEnvelopePerspective::LPEEnvelopePerspective(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject),
+ // initialise your parameters here:
+ perspective(_("Perspective"), _("Perspective"), "Perspective", &wr, this, false),
+ Up_Left_Point(_("Top Left:"), _("Top Left - Ctrl+Alt+Click to reset"), "Up_Left_Point", &wr, this),
+ Up_Right_Point(_("Top Right:"), _("Top Right - Ctrl+Alt+Click to reset"), "Up_Right_Point", &wr, this),
+ Down_Left_Point(_("Down Left:"), _("Down Left - Ctrl+Alt+Click to reset"), "Down_Left_Point", &wr, this),
+ Down_Right_Point(_("Down Right:"), _("Down Right - Ctrl+Alt+Click to reset"), "Down_Right_Point", &wr, this)
+{
+ // register all your parameters here, so Inkscape knows which parameters this effect has:
+ registerParameter( dynamic_cast<Parameter *>(&perspective));
+ registerParameter( dynamic_cast<Parameter *>(&Up_Left_Point) );
+ registerParameter( dynamic_cast<Parameter *>(&Up_Right_Point) );
+ registerParameter( dynamic_cast<Parameter *>(&Down_Left_Point) );
+ registerParameter( dynamic_cast<Parameter *>(&Down_Right_Point) );
+}
+
+LPEEnvelopePerspective::~LPEEnvelopePerspective()
+{
+}
+
+void LPEEnvelopePerspective::doEffect(SPCurve *curve) {
+ using Geom::X;
+ using Geom::Y;
+ double projmatrix[3][3];
+ if(perspective){
+ std::vector<Geom::Point> handles(4);
+ handles[0] = Down_Left_Point;
+ handles[1] = Up_Left_Point;
+ handles[2] = Up_Right_Point;
+ handles[3] = Down_Right_Point;
+ std::vector<Geom::Point> sourceHandles(4);
+ sourceHandles[0] = Geom::Point(boundingbox_X.min(), boundingbox_Y.max());
+ sourceHandles[1] = Geom::Point(boundingbox_X.min(), boundingbox_Y.min());
+ sourceHandles[2] = Geom::Point(boundingbox_X.max(), boundingbox_Y.min());
+ sourceHandles[3] = Geom::Point(boundingbox_X.max(), boundingbox_Y.max());
+ double solmatrix[8][8] = {{0}};
+ double free_term[8] = {0};
+ double gslSolmatrix[64];
+ for(unsigned int i = 0; i < 4; ++i){
+ solmatrix[i][0] = sourceHandles[i][X];
+ solmatrix[i][1] = sourceHandles[i][Y];
+ solmatrix[i][2] = 1;
+ solmatrix[i][6] = -handles[i][X] * sourceHandles[i][X];
+ solmatrix[i][7] = -handles[i][X] * sourceHandles[i][Y];
+ solmatrix[i+4][3] = sourceHandles[i][X];
+ solmatrix[i+4][4] = sourceHandles[i][Y];
+ solmatrix[i+4][5] = 1;
+ solmatrix[i+4][6] = -handles[i][Y] * sourceHandles[i][X];
+ solmatrix[i+4][7] = -handles[i][Y] * sourceHandles[i][Y];
+ free_term[i] = handles[i][X];
+ free_term[i+4] = handles[i][Y];
+ }
+ int h = 0;
+ for( int i = 0; i < 8; i++ ) {
+ for( int j = 0; j < 8; j++ ) {
+ gslSolmatrix[h] = solmatrix[i][j];
+ h++;
+ }
+ }
+ //this is get by this page:
+ //http://www.gnu.org/software/gsl/manual/html_node/Linear-Algebra-Examples.html#Linear-Algebra-Examples
+ gsl_matrix_view m = gsl_matrix_view_array (gslSolmatrix, 8, 8);
+ gsl_vector_view b = gsl_vector_view_array (free_term, 8);
+ gsl_vector *x = gsl_vector_alloc (8);
+ int s;
+ gsl_permutation * p = gsl_permutation_alloc (8);
+ gsl_linalg_LU_decomp (&m.matrix, p, &s);
+ gsl_linalg_LU_solve (&m.matrix, p, &b.vector, x);
+ h = 0;
+ for( int i = 0; i < 3; i++ ) {
+ for( int j = 0; j < 3; j++ ) {
+ if(h==8){
+ projmatrix[2][2] = 1.0;
+ continue;
+ }
+ projmatrix[i][j] = gsl_vector_get(x, h);
+ h++;
+ }
+ }
+ gsl_permutation_free (p);
+ gsl_vector_free (x);
+ }
+ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector());
+ curve->reset();
+ Geom::CubicBezier const *cubic = NULL;
+ Geom::Point pointAt1(0, 0);
+ Geom::Point pointAt2(0, 0);
+ Geom::Point pointAt3(0, 0);
+ for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
+ //Si está vacío...
+ if (path_it->empty())
+ continue;
+ //Itreadores
+ SPCurve *nCurve = new SPCurve();
+ Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve
+ Geom::Path::const_iterator curve_it2 =
+ ++(path_it->begin()); // outgoing curve
+ Geom::Path::const_iterator curve_endit =
+ path_it->end_default(); // this determines when the loop has to stop
+
+ if (path_it->closed()) {
+ // if the path is closed, maybe we have to stop a bit earlier because the
+ // closing line segment has zerolength.
+ const Geom::Curve &closingline =
+ path_it->back_closed(); // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
+ }
+ if(perspective){
+ nCurve->moveto(project_point(curve_it1->initialPoint(),projmatrix));
+ }else{
+ nCurve->moveto(project_point(curve_it1->initialPoint()));
+ }
+ while (curve_it2 != curve_endit) {
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
+ if (cubic) {
+ pointAt1 = (*cubic)[1];
+ pointAt2 = (*cubic)[2];
+ } else {
+ pointAt1 = curve_it1->initialPoint();
+ pointAt2 = curve_it1->finalPoint();
+ }
+ pointAt3 = curve_it1->finalPoint();
+ if(perspective){
+ pointAt1 = project_point(pointAt1,projmatrix);
+ pointAt2 = project_point(pointAt2,projmatrix);
+ pointAt3 = project_point(pointAt3,projmatrix);
+ }else{
+ pointAt1 = project_point(pointAt1);
+ pointAt2 = project_point(pointAt2);
+ pointAt3 = project_point(pointAt3);
+ }
+ nCurve->curveto(pointAt1, pointAt2, pointAt3);
+ ++curve_it1;
+ ++curve_it2;
+ }
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
+ if (cubic) {
+ pointAt1 = (*cubic)[1];
+ pointAt2 = (*cubic)[2];
+ } else {
+ pointAt1 = curve_it1->initialPoint();
+ pointAt2 = curve_it1->finalPoint();
+ }
+ pointAt3 = curve_it1->finalPoint();
+ if(perspective){
+ pointAt1 = project_point(pointAt1,projmatrix);
+ pointAt2 = project_point(pointAt2,projmatrix);
+ pointAt3 = project_point(pointAt3,projmatrix);
+ }else{
+ pointAt1 = project_point(pointAt1);
+ pointAt2 = project_point(pointAt2);
+ pointAt3 = project_point(pointAt3);
+ }
+ nCurve->curveto(pointAt1, pointAt2, pointAt3);
+ if(perspective){
+ nCurve->move_endpoints(project_point(path_it->begin()->initialPoint(),projmatrix), pointAt3);
+ }else{
+ nCurve->move_endpoints(project_point(path_it->begin()->initialPoint()), pointAt3);
+ }
+ //y cerramos la curva
+ if (path_it->closed()) {
+ nCurve->closepath_current();
+ }
+ curve->append(nCurve, false);
+ nCurve->reset();
+ delete nCurve;
+ }
+}
+
+Geom::Point
+LPEEnvelopePerspective::project_point(Geom::Point p){
+ double width = boundingbox_X.extent();
+ double height = boundingbox_Y.extent();
+ Geom::Coord xratio = abs(Geom::Point(boundingbox_X.min(), boundingbox_Y.max())[X]-p[X])/width;
+ Geom::Coord yratio = abs(Geom::Point(boundingbox_X.min(), boundingbox_Y.max())[Y]-p[Y])/height;
+ Geom::Line* horiz = new Geom::Line();
+ Geom::Line* vert = new Geom::Line();
+ vert->setPoints (pointAtRatio(yratio,Down_Left_Point,Up_Left_Point),pointAtRatio(yratio,Down_Right_Point,Up_Right_Point));
+ horiz->setPoints (pointAtRatio(xratio,Down_Left_Point,Down_Right_Point),pointAtRatio(xratio,Up_Left_Point,Up_Right_Point));
+
+ OptCrossing crossPoint = intersection(*horiz,*vert);
+ if(crossPoint){
+ return horiz->pointAt(Geom::Coord(crossPoint->ta));
+ }else{
+ return p;
+ }
+}
+
+Geom::Point
+LPEEnvelopePerspective::project_point(Geom::Point p, double m[][3]){
+ Geom::Coord x = p[0];
+ Geom::Coord y = p[1];
+ return Geom::Point(
+ Geom::Coord((x*m[0][0] + y*m[0][1] + m[0][2])/(x*m[2][0]+y*m[2][1]+m[2][2])),
+ Geom::Coord((x*m[1][0] + y*m[1][1] + m[1][2])/(x*m[2][0]+y*m[2][1]+m[2][2])));
+}
+
+Geom::Point
+LPEEnvelopePerspective::pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B){
+ Geom::Coord x = A[X] + (ratio * (B[X]-A[X]));
+ Geom::Coord y = A[Y]+ (ratio * (B[Y]-A[Y]));
+ return Point(x, y);
+}
+
+
+Gtk::Widget *
+LPEEnvelopePerspective::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might still be pointing to this widget.
+ Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(6);
+ Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
+
+ Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR));
+ resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPEEnvelopePerspective::resetGrid));
+ resetButton->set_size_request(140,45);
+ vbox->pack_start(*hbox, true,true,2);
+ hbox->pack_start(*resetButton, false, false,2);
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ Gtk::HBox * hboxUpHandles = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::HBox * hboxDownHandles = Gtk::manage(new Gtk::HBox(false,0));
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter * param = *it;
+ Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ if (param->param_key == "Up_Left_Point" ||
+ param->param_key == "Up_Right_Point" ||
+ param->param_key == "Down_Left_Point" ||
+ param->param_key == "Down_Right_Point")
+ {
+ Gtk::HBox * pointParameter = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector< Gtk::Widget* > childList = pointParameter->get_children();
+ Gtk::HBox * pointParameterHBox = dynamic_cast<Gtk::HBox *>(childList[0]);
+ std::vector< Gtk::Widget* > childList2 = pointParameterHBox->get_children();
+ pointParameterHBox->remove(childList2[0][0]);
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ if(param->param_key == "Up_Left_Point"){
+ Gtk::Label* handles = Gtk::manage(new Gtk::Label(Glib::ustring(_("Handles:")),Gtk::ALIGN_START));
+ vbox->pack_start(*handles, false, false, 2);
+ hboxUpHandles->pack_start(*widg, true, true, 2);
+ hboxUpHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ }else if(param->param_key == "Up_Right_Point"){
+ hboxUpHandles->pack_start(*widg, true, true, 2);
+ }else if(param->param_key == "Down_Left_Point"){
+ hboxDownHandles->pack_start(*widg, true, true, 2);
+ hboxDownHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ }else{
+ hboxDownHandles->pack_start(*widg, true, true, 2);
+ }
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }else{
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+ }
+
+ ++it;
+ }
+ vbox->pack_start(*hboxUpHandles,true, true, 2);
+ Gtk::HBox * hboxMiddle = Gtk::manage(new Gtk::HBox(true,2));
+ hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET);
+ vbox->pack_start(*hboxMiddle, false, true, 2);
+ vbox->pack_start(*hboxDownHandles, true, true, 2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void
+LPEEnvelopePerspective::doBeforeEffect (SPLPEItem const* lpeitem)
+{
+ original_bbox(lpeitem);
+ setDefaults();
+}
+
+void
+LPEEnvelopePerspective::setDefaults()
+{
+ Geom::Point Up_Left(boundingbox_X.min(), boundingbox_Y.min());
+ Geom::Point Up_Right(boundingbox_X.max(), boundingbox_Y.min());
+ Geom::Point Down_Left(boundingbox_X.min(), boundingbox_Y.max());
+ Geom::Point Down_Right(boundingbox_X.max(), boundingbox_Y.max());
+
+ Up_Left_Point.param_update_default(Up_Left);
+ Up_Right_Point.param_update_default(Up_Right);
+ Down_Right_Point.param_update_default(Down_Right);
+ Down_Left_Point.param_update_default(Down_Left);
+}
+
+void
+LPEEnvelopePerspective::resetGrid()
+{
+ Up_Left_Point.param_set_and_write_default();
+ Up_Right_Point.param_set_and_write_default();
+ Down_Right_Point.param_set_and_write_default();
+ Down_Left_Point.param_set_and_write_default();
+ //todo:this hack is only to reposition the knots on reser grid button
+ //Better update path effect in LPEITEM
+ SPDesktop * desktop = inkscape_active_desktop();
+ tools_switch(desktop, TOOLS_SELECT);
+ tools_switch(desktop, TOOLS_NODES);
+}
+
+void
+LPEEnvelopePerspective::resetDefaults(SPItem const* item)
+{
+ Effect::resetDefaults(item);
+ original_bbox(SP_LPE_ITEM(item));
+ setDefaults();
+ resetGrid();
+}
+
+void
+LPEEnvelopePerspective::calculateCurve(Geom::Point a,Geom::Point b, SPCurve* c, bool horizontal, bool move)
+{
+ using Geom::X;
+ using Geom::Y;
+ if(move) c->moveto(a);
+ Geom::Point cubic1 = a + (1./3)* (b - a);
+ Geom::Point cubic2 = b + (1./3)* (a - b);
+ if(horizontal) c->curveto(Geom::Point(cubic1[X],a[Y]),Geom::Point(cubic2[X],b[Y]),b);
+ else c->curveto(Geom::Point(a[X],cubic1[Y]),Geom::Point(b[X],cubic2[Y]),b);
+}
+
+void
+LPEEnvelopePerspective::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.clear();
+
+ SPCurve *c = new SPCurve();
+ c->reset();
+ c->moveto(Up_Left_Point);
+ c->lineto(Up_Right_Point);
+ c->lineto(Down_Right_Point);
+ c->lineto(Down_Left_Point);
+ c->lineto(Up_Left_Point);
+ hp_vec.push_back(c->get_pathvector());
+}
+
+
+/* ######################## */
+
+} //namespace LivePathEffect
+} /* namespace Inkscape */
+
+
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/lpe-envelope-perspective.h b/src/live_effects/lpe-envelope-perspective.h
new file mode 100644
index 000000000..6aae33936
--- /dev/null
+++ b/src/live_effects/lpe-envelope-perspective.h
@@ -0,0 +1,76 @@
+#ifndef INKSCAPE_LPE_ENVELOPE_PERSPECTIVE_H
+#define INKSCAPE_LPE_ENVELOPE_PERSPECTIVE_H
+
+/** \file
+ * LPE <envelope-perspective> implementation , see lpe-envelope-perspective.cpp.
+
+ */
+/*
+ * Authors:
+ * Jabiertxof Code migration from python extensions envelope and perspective
+ * Aaron Spike, aaron@ekips.org from envelope and perspective phyton code
+ * Dmitry Platonov, shadowjack@mail.ru, 2006 perspective approach & math
+ * Jose Hevia (freon) Transform algorithm from envelope
+ *
+ * Copyright (C) 2007-2014 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/parameter/enum.h"
+#include "live_effects/effect.h"
+#include "live_effects/parameter/pointreseteable.h"
+#include "live_effects/lpegroupbbox.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPEEnvelopePerspective : public Effect, GroupBBoxEffect {
+public:
+
+ LPEEnvelopePerspective(LivePathEffectObject *lpeobject);
+ virtual ~LPEEnvelopePerspective();
+
+ virtual void doEffect(SPCurve *curve);
+
+ virtual Geom::Point project_point(Geom::Point p);
+
+ virtual Geom::Point project_point(Geom::Point p, double m[][3]);
+
+ Geom::Point pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B);
+
+ virtual void resetDefaults(SPItem const* item);
+
+ virtual void doBeforeEffect(SPLPEItem const* lpeitem);
+
+ virtual Gtk::Widget * newWidget();
+
+ virtual void calculateCurve(Geom::Point a,Geom::Point b, SPCurve *c, bool horizontal, bool move);
+
+ virtual void setDefaults();
+
+ virtual void resetGrid();
+
+ //virtual void original_bbox(SPLPEItem const* lpeitem, bool absolute = false);
+
+ //virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/);
+
+ //virtual std::vector<Geom::PathVector> getHelperPaths(SPLPEItem const* lpeitem);
+protected:
+ void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
+private:
+
+ BoolParam perspective;
+ PointReseteableParam Up_Left_Point;
+ PointReseteableParam Up_Right_Point;
+ PointReseteableParam Down_Left_Point;
+ PointReseteableParam Down_Right_Point;
+
+ LPEEnvelopePerspective(const LPEEnvelopePerspective&);
+ LPEEnvelopePerspective& operator=(const LPEEnvelopePerspective&);
+};
+
+} //namespace LivePathEffect
+} //namespace Inkscape
+
+#endif