From c006641818185435dcb6b98c49fdae2fa561d762 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 16 Oct 2014 18:05:08 -0400 Subject: Fix previous revision. revid:jtx@jtx.marker.es-20141016153516-eng0y49ppsk2vt5b 13617 Jabiertxof2014-10-16 Change LPE from envelope-perspective to perspective-envelope For me is easy to use/find with this new name. Also fix a rounding error on envelope at small sizes (bzr r13341.1.276) --- src/live_effects/CMakeLists.txt | 5 +- src/live_effects/Makefile_insert | 6 +- src/live_effects/effect-enum.h | 2 +- src/live_effects/effect.cpp | 8 +- src/live_effects/lpe-envelope-perspective.cpp | 440 -------------------------- src/live_effects/lpe-envelope-perspective.h | 76 ----- src/live_effects/lpe-perspective-envelope.cpp | 384 ++++++++++++++++++++++ src/live_effects/lpe-perspective-envelope.h | 70 ++++ 8 files changed, 464 insertions(+), 527 deletions(-) delete mode 100644 src/live_effects/lpe-envelope-perspective.cpp delete mode 100644 src/live_effects/lpe-envelope-perspective.h create mode 100644 src/live_effects/lpe-perspective-envelope.cpp create mode 100644 src/live_effects/lpe-perspective-envelope.h (limited to 'src') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 30c2b2f41..c8a02c810 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -15,7 +15,6 @@ 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 @@ -32,6 +31,7 @@ set(live_effects_SRC lpe-patternalongpath.cpp lpe-perp_bisector.cpp lpe-perspective_path.cpp + lpe-perspective-envelope.cpp lpe-powerstroke.cpp lpe-recursiveskeleton.cpp lpe-rough-hatches.cpp @@ -47,7 +47,6 @@ 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 @@ -106,6 +105,7 @@ set(live_effects_SRC lpe-patternalongpath.h lpe-perp_bisector.h lpe-perspective_path.h + lpe-perspective-envelope.h lpe-powerstroke.h lpe-powerstroke-interpolators.h lpe-recursiveskeleton.h @@ -122,7 +122,6 @@ 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 f18dcdef0..8f0a3ac57 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -70,6 +70,8 @@ ink_common_sources += \ live_effects/lpe-circle_with_radius.h \ live_effects/lpe-perspective_path.cpp \ live_effects/lpe-perspective_path.h \ + live_effects/lpe-perspective-envelope.cpp \ + live_effects/lpe-perspective-envelope.h \ live_effects/lpe-mirror_symmetry.cpp \ live_effects/lpe-mirror_symmetry.h \ live_effects/lpe-circle_3pts.cpp \ @@ -112,6 +114,4 @@ 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-envelope-perspective.cpp \ - live_effects/lpe-envelope-perspective.h + live_effects/lpe-taperstroke.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index c53f1a5b9..383eec19e 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -63,7 +63,7 @@ enum EffectType { BOUNDING_BOX, JOIN_TYPE, TAPER_STROKE, - ENVELOPE_PERSPECTIVE, + PERSPECTIVE_ENVELOPE, FILLET_CHAMFER, 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 0885ad6f0..1a64defd9 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -25,6 +25,7 @@ #include "live_effects/lpe-curvestitch.h" #include "live_effects/lpe-circle_with_radius.h" #include "live_effects/lpe-perspective_path.h" +#include "live_effects/lpe-perspective-envelope.h" #include "live_effects/lpe-spiro.h" #include "live_effects/lpe-lattice.h" #include "live_effects/lpe-lattice2.h" @@ -60,7 +61,6 @@ #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 "live_effects/lpe-fillet-chamfer.h" #include "xml/node-event-vector.h" @@ -152,7 +152,7 @@ const Util::EnumData LPETypeData[] = { /* 0.91 */ {SIMPLIFY, N_("Simplify"), "simplify"}, {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"}, + {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, }; @@ -311,8 +311,8 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case LATTICE2: neweffect = static_cast ( new LPELattice2(lpeobj) ); break; - case ENVELOPE_PERSPECTIVE: - neweffect = static_cast ( new LPEEnvelopePerspective(lpeobj) ); + case PERSPECTIVE_ENVELOPE: + neweffect = static_cast ( new LPEPerspectiveEnvelope(lpeobj) ); break; case FILLET_CHAMFER: neweffect = static_cast ( new LPEFilletChamfer(lpeobj) ); diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp deleted file mode 100644 index c62dbbf6a..000000000 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ /dev/null @@ -1,440 +0,0 @@ -/** \file - * LPE 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 -#include "live_effects/lpe-envelope-perspective.h" -#include "helper/geom.h" -#include "display/curve.h" -#include "svg/svg.h" -#include "ui/tools-switch.h" -#include -#include "desktop.h" - -using namespace Geom; - -namespace Inkscape { -namespace LivePathEffect { - -enum DeformationType { - DEFORMATION_ENVELOPE, - DEFORMATION_PERSPECTIVE -}; - -static const Util::EnumData DeformationTypeData[] = { - {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"}, - {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"} -}; - -static const Util::EnumDataConverter DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData)); - -LPEEnvelopePerspective::LPEEnvelopePerspective(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - // initialise your parameters here: - deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_ENVELOPE), - 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(&deform_type)); - registerParameter( dynamic_cast(&Up_Left_Point) ); - registerParameter( dynamic_cast(&Up_Right_Point) ); - registerParameter( dynamic_cast(&Down_Left_Point) ); - registerParameter( dynamic_cast(&Down_Right_Point) ); -} - -LPEEnvelopePerspective::~LPEEnvelopePerspective() -{ -} - -void LPEEnvelopePerspective::doEffect(SPCurve *curve) { - using Geom::X; - using Geom::Y; - double projmatrix[3][3]; - if(deform_type == DEFORMATION_PERSPECTIVE){ - std::vector handles(4); - handles[0] = Down_Left_Point; - handles[1] = Up_Left_Point; - handles[2] = Up_Right_Point; - handles[3] = Down_Right_Point; - std::vector 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(deform_type == DEFORMATION_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(&*curve_it1); - if (cubic) { - pointAt1 = (*cubic)[1]; - pointAt2 = (*cubic)[2]; - } else { - pointAt1 = curve_it1->initialPoint(); - pointAt2 = curve_it1->finalPoint(); - } - pointAt3 = curve_it1->finalPoint(); - if(deform_type == DEFORMATION_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(&*curve_it1); - if (cubic) { - pointAt1 = (*cubic)[1]; - pointAt2 = (*cubic)[2]; - } else { - pointAt1 = curve_it1->initialPoint(); - pointAt2 = curve_it1->finalPoint(); - } - pointAt3 = curve_it1->finalPoint(); - if(deform_type == DEFORMATION_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(deform_type == DEFORMATION_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); - std::vector::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(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(widg); - std::vector< Gtk::Widget* > childList = pointParameter->get_children(); - Gtk::HBox * pointParameterHBox = dynamic_cast(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); -#if WITH_GTKMM_3_0 - hboxUpHandles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET); -#else - hboxUpHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); -#endif - }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); -#if WITH_GTKMM_3_0 - hboxDownHandles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET); -#else - hboxDownHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET); -#endif - }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)); -#if WITH_GTKMM_3_0 - hboxMiddle->pack_start(*Gtk::manage(new Gtk::Separator()), Gtk::PACK_EXPAND_WIDGET); - hboxMiddle->pack_start(*Gtk::manage(new Gtk::Separator()), Gtk::PACK_EXPAND_WIDGET); -#else - hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); - hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); -#endif - vbox->pack_start(*hboxMiddle, false, true, 2); - vbox->pack_start(*hboxDownHandles, true, true, 2); - 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); - return dynamic_cast(vbox); -} - -void -LPEEnvelopePerspective::doBeforeEffect (SPLPEItem const* lpeitem) -{ - original_bbox(lpeitem); - setDefaults(); - SPLPEItem * item = const_cast(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); -} - -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 &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 deleted file mode 100644 index 0de9a0e35..000000000 --- a/src/live_effects/lpe-envelope-perspective.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef INKSCAPE_LPE_ENVELOPE_PERSPECTIVE_H -#define INKSCAPE_LPE_ENVELOPE_PERSPECTIVE_H - -/** \file - * LPE 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 &/*hp_vec*/); - - //virtual std::vector getHelperPaths(SPLPEItem const* lpeitem); -protected: - void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); -private: - - EnumParam deform_type; - 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 diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp new file mode 100644 index 000000000..249269b6f --- /dev/null +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -0,0 +1,384 @@ +/** \file + * LPE 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 +#include "live_effects/lpe-perspective-envelope.h" +#include "helper/geom.h" +#include "display/curve.h" +#include "svg/svg.h" +#include "ui/tools-switch.h" +#include +#include "desktop.h" + +using namespace Geom; + +namespace Inkscape { +namespace LivePathEffect { + +enum DeformationType { + DEFORMATION_PERSPECTIVE, + DEFORMATION_ENVELOPE +}; + +static const Util::EnumData DeformationTypeData[] = { + {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"}, + {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"} +}; + +static const Util::EnumDataConverter DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData)); + +LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + // initialise your parameters here: + deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_PERSPECTIVE), + 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(&deform_type)); + registerParameter( dynamic_cast(&Up_Left_Point) ); + registerParameter( dynamic_cast(&Up_Right_Point) ); + registerParameter( dynamic_cast(&Down_Left_Point) ); + registerParameter( dynamic_cast(&Down_Right_Point) ); +} + +LPEPerspectiveEnvelope::~LPEPerspectiveEnvelope() +{ +} + +void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { + using Geom::X; + using Geom::Y; + double projmatrix[3][3]; + if(deform_type == DEFORMATION_PERSPECTIVE){ + std::vector handles(4); + handles[0] = Down_Left_Point; + handles[1] = Up_Left_Point; + handles[2] = Up_Right_Point; + handles[3] = Down_Right_Point; + std::vector 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(); + Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); + Geom::Path::const_iterator curve_endit = path_it->end_default(); + + if (path_it->closed()) { + const Geom::Curve &closingline = + path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + if(deform_type == DEFORMATION_PERSPECTIVE){ + nCurve->moveto(project_point(curve_it1->initialPoint(),projmatrix)); + }else{ + nCurve->moveto(project_point(curve_it1->initialPoint())); + } + while (curve_it1 != curve_endit) { + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + pointAt1 = (*cubic)[1]; + pointAt2 = (*cubic)[2]; + } else { + pointAt1 = curve_it1->initialPoint(); + pointAt2 = curve_it1->finalPoint(); + } + pointAt3 = curve_it1->finalPoint(); + if(deform_type == DEFORMATION_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; + if(curve_it2 != curve_endit) { + ++curve_it2; + } + } + //y cerramos la curva + if (path_it->closed()) { + nCurve->move_endpoints(pointAt3, pointAt3); + nCurve->closepath_current(); + } + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; + } +} + +Geom::Point +LPEPerspectiveEnvelope::project_point(Geom::Point p){ + double width = boundingbox_X.extent(); + double height = boundingbox_Y.extent(); + double delta_x = boundingbox_X.min() - p[X]; + double delta_y = boundingbox_Y.max() - p[Y]; + Geom::Coord xratio = (delta_x * sgn(delta_x)) / width; + Geom::Coord yratio = (delta_y * sgn(delta_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 +LPEPerspectiveEnvelope::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 +LPEPerspectiveEnvelope::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 * +LPEPerspectiveEnvelope::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); + std::vector::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(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(widg); + std::vector< Gtk::Widget* > childList = pointParameter->get_children(); + Gtk::HBox * pointParameterHBox = dynamic_cast(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); + 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,&LPEPerspectiveEnvelope::resetGrid)); + resetButton->set_size_request(140,45); + vbox->pack_start(*hbox, true,true,2); + hbox->pack_start(*resetButton, false, false,2); + return dynamic_cast(vbox); +} + +void +LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) +{ + original_bbox(lpeitem); + setDefaults(); +} + +void +LPEPerspectiveEnvelope::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 +LPEPerspectiveEnvelope::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 +LPEPerspectiveEnvelope::resetDefaults(SPItem const* item) +{ + Effect::resetDefaults(item); + original_bbox(SP_LPE_ITEM(item)); + setDefaults(); + resetGrid(); +} + +void +LPEPerspectiveEnvelope::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &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: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-perspective-envelope.h b/src/live_effects/lpe-perspective-envelope.h new file mode 100644 index 000000000..2f253882e --- /dev/null +++ b/src/live_effects/lpe-perspective-envelope.h @@ -0,0 +1,70 @@ +#ifndef INKSCAPE_LPE_PERSPECTIVE_ENVELOPE_H +#define INKSCAPE_LPE_PERSPECTIVE_ENVELOPE_H + +/** \file + * LPE implementation , see lpe-perspective-envelope.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 LPEPerspectiveEnvelope : public Effect, GroupBBoxEffect { +public: + + LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject); + + virtual ~LPEPerspectiveEnvelope(); + + virtual void doEffect(SPCurve *curve); + + virtual Geom::Point project_point(Geom::Point p); + + virtual Geom::Point project_point(Geom::Point p, double m[][3]); + + virtual 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 setDefaults(); + + virtual void resetGrid(); + +protected: + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); +private: + + EnumParam deform_type; + PointReseteableParam Up_Left_Point; + PointReseteableParam Up_Right_Point; + PointReseteableParam Down_Left_Point; + PointReseteableParam Down_Right_Point; + + LPEPerspectiveEnvelope(const LPEPerspectiveEnvelope&); + LPEPerspectiveEnvelope& operator=(const LPEPerspectiveEnvelope&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif -- cgit v1.2.3