From afcec343e905389d2645115d60f14dfd45f5f2d0 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 14 Dec 2012 01:01:57 +0100 Subject: bzr history lost by a killed merge (bzr r11950.1.1) --- src/live_effects/CMakeLists.txt | 2 ++ src/live_effects/Makefile_insert | 2 ++ src/live_effects/effect-enum.h | 3 +++ src/live_effects/effect.cpp | 13 ++++++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index a5f50a69d..7aeb911b0 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -34,6 +34,7 @@ set(live_effects_SRC lpe-spiro.cpp lpe-tangent_to_curve.cpp lpe-test-doEffect-stack.cpp + lpe-bspline.cpp lpe-text_label.cpp lpe-vonkoch.cpp lpegroupbbox.cpp @@ -94,6 +95,7 @@ set(live_effects_SRC lpe-spiro.h lpe-tangent_to_curve.h lpe-test-doEffect-stack.h + lpe-bspline.h lpe-text_label.h lpe-vonkoch.h lpegroupbbox.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 9c3c171f2..248030e8c 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -38,6 +38,8 @@ ink_common_sources += \ live_effects/lpe-interpolate.h \ live_effects/lpe-test-doEffect-stack.cpp \ live_effects/lpe-test-doEffect-stack.h \ + live_effects/lpe-bspline.cpp \ + live_effects/lpe-bspline.h \ live_effects/lpe-lattice.cpp \ live_effects/lpe-lattice.h \ live_effects/lpe-envelope.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 43af33b53..cf97dd87f 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -45,6 +45,9 @@ enum EffectType { PATH_LENGTH, LINE_SEGMENT, DOEFFECTSTACK_TEST, + //BSpline + BSPLINE, + //BSpline End DYNASTROKE, RECURSIVE_SKELETON, EXTRUDE, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 3b57de25c..e9ec2076f 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -10,7 +10,7 @@ #include "live_effects/effect.h" #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif // include effects: @@ -22,6 +22,9 @@ #include "live_effects/lpe-rough-hatches.h" #include "live_effects/lpe-dynastroke.h" #include "live_effects/lpe-test-doEffect-stack.h" +//BSpline +#include "live_effects/lpe-bspline.h" +//BSpline End #include "live_effects/lpe-gears.h" #include "live_effects/lpe-curvestitch.h" #include "live_effects/lpe-circle_with_radius.h" @@ -123,6 +126,9 @@ const Util::EnumData LPETypeData[] = { /* 0.49 */ {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, + //BSpline + {BSPLINE, N_("BSpline"), "bspline"}, + //BSpline End }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -231,6 +237,11 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case DOEFFECTSTACK_TEST: neweffect = static_cast ( new LPEdoEffectStackTest(lpeobj) ); break; + //BSpline + case BSPLINE: + neweffect = static_cast ( new LPEBSpline(lpeobj) ); + break; + //BSpline End case DYNASTROKE: neweffect = static_cast ( new LPEDynastroke(lpeobj) ); break; -- cgit v1.2.3 From d395af6ee332142c63355d008d49b1f4b3487dfe Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 24 Dec 2012 08:05:24 +0100 Subject: Going to merge (bzr r11950.1.5) --- src/live_effects/lpe-bspline.cpp | 226 +++++++++++++++++++++++++++++++++++++++ src/live_effects/lpe-bspline.h | 35 ++++++ 2 files changed, 261 insertions(+) create mode 100644 src/live_effects/lpe-bspline.cpp create mode 100644 src/live_effects/lpe-bspline.h (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp new file mode 100644 index 000000000..e125cc4e0 --- /dev/null +++ b/src/live_effects/lpe-bspline.cpp @@ -0,0 +1,226 @@ +#define INKSCAPE_LPE_BSPLINE_C + +/* + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-bspline.h" + +#include "display/curve.h" +#include +#include <2geom/pathvector.h> +#include <2geom/affine.h> +#include <2geom/bezier-curve.h> +#include "helper/geom-curves.h" + +// For handling un-continuous paths: +#include "message-stack.h" +#include "inkscape.h" +#include "desktop.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : + Effect(lpeobject) +{ +} + +LPEBSpline::~LPEBSpline() +{ +} +//Crea una nueva curva reseteando la original +SPCurve * +LPEBSpline::reverse_then_reset(SPCurve * orig){ + SPCurve *ret = orig->create_reverse(); + orig->reset(); + return ret; +} + +void +LPEBSpline::doEffect(SPCurve * curve) +{ + using Geom::X; + using Geom::Y; + + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); + //Sbasis + Geom::D2< Geom::SBasis > SBasisIn; + Geom::D2< Geom::SBasis > SBasisOut; + Geom::D2< Geom::SBasis > SBasisEnd; + Geom::D2< Geom::SBasis > SBasisHelper; + //curves + SPCurve * in = new SPCurve(); + SPCurve * out = new SPCurve(); + SPCurve * end = new SPCurve(); + //Curvas temporales + SPCurve *lineHelper = new SPCurve(); + SPCurve *curveHelper = new SPCurve(); + SPCurve *nCurve = new SPCurve(); + //Puntos a usar. Ponemos todos los posibles para hacer más inteligible el código + Geom::Point startNode(0,0); + Geom::Point previousNode(0,0); + Geom::Point node(0,0); + //Geom::Point previousPointAt3(0,0); + Geom::Point pointAt0(0,0); + Geom::Point pointAt1(0,0); + Geom::Point pointAt2(0,0); + Geom::Point pointAt3(0,0); + //Geom::Point nextPointAt0(0,0); + Geom::Point nextPointAt1(0,0); + Geom::Point nextPointAt2(0,0); + Geom::Point nextPointAt3(0,0); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo + 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 + 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_end = path_it->end(); // end curve + Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop + //Las lineas rectas forman nodos BSpline + //Las curvas forman nodos CUSP + bool isBSpline = true; + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + //este no cambia. + end->moveto(curve_end->initialPoint()); + end->lineto(curve_end->finalPoint()); + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo BSPline + if (path_it->closed() && is_straight_curve(*curve_end)) { + //Calculamos el nodo de inicio BSpline + SBasisIn = in->first_segment()->toSBasis(); + SBasisEnd = end->first_segment()->toSBasis(); + lineHelper->moveto(SBasisIn.valueAt(0.3334)); + lineHelper->lineto(SBasisEnd.valueAt(0.6664)); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + //Guardamos el principio de la curva + startNode = SBasisHelper.valueAt(0.5); + //Definimos el punto de inicio original de la curva resultante + node = startNode; + }else{ + //Guardamos el principio de la curva + startNode = in->first_segment()->initialPoint(); + //Definimos el punto de inicio original de la curva resultante + node = startNode; + } + //Recorremos todos los segmentos menos el último + while ( curve_it2 != curve_endit ) + { + //Damos valor a el objeto SBasis para el path de entrada y el de salida + SBasisIn = in->first_segment()->toSBasis(); + SBasisOut = out->first_segment()->toSBasis(); + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida + pointAt0 = SBasisIn.valueAt(0); + pointAt1 = SBasisIn.valueAt(0.3334); + pointAt2 = SBasisIn.valueAt(0.6667); + pointAt3 = SBasisIn.valueAt(1); + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + nextPointAt1 = SBasisOut.valueAt(0.3334); + nextPointAt2 = SBasisOut.valueAt(0.6667);; + nextPointAt3 = SBasisOut.valueAt(1); + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente de + //los manejadores de la curva + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva + previousNode = node; + //Y este hará de final de curva + node = SBasisHelper.valueAt(0.5); + //Vemos si el nodo es BSpline o CUSP + //Averiguamos si el path de entrada es recto o tiene manejadores + isBSpline = is_straight_curve(*curve_it1); + //Si no es recto, tenemos que generar la curva con nodo final CUSP + if(!isBSpline ){ + //Definimos como nodo el final del segmento de entrada + node = pointAt3; + } + curveHelper->moveto(previousNode); + curveHelper->curveto(pointAt1, pointAt2, node); + //añadimos la curva generada a la curva pricipal + nCurve->append_continuous(curveHelper, 0.0625); + curveHelper->reset(); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + in->reset(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + out->reset(); + if(curve_it1 != curve_end){ + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + } + } + //Aberiguamos la ultima parte de la curva correspondiente al último segmento + curveHelper->moveto(node); + //Si está cerrada la curva, la cerramos sobre el valor guardado previamente + //Si no finalizamos en el punto final + if (path_it->closed()) { + curveHelper->curveto(nextPointAt1, nextPointAt2, startNode); + }else{ + curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + } + //añadimos este último segmento + nCurve->append_continuous(curveHelper, 0.0625); + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); + } + curve->append(nCurve,false); + nCurve->reset(); + //Limpiamos + in->reset(); + out->reset(); + end->reset(); + lineHelper->reset(); + curveHelper->reset(); + } + delete in; + delete out; + delete end; + delete lineHelper; + delete curveHelper; + //Todo: remove? + //delete SBasisIn; + //delete SBasisOut; + //delete SBasisEnd; + //delete SBasisHelper; +} + + + +}; //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-bspline.h b/src/live_effects/lpe-bspline.h new file mode 100644 index 000000000..23ac495df --- /dev/null +++ b/src/live_effects/lpe-bspline.h @@ -0,0 +1,35 @@ +#ifndef INKSCAPE_LPE_BSPLINE_H +#define INKSCAPE_LPE_BSPLINE_H + +/* + * Inkscape::LPEBSpline + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" + + +namespace Inkscape { +namespace LivePathEffect { + +class LPEBSpline : public Effect { +public: + LPEBSpline(LivePathEffectObject *lpeobject); + virtual ~LPEBSpline(); + + virtual LPEPathFlashType pathFlashType() { return SUPPRESS_FLASH; } + + virtual SPCurve *reverse_then_reset(SPCurve * orig); + + virtual void doEffect(SPCurve * curve); + +private: + LPEBSpline(const LPEBSpline&); + LPEBSpline& operator=(const LPEBSpline&); +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape + +#endif -- cgit v1.2.3 From eac303cf672b1c09a0378ca8b34aafcfdf4ee08d Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 4 Jan 2013 22:30:00 +0100 Subject: Fixing StartAnchor problems in bspline (bzr r11950.1.10) --- src/live_effects/lpe-bspline.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index e125cc4e0..24e7a5027 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -13,6 +13,7 @@ #include <2geom/bezier-curve.h> #include "helper/geom-curves.h" + // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -72,6 +73,8 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); + Geom::CubicBezier const * cubic; + Geom::PathVector newpathv; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { @@ -79,6 +82,7 @@ LPEBSpline::doEffect(SPCurve * curve) if (path_it->empty()) continue; //Itreadores + 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_end = path_it->end(); // end curve @@ -100,7 +104,12 @@ LPEBSpline::doEffect(SPCurve * curve) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - if (path_it->closed() && is_straight_curve(*curve_end)) { + + cubic = dynamic_cast(&*curve_endit); + if((*cubic)[2] == (*cubic)[3]) + isBSpline = false; + if (path_it->closed() && !isBSpline) { + isBSpline = true; //Calculamos el nodo de inicio BSpline SBasisIn = in->first_segment()->toSBasis(); SBasisEnd = end->first_segment()->toSBasis(); @@ -149,9 +158,11 @@ LPEBSpline::doEffect(SPCurve * curve) //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); //Vemos si el nodo es BSpline o CUSP - //Averiguamos si el path de entrada es recto o tiene manejadores - isBSpline = is_straight_curve(*curve_it1); - //Si no es recto, tenemos que generar la curva con nodo final CUSP + //Averiguamos si el punto de union tiene manejadores + cubic = dynamic_cast(&*curve_it1); + if((*cubic)[2] == (*cubic)[3]) + isBSpline = true; + //Si no tiene manejador, tenemos que generar la curva con nodo final CUSP if(!isBSpline ){ //Definimos como nodo el final del segmento de entrada node = pointAt3; -- cgit v1.2.3 From 32866e3ed73a2a8c41520e2538687b5701a2d347 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 5 Jan 2013 11:53:55 +0100 Subject: fix continue (bzr r11950.1.11) --- src/live_effects/lpe-bspline.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 24e7a5027..c8263282e 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -1,5 +1,5 @@ +#define INKSCAPE_HELPER_GEOM_CURVES_H #define INKSCAPE_LPE_BSPLINE_C - /* * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -73,9 +73,6 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); - Geom::CubicBezier const * cubic; - Geom::PathVector newpathv; - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -104,10 +101,10 @@ LPEBSpline::doEffect(SPCurve * curve) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - - cubic = dynamic_cast(&*curve_endit); - if((*cubic)[2] == (*cubic)[3]) - isBSpline = false; + if (Geom::CubicBezier const *cubic = dynamic_cast(&*curve_end)){ + if((*cubic)[2] == (*cubic)[3]) + isBSpline = false; + } if (path_it->closed() && !isBSpline) { isBSpline = true; //Calculamos el nodo de inicio BSpline @@ -159,9 +156,10 @@ LPEBSpline::doEffect(SPCurve * curve) node = SBasisHelper.valueAt(0.5); //Vemos si el nodo es BSpline o CUSP //Averiguamos si el punto de union tiene manejadores - cubic = dynamic_cast(&*curve_it1); - if((*cubic)[2] == (*cubic)[3]) - isBSpline = true; + if (Geom::CubicBezier const *cubic = dynamic_cast(&*curve_it1)){ + if((*cubic)[2] == (*cubic)[3]) + isBSpline = true; + } //Si no tiene manejador, tenemos que generar la curva con nodo final CUSP if(!isBSpline ){ //Definimos como nodo el final del segmento de entrada @@ -221,7 +219,6 @@ LPEBSpline::doEffect(SPCurve * curve) } - }; //namespace LivePathEffect }; /* namespace Inkscape */ -- cgit v1.2.3 From 74b658f45b5044ab5903ccc255c1ae0f8a750fce Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 6 Jan 2013 19:20:10 +0100 Subject: fix continue (bzr r11950.1.12) --- src/live_effects/lpe-bspline.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index c8263282e..a57cc9a88 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -1,4 +1,3 @@ -#define INKSCAPE_HELPER_GEOM_CURVES_H #define INKSCAPE_LPE_BSPLINE_C /* * Released under GNU GPL, read the file 'COPYING' for more information @@ -73,6 +72,7 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); + Geom::CubicBezier const *cubic; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -101,17 +101,15 @@ LPEBSpline::doEffect(SPCurve * curve) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - if (Geom::CubicBezier const *cubic = dynamic_cast(&*curve_end)){ - if((*cubic)[2] == (*cubic)[3]) - isBSpline = false; - } - if (path_it->closed() && !isBSpline) { - isBSpline = true; + cubic = dynamic_cast(&*curve_end); + if(cubic && (*cubic)[2] != (*cubic)[3]) + isBSpline = false; + if (path_it->closed() && isBSpline) { //Calculamos el nodo de inicio BSpline SBasisIn = in->first_segment()->toSBasis(); SBasisEnd = end->first_segment()->toSBasis(); lineHelper->moveto(SBasisIn.valueAt(0.3334)); - lineHelper->lineto(SBasisEnd.valueAt(0.6664)); + lineHelper->lineto(SBasisEnd.valueAt(0.6667)); SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); //Guardamos el principio de la curva @@ -119,6 +117,7 @@ LPEBSpline::doEffect(SPCurve * curve) //Definimos el punto de inicio original de la curva resultante node = startNode; }else{ + isBSpline = true; //Guardamos el principio de la curva startNode = in->first_segment()->initialPoint(); //Definimos el punto de inicio original de la curva resultante @@ -156,13 +155,16 @@ LPEBSpline::doEffect(SPCurve * curve) node = SBasisHelper.valueAt(0.5); //Vemos si el nodo es BSpline o CUSP //Averiguamos si el punto de union tiene manejadores - if (Geom::CubicBezier const *cubic = dynamic_cast(&*curve_it1)){ - if((*cubic)[2] == (*cubic)[3]) - isBSpline = true; - } + cubic = dynamic_cast(&*curve_it1); + if(cubic && (*cubic)[2] != (*cubic)[3]) + isBSpline = false; + cubic = dynamic_cast(&*curve_it2); + if(cubic && (*cubic)[0] != (*cubic)[1]) + isBSpline = false; //Si no tiene manejador, tenemos que generar la curva con nodo final CUSP if(!isBSpline ){ //Definimos como nodo el final del segmento de entrada + isBSpline = true; node = pointAt3; } curveHelper->moveto(previousNode); @@ -190,6 +192,7 @@ LPEBSpline::doEffect(SPCurve * curve) curveHelper->curveto(nextPointAt1, nextPointAt2, startNode); }else{ curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + isBSpline = true; } //añadimos este último segmento nCurve->append_continuous(curveHelper, 0.0625); -- cgit v1.2.3 From eeb9410c8748a03536119dd01615cda3ca215cb1 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 8 Jan 2013 01:57:47 +0100 Subject: Fix BSplines whit 1 segment (bzr r11950.1.16) --- src/live_effects/lpe-bspline.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index a57cc9a88..a1f51de0b 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -43,6 +43,8 @@ LPEBSpline::doEffect(SPCurve * curve) using Geom::X; using Geom::Y; + if(curve->get_segment_count() < 2) + return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); -- cgit v1.2.3 From 91942b752107bb44bbc64af31d5912a8b04c815a Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 13 Feb 2013 00:07:12 +0100 Subject: First attempt for Adjustable Wheight (bzr r11950.1.28) --- src/live_effects/lpe-bspline.cpp | 82 ++++++++++++++-------------------------- src/live_effects/lpe-bspline.h | 2 - 2 files changed, 28 insertions(+), 56 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index a1f51de0b..8a01beabd 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -53,14 +53,14 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::D2< Geom::SBasis > SBasisOut; Geom::D2< Geom::SBasis > SBasisEnd; Geom::D2< Geom::SBasis > SBasisHelper; - //curves - SPCurve * in = new SPCurve(); - SPCurve * out = new SPCurve(); - SPCurve * end = new SPCurve(); //Curvas temporales SPCurve *lineHelper = new SPCurve(); SPCurve *curveHelper = new SPCurve(); SPCurve *nCurve = new SPCurve(); + //curves + SPCurve * in = new SPCurve(); + SPCurve * out = new SPCurve(); + SPCurve * end = new SPCurve(); //Puntos a usar. Ponemos todos los posibles para hacer más inteligible el código Geom::Point startNode(0,0); Geom::Point previousNode(0,0); @@ -74,7 +74,9 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); - Geom::CubicBezier const *cubic; + Geom::CubicBezier const *cubicIn; + Geom::CubicBezier const *cubicOut; + Geom::CubicBezier const *cubicEnd; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -86,9 +88,6 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve Geom::Path::const_iterator curve_end = path_it->end(); // end curve Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop - //Las lineas rectas forman nodos BSpline - //Las curvas forman nodos CUSP - bool isBSpline = true; //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán //los puntos clave para los manejadores. //Esto hace que la curva BSpline no pierda su condición aunque se trasladen @@ -100,31 +99,22 @@ LPEBSpline::doEffect(SPCurve * curve) //este no cambia. end->moveto(curve_end->initialPoint()); end->lineto(curve_end->finalPoint()); + //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - cubic = dynamic_cast(&*curve_end); - if(cubic && (*cubic)[2] != (*cubic)[3]) - isBSpline = false; - if (path_it->closed() && isBSpline) { - //Calculamos el nodo de inicio BSpline - SBasisIn = in->first_segment()->toSBasis(); - SBasisEnd = end->first_segment()->toSBasis(); - lineHelper->moveto(SBasisIn.valueAt(0.3334)); - lineHelper->lineto(SBasisEnd.valueAt(0.6667)); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - //Guardamos el principio de la curva - startNode = SBasisHelper.valueAt(0.5); - //Definimos el punto de inicio original de la curva resultante - node = startNode; - }else{ - isBSpline = true; - //Guardamos el principio de la curva - startNode = in->first_segment()->initialPoint(); - //Definimos el punto de inicio original de la curva resultante - node = startNode; - } + cubicIn = dynamic_cast(&*curve_it1); + cubicOut = dynamic_cast(&*curve_it2); + cubicEnd = dynamic_cast(&*curve_end); + //Calculamos el nodo de inicio BSpline + lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment()))); + lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubicEnd)[2],*end->first_segment()))); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + //Guardamos el principio de la curva + startNode = SBasisHelper.valueAt(0.5); + //Definimos el punto de inicio original de la curva resultante + node = startNode; //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { @@ -134,14 +124,15 @@ LPEBSpline::doEffect(SPCurve * curve) //previousPointAt3 = pointAt3; //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida pointAt0 = SBasisIn.valueAt(0); - pointAt1 = SBasisIn.valueAt(0.3334); - pointAt2 = SBasisIn.valueAt(0.6667); + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment())); + pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[2],*in->first_segment())); pointAt3 = SBasisIn.valueAt(1); //Y hacemos lo propio con el path de salida //nextPointAt0 = curveOut.valueAt(0); - nextPointAt1 = SBasisOut.valueAt(0.3334); - nextPointAt2 = SBasisOut.valueAt(0.6667);; + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[1],*in->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[1],*out->first_segment())); nextPointAt3 = SBasisOut.valueAt(1); + //La curva BSpline se forma calculando el centro del segmanto de unión //de el punto situado en las 2/3 partes de el segmento de entrada //con el punto situado en la posición 1/3 del segmento de salida @@ -155,20 +146,6 @@ LPEBSpline::doEffect(SPCurve * curve) previousNode = node; //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); - //Vemos si el nodo es BSpline o CUSP - //Averiguamos si el punto de union tiene manejadores - cubic = dynamic_cast(&*curve_it1); - if(cubic && (*cubic)[2] != (*cubic)[3]) - isBSpline = false; - cubic = dynamic_cast(&*curve_it2); - if(cubic && (*cubic)[0] != (*cubic)[1]) - isBSpline = false; - //Si no tiene manejador, tenemos que generar la curva con nodo final CUSP - if(!isBSpline ){ - //Definimos como nodo el final del segmento de entrada - isBSpline = true; - node = pointAt3; - } curveHelper->moveto(previousNode); curveHelper->curveto(pointAt1, pointAt2, node); //añadimos la curva generada a la curva pricipal @@ -177,6 +154,7 @@ LPEBSpline::doEffect(SPCurve * curve) //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; + //Damos valor a el objeto para el path de entrada y el de salida in->reset(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); @@ -185,6 +163,8 @@ LPEBSpline::doEffect(SPCurve * curve) out->moveto(curve_it2->initialPoint()); out->lineto(curve_it2->finalPoint()); } + cubicIn = dynamic_cast(&*curve_it1); + cubicOut = dynamic_cast(&*curve_it2); } //Aberiguamos la ultima parte de la curva correspondiente al último segmento curveHelper->moveto(node); @@ -194,7 +174,6 @@ LPEBSpline::doEffect(SPCurve * curve) curveHelper->curveto(nextPointAt1, nextPointAt2, startNode); }else{ curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - isBSpline = true; } //añadimos este último segmento nCurve->append_continuous(curveHelper, 0.0625); @@ -217,13 +196,8 @@ LPEBSpline::doEffect(SPCurve * curve) delete lineHelper; delete curveHelper; //Todo: remove? - //delete SBasisIn; - //delete SBasisOut; - //delete SBasisEnd; //delete SBasisHelper; } - - }; //namespace LivePathEffect }; /* namespace Inkscape */ diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 23ac495df..898f638ed 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -18,8 +18,6 @@ public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); - virtual LPEPathFlashType pathFlashType() { return SUPPRESS_FLASH; } - virtual SPCurve *reverse_then_reset(SPCurve * orig); virtual void doEffect(SPCurve * curve); -- cgit v1.2.3 From 23e56d5e362d55bb22edaf1070cbac0b604aee36 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 13 Feb 2013 03:55:29 +0100 Subject: First Steps, BSpline Live Path Ok, working Pen Context (bzr r11950.1.29) --- src/live_effects/lpe-bspline.cpp | 88 ++++++++++++++++++++++++---------------- src/live_effects/lpe-bspline.h | 2 +- 2 files changed, 54 insertions(+), 36 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 8a01beabd..408f0f8a6 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -12,7 +12,6 @@ #include <2geom/bezier-curve.h> #include "helper/geom-curves.h" - // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -29,13 +28,6 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : LPEBSpline::~LPEBSpline() { } -//Crea una nueva curva reseteando la original -SPCurve * -LPEBSpline::reverse_then_reset(SPCurve * orig){ - SPCurve *ret = orig->create_reverse(); - orig->reset(); - return ret; -} void LPEBSpline::doEffect(SPCurve * curve) @@ -106,46 +98,70 @@ LPEBSpline::doEffect(SPCurve * curve) cubicIn = dynamic_cast(&*curve_it1); cubicOut = dynamic_cast(&*curve_it2); cubicEnd = dynamic_cast(&*curve_end); - //Calculamos el nodo de inicio BSpline - lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment()))); - lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubicEnd)[2],*end->first_segment()))); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - //Guardamos el principio de la curva - startNode = SBasisHelper.valueAt(0.5); - //Definimos el punto de inicio original de la curva resultante - node = startNode; + if (path_it->closed() && cubicIn && cubicEnd && (*cubicIn)[1] != (*cubicEnd)[2]){ + //Calculamos el nodo de inicio BSpline + SBasisIn = in->first_segment()->toSBasis(); + SBasisEnd = end->first_segment()->toSBasis(); + lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment()))); + lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubicEnd)[2],*end->first_segment()))); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + //Guardamos el principio de la curva + startNode = SBasisHelper.valueAt(0.5); + //Definimos el punto de inicio original de la curva resultante + node = startNode; + }else{ + startNode = in->first_segment()->initialPoint(); + node = startNode; + } //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { - //Damos valor a el objeto SBasis para el path de entrada y el de salida SBasisIn = in->first_segment()->toSBasis(); SBasisOut = out->first_segment()->toSBasis(); //previousPointAt3 = pointAt3; //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - pointAt0 = SBasisIn.valueAt(0); - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment())); - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[2],*in->first_segment())); - pointAt3 = SBasisIn.valueAt(1); + if(cubicIn){ + pointAt0 = SBasisIn.valueAt(0); + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment())); + pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[2],*in->first_segment())); + pointAt3 = SBasisIn.valueAt(1); + }else{ + pointAt0 = SBasisIn.valueAt(0); + pointAt1 = SBasisIn.valueAt(0); + pointAt2 = SBasisIn.valueAt(1); + pointAt3 = SBasisIn.valueAt(1); + } //Y hacemos lo propio con el path de salida //nextPointAt0 = curveOut.valueAt(0); - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[1],*in->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[1],*out->first_segment())); - nextPointAt3 = SBasisOut.valueAt(1); - + if(cubicOut){ + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[1],*out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[2],*out->first_segment())); + nextPointAt3 = SBasisOut.valueAt(1); + }else{ + nextPointAt1 = SBasisOut.valueAt(0); + nextPointAt2 = SBasisOut.valueAt(1); + nextPointAt3 = SBasisOut.valueAt(1); + } //La curva BSpline se forma calculando el centro del segmanto de unión //de el punto situado en las 2/3 partes de el segmento de entrada //con el punto situado en la posición 1/3 del segmento de salida //Estos dos puntos ademas estan posicionados en el lugas correspondiente de //los manejadores de la curva - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva - previousNode = node; - //Y este hará de final de curva - node = SBasisHelper.valueAt(0.5); + if(nextPointAt1 != pointAt2){ + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva + previousNode = node; + //Y este hará de final de curva + node = SBasisHelper.valueAt(0.5); + }else{ + previousNode = node; + //Y este hará de final de curva + node = nextPointAt1; + } curveHelper->moveto(previousNode); curveHelper->curveto(pointAt1, pointAt2, node); //añadimos la curva generada a la curva pricipal @@ -162,9 +178,10 @@ LPEBSpline::doEffect(SPCurve * curve) if(curve_it1 != curve_end){ out->moveto(curve_it2->initialPoint()); out->lineto(curve_it2->finalPoint()); + cubicOut = dynamic_cast(&*curve_it2); } cubicIn = dynamic_cast(&*curve_it1); - cubicOut = dynamic_cast(&*curve_it2); + } //Aberiguamos la ultima parte de la curva correspondiente al último segmento curveHelper->moveto(node); @@ -198,6 +215,7 @@ LPEBSpline::doEffect(SPCurve * curve) //Todo: remove? //delete SBasisHelper; } + }; //namespace LivePathEffect }; /* namespace Inkscape */ diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 898f638ed..d983a7654 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -18,7 +18,7 @@ public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); - virtual SPCurve *reverse_then_reset(SPCurve * orig); + virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } virtual void doEffect(SPCurve * curve); -- cgit v1.2.3 From 28b44133e0d9df8054e17ed9724ea645220e1530 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 14 Feb 2013 06:01:26 +0100 Subject: All done except cusp continuous and close bspline (bzr r11950.1.32) --- src/live_effects/lpe-bspline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 408f0f8a6..0ce18dcea 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -98,7 +98,7 @@ LPEBSpline::doEffect(SPCurve * curve) cubicIn = dynamic_cast(&*curve_it1); cubicOut = dynamic_cast(&*curve_it2); cubicEnd = dynamic_cast(&*curve_end); - if (path_it->closed() && cubicIn && cubicEnd && (*cubicIn)[1] != (*cubicEnd)[2]){ + if (path_it->closed() && cubicEnd && (*cubicEnd)[3] != (*cubicEnd)[2]){ //Calculamos el nodo de inicio BSpline SBasisIn = in->first_segment()->toSBasis(); SBasisEnd = end->first_segment()->toSBasis(); -- cgit v1.2.3 From 4a0858ff965d54fc08f721fbbc2503f9ab3d9d3c Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 18 Feb 2013 11:23:51 +0100 Subject: refactor (bzr r11950.1.35) --- src/live_effects/lpe-bspline.cpp | 46 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 0ce18dcea..858a09159 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -45,14 +45,14 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::D2< Geom::SBasis > SBasisOut; Geom::D2< Geom::SBasis > SBasisEnd; Geom::D2< Geom::SBasis > SBasisHelper; - //Curvas temporales - SPCurve *lineHelper = new SPCurve(); - SPCurve *curveHelper = new SPCurve(); - SPCurve *nCurve = new SPCurve(); //curves SPCurve * in = new SPCurve(); SPCurve * out = new SPCurve(); SPCurve * end = new SPCurve(); + //Curvas temporales + SPCurve *lineHelper = new SPCurve(); + SPCurve *curveHelper = new SPCurve(); + SPCurve *nCurve = new SPCurve(); //Puntos a usar. Ponemos todos los posibles para hacer más inteligible el código Geom::Point startNode(0,0); Geom::Point previousNode(0,0); @@ -66,9 +66,7 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); - Geom::CubicBezier const *cubicIn; - Geom::CubicBezier const *cubicOut; - Geom::CubicBezier const *cubicEnd; + Geom::BezierCurve const *bezier; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -80,6 +78,7 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve Geom::Path::const_iterator curve_end = path_it->end(); // end curve Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán //los puntos clave para los manejadores. //Esto hace que la curva BSpline no pierda su condición aunque se trasladen @@ -91,19 +90,18 @@ LPEBSpline::doEffect(SPCurve * curve) //este no cambia. end->moveto(curve_end->initialPoint()); end->lineto(curve_end->finalPoint()); - //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - cubicIn = dynamic_cast(&*curve_it1); - cubicOut = dynamic_cast(&*curve_it2); - cubicEnd = dynamic_cast(&*curve_end); - if (path_it->closed() && cubicEnd && (*cubicEnd)[3] != (*cubicEnd)[2]){ + bezier = dynamic_cast(&*curve_end); + if (path_it->closed() && bezier && (*bezier)[2] != (*bezier)[3]) { //Calculamos el nodo de inicio BSpline SBasisIn = in->first_segment()->toSBasis(); SBasisEnd = end->first_segment()->toSBasis(); - lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment()))); - lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubicEnd)[2],*end->first_segment()))); + bezier = dynamic_cast(&*curve_it1); + lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*bezier)[1],*in->first_segment()))); + bezier = dynamic_cast(&*curve_end); + lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*bezier)[2],*end->first_segment()))); SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); //Guardamos el principio de la curva @@ -111,9 +109,12 @@ LPEBSpline::doEffect(SPCurve * curve) //Definimos el punto de inicio original de la curva resultante node = startNode; }else{ + //Guardamos el principio de la curva startNode = in->first_segment()->initialPoint(); + //Definimos el punto de inicio original de la curva resultante node = startNode; } + //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { @@ -121,10 +122,11 @@ LPEBSpline::doEffect(SPCurve * curve) SBasisOut = out->first_segment()->toSBasis(); //previousPointAt3 = pointAt3; //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - if(cubicIn){ + bezier = dynamic_cast(&*curve_it1); + if(bezier){ pointAt0 = SBasisIn.valueAt(0); - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[1],*in->first_segment())); - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubicIn)[2],*in->first_segment())); + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*bezier)[1],*in->first_segment())); + pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*bezier)[2],*in->first_segment())); pointAt3 = SBasisIn.valueAt(1); }else{ pointAt0 = SBasisIn.valueAt(0); @@ -134,9 +136,10 @@ LPEBSpline::doEffect(SPCurve * curve) } //Y hacemos lo propio con el path de salida //nextPointAt0 = curveOut.valueAt(0); - if(cubicOut){ - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[1],*out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubicOut)[2],*out->first_segment())); + bezier = dynamic_cast(&*curve_it2); + if(bezier){ + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*bezier)[1],*out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*bezier)[2],*out->first_segment())); nextPointAt3 = SBasisOut.valueAt(1); }else{ nextPointAt1 = SBasisOut.valueAt(0); @@ -178,10 +181,7 @@ LPEBSpline::doEffect(SPCurve * curve) if(curve_it1 != curve_end){ out->moveto(curve_it2->initialPoint()); out->lineto(curve_it2->finalPoint()); - cubicOut = dynamic_cast(&*curve_it2); } - cubicIn = dynamic_cast(&*curve_it1); - } //Aberiguamos la ultima parte de la curva correspondiente al último segmento curveHelper->moveto(node); -- cgit v1.2.3 From dfe131791aef37e26fd0358c32222dacf813864c Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 19 Feb 2013 12:08:14 +0100 Subject: Mayor refactor (bzr r11950.1.36) --- src/live_effects/lpe-bspline.cpp | 80 +++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 46 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 858a09159..8147ae014 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -41,9 +41,6 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); //Sbasis - Geom::D2< Geom::SBasis > SBasisIn; - Geom::D2< Geom::SBasis > SBasisOut; - Geom::D2< Geom::SBasis > SBasisEnd; Geom::D2< Geom::SBasis > SBasisHelper; //curves SPCurve * in = new SPCurve(); @@ -66,7 +63,9 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); - Geom::BezierCurve const *bezier; + Geom::CubicBezier const *cubicIn; + Geom::CubicBezier const *cubicOut; + Geom::CubicBezier const *cubicEnd; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -93,15 +92,12 @@ LPEBSpline::doEffect(SPCurve * curve) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - bezier = dynamic_cast(&*curve_end); - if (path_it->closed() && bezier && (*bezier)[2] != (*bezier)[3]) { + cubicEnd = dynamic_cast(&*curve_end); + cubicIn = dynamic_cast(&*curve_it1); + if (path_it->closed() && cubicEnd && cubicIn) { //Calculamos el nodo de inicio BSpline - SBasisIn = in->first_segment()->toSBasis(); - SBasisEnd = end->first_segment()->toSBasis(); - bezier = dynamic_cast(&*curve_it1); - lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*bezier)[1],*in->first_segment()))); - bezier = dynamic_cast(&*curve_end); - lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*bezier)[2],*end->first_segment()))); + lineHelper->moveto((*cubicIn)[1]); + lineHelper->lineto((*cubicEnd)[2]); SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); //Guardamos el principio de la curva @@ -118,53 +114,45 @@ LPEBSpline::doEffect(SPCurve * curve) //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { - SBasisIn = in->first_segment()->toSBasis(); - SBasisOut = out->first_segment()->toSBasis(); //previousPointAt3 = pointAt3; //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - bezier = dynamic_cast(&*curve_it1); - if(bezier){ - pointAt0 = SBasisIn.valueAt(0); - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*bezier)[1],*in->first_segment())); - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*bezier)[2],*in->first_segment())); - pointAt3 = SBasisIn.valueAt(1); + cubicIn = dynamic_cast(&*curve_it1); + if(cubicIn){ + pointAt0 = (*cubicIn)[0]; + pointAt1 = (*cubicIn)[1]; + pointAt2 = (*cubicIn)[2]; + pointAt3 = (*cubicIn)[3]; }else{ - pointAt0 = SBasisIn.valueAt(0); - pointAt1 = SBasisIn.valueAt(0); - pointAt2 = SBasisIn.valueAt(1); - pointAt3 = SBasisIn.valueAt(1); + pointAt0 = in->first_segment()->initialPoint(); + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + pointAt3 = in->first_segment()->finalPoint(); } //Y hacemos lo propio con el path de salida //nextPointAt0 = curveOut.valueAt(0); - bezier = dynamic_cast(&*curve_it2); - if(bezier){ - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*bezier)[1],*out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*bezier)[2],*out->first_segment())); - nextPointAt3 = SBasisOut.valueAt(1); + cubicOut = dynamic_cast(&*curve_it2); + if(cubicOut){ + nextPointAt1 = (*cubicOut)[1]; + nextPointAt2 = (*cubicOut)[2]; + nextPointAt3 = (*cubicOut)[3]; }else{ - nextPointAt1 = SBasisOut.valueAt(0); - nextPointAt2 = SBasisOut.valueAt(1); - nextPointAt3 = SBasisOut.valueAt(1); + nextPointAt1 = in->first_segment()->initialPoint(); + nextPointAt2 = in->first_segment()->finalPoint(); + nextPointAt3 = in->first_segment()->finalPoint(); } //La curva BSpline se forma calculando el centro del segmanto de unión //de el punto situado en las 2/3 partes de el segmento de entrada //con el punto situado en la posición 1/3 del segmento de salida //Estos dos puntos ademas estan posicionados en el lugas correspondiente de //los manejadores de la curva - if(nextPointAt1 != pointAt2){ - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva - previousNode = node; - //Y este hará de final de curva - node = SBasisHelper.valueAt(0.5); - }else{ - previousNode = node; - //Y este hará de final de curva - node = nextPointAt1; - } + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva + previousNode = node; + //Y este hará de final de curva + node = SBasisHelper.valueAt(0.5); curveHelper->moveto(previousNode); curveHelper->curveto(pointAt1, pointAt2, node); //añadimos la curva generada a la curva pricipal -- cgit v1.2.3 From 9af17a6572db964acebd2b7eeea29c8b722c8221 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 23 Feb 2013 23:34:58 +0100 Subject: Saved for next refactor (bzr r11950.1.37) --- src/live_effects/lpe-bspline.cpp | 77 +++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 29 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 8147ae014..8dc840556 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -32,15 +32,15 @@ LPEBSpline::~LPEBSpline() void LPEBSpline::doEffect(SPCurve * curve) { - using Geom::X; - using Geom::Y; - if(curve->get_segment_count() < 2) return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); //Sbasis + Geom::D2< Geom::SBasis > SBasisIn; + Geom::D2< Geom::SBasis > SBasisOut; + Geom::D2< Geom::SBasis > SBasisEnd; Geom::D2< Geom::SBasis > SBasisHelper; //curves SPCurve * in = new SPCurve(); @@ -63,9 +63,9 @@ LPEBSpline::doEffect(SPCurve * curve) Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); - Geom::CubicBezier const *cubicIn; - Geom::CubicBezier const *cubicOut; - Geom::CubicBezier const *cubicEnd; + + Geom::Point endPointAt2(0,0); + Geom::CubicBezier const *cubic; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -75,7 +75,7 @@ LPEBSpline::doEffect(SPCurve * curve) 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_end = path_it->end(); // end curve + Geom::Path::const_iterator curve_end = path_it->end_open(); // end curve Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán @@ -92,12 +92,31 @@ LPEBSpline::doEffect(SPCurve * curve) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - cubicEnd = dynamic_cast(&*curve_end); - cubicIn = dynamic_cast(&*curve_it1); - if (path_it->closed() && cubicEnd && cubicIn) { - //Calculamos el nodo de inicio BSpline - lineHelper->moveto((*cubicIn)[1]); - lineHelper->lineto((*cubicEnd)[2]); + + 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(); + } + SBasisIn = in->first_segment()->toSBasis(); + SBasisEnd = end->first_segment()->toSBasis(); + cubic = dynamic_cast(&*curve_it1); + if(cubic){ + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); + }else{ + pointAt1 = in->first_segment()->initialPoint(); + } + cubic = dynamic_cast(&*curve_end); + if(cubic){ + endPointAt2 = SBasisEnd.valueAt(Geom::nearest_point((*cubic)[2],*end->first_segment())); + }else{ + endPointAt2 = end->first_segment()->finalPoint(); + } + lineHelper->moveto(pointAt1); + lineHelper->lineto(endPointAt2); SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); //Guardamos el principio de la curva @@ -110,18 +129,18 @@ LPEBSpline::doEffect(SPCurve * curve) //Definimos el punto de inicio original de la curva resultante node = startNode; } - //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { //previousPointAt3 = pointAt3; //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - cubicIn = dynamic_cast(&*curve_it1); - if(cubicIn){ - pointAt0 = (*cubicIn)[0]; - pointAt1 = (*cubicIn)[1]; - pointAt2 = (*cubicIn)[2]; - pointAt3 = (*cubicIn)[3]; + cubic = dynamic_cast(&*curve_it1); + if(cubic){ + SBasisIn = in->first_segment()->toSBasis(); + pointAt0 = (*cubic)[0]; + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); + pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2],*in->first_segment())); + pointAt3 = (*cubic)[3]; }else{ pointAt0 = in->first_segment()->initialPoint(); pointAt1 = in->first_segment()->initialPoint(); @@ -130,15 +149,16 @@ LPEBSpline::doEffect(SPCurve * curve) } //Y hacemos lo propio con el path de salida //nextPointAt0 = curveOut.valueAt(0); - cubicOut = dynamic_cast(&*curve_it2); - if(cubicOut){ - nextPointAt1 = (*cubicOut)[1]; - nextPointAt2 = (*cubicOut)[2]; - nextPointAt3 = (*cubicOut)[3]; + cubic = dynamic_cast(&*curve_it2); + if(cubic){ + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1],*out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2],*out->first_segment()));; + nextPointAt3 = (*cubic)[3]; }else{ - nextPointAt1 = in->first_segment()->initialPoint(); - nextPointAt2 = in->first_segment()->finalPoint(); - nextPointAt3 = in->first_segment()->finalPoint(); + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); } //La curva BSpline se forma calculando el centro del segmanto de unión //de el punto situado en las 2/3 partes de el segmento de entrada @@ -203,7 +223,6 @@ LPEBSpline::doEffect(SPCurve * curve) //Todo: remove? //delete SBasisHelper; } - }; //namespace LivePathEffect }; /* namespace Inkscape */ -- cgit v1.2.3 From ecc57932f1e7d157950ada2901f6ea6f3acc8aad Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 28 Feb 2013 04:43:21 +0100 Subject: Fixed closed pc->ea (bzr r11950.1.40) --- src/live_effects/lpe-bspline.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 8dc840556..36caf73c5 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -34,6 +34,8 @@ LPEBSpline::doEffect(SPCurve * curve) { if(curve->get_segment_count() < 2) return; + using Geom::X; + using Geom::Y; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); @@ -94,13 +96,6 @@ LPEBSpline::doEffect(SPCurve * curve) //en posible caso de que se cierre con una linea recta creando un nodo BSPline 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(); - } SBasisIn = in->first_segment()->toSBasis(); SBasisEnd = end->first_segment()->toSBasis(); cubic = dynamic_cast(&*curve_it1); @@ -223,6 +218,7 @@ LPEBSpline::doEffect(SPCurve * curve) //Todo: remove? //delete SBasisHelper; } + }; //namespace LivePathEffect }; /* namespace Inkscape */ -- cgit v1.2.3 From 9c35b88816e60d7fe413a76b48d1764e45157612 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 1 Mar 2013 02:36:23 +0100 Subject: BSpline refactor (bzr r11950.1.41) --- src/live_effects/lpe-bspline.cpp | 118 +++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 66 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 36caf73c5..d046ad683 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -33,41 +33,11 @@ void LPEBSpline::doEffect(SPCurve * curve) { if(curve->get_segment_count() < 2) - return; - using Geom::X; - using Geom::Y; + return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); - //Sbasis - Geom::D2< Geom::SBasis > SBasisIn; - Geom::D2< Geom::SBasis > SBasisOut; - Geom::D2< Geom::SBasis > SBasisEnd; - Geom::D2< Geom::SBasis > SBasisHelper; - //curves - SPCurve * in = new SPCurve(); - SPCurve * out = new SPCurve(); - SPCurve * end = new SPCurve(); - //Curvas temporales - SPCurve *lineHelper = new SPCurve(); - SPCurve *curveHelper = new SPCurve(); - SPCurve *nCurve = new SPCurve(); - //Puntos a usar. Ponemos todos los posibles para hacer más inteligible el código - Geom::Point startNode(0,0); - Geom::Point previousNode(0,0); - Geom::Point node(0,0); - //Geom::Point previousPointAt3(0,0); - Geom::Point pointAt0(0,0); - Geom::Point pointAt1(0,0); - Geom::Point pointAt2(0,0); - Geom::Point pointAt3(0,0); - //Geom::Point nextPointAt0(0,0); - Geom::Point nextPointAt1(0,0); - Geom::Point nextPointAt2(0,0); - Geom::Point nextPointAt3(0,0); - - Geom::Point endPointAt2(0,0); - Geom::CubicBezier const *cubic; + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { //Si está vacío... @@ -77,43 +47,60 @@ LPEBSpline::doEffect(SPCurve * curve) 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_end = path_it->end_open(); // end curve Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán //los puntos clave para los manejadores. //Esto hace que la curva BSpline no pierda su condición aunque se trasladen //dichos manejadores + SPCurve * in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); + SPCurve * out = new SPCurve(); out->moveto(curve_it2->initialPoint()); out->lineto(curve_it2->finalPoint()); - //este no cambia. - end->moveto(curve_end->initialPoint()); - end->lineto(curve_end->finalPoint()); + SPCurve *nCurve = new SPCurve(); + Geom::Point startNode(0,0); + Geom::Point previousNode(0,0); + Geom::Point node(0,0); + Geom::Point pointAt1(0,0); + Geom::Point pointAt2(0,0); + Geom::Point nextPointAt1(0,0); + Geom::Point nextPointAt2(0,0); + Geom::Point nextPointAt3(0,0); + Geom::CubicBezier const *cubic = NULL; //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline if (path_it->closed()) { - SBasisIn = in->first_segment()->toSBasis(); - SBasisEnd = end->first_segment()->toSBasis(); + //Calculamos el nodo de inicio BSpline + const Geom::Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + SPCurve * end = new SPCurve(); + end->moveto(curve_endit->initialPoint()); + end->lineto(curve_endit->finalPoint()); + Geom::D2< Geom::SBasis > SBasisIn = in->first_segment()->toSBasis(); + Geom::D2< Geom::SBasis > SBasisEnd = end->first_segment()->toSBasis(); + end->reset(); + delete end; + SPCurve *lineHelper = new SPCurve(); cubic = dynamic_cast(&*curve_it1); if(cubic){ - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); + lineHelper->moveto(SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment()))); }else{ - pointAt1 = in->first_segment()->initialPoint(); + lineHelper->moveto(in->first_segment()->initialPoint()); } - cubic = dynamic_cast(&*curve_end); + cubic = dynamic_cast(&*curve_endit); if(cubic){ - endPointAt2 = SBasisEnd.valueAt(Geom::nearest_point((*cubic)[2],*end->first_segment())); + lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubic)[2],*end->first_segment()))); }else{ - endPointAt2 = end->first_segment()->finalPoint(); + lineHelper->lineto(end->first_segment()->finalPoint()); } - lineHelper->moveto(pointAt1); - lineHelper->lineto(endPointAt2); - SBasisHelper = lineHelper->first_segment()->toSBasis(); + Geom::D2< Geom::SBasis > SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); + delete lineHelper; //Guardamos el principio de la curva startNode = SBasisHelper.valueAt(0.5); //Definimos el punto de inicio original de la curva resultante @@ -131,22 +118,18 @@ LPEBSpline::doEffect(SPCurve * curve) //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida cubic = dynamic_cast(&*curve_it1); if(cubic){ - SBasisIn = in->first_segment()->toSBasis(); - pointAt0 = (*cubic)[0]; + Geom::D2< Geom::SBasis > SBasisIn = in->first_segment()->toSBasis(); pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2],*in->first_segment())); - pointAt3 = (*cubic)[3]; }else{ - pointAt0 = in->first_segment()->initialPoint(); pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); - pointAt3 = in->first_segment()->finalPoint(); } //Y hacemos lo propio con el path de salida //nextPointAt0 = curveOut.valueAt(0); cubic = dynamic_cast(&*curve_it2); if(cubic){ - SBasisOut = out->first_segment()->toSBasis(); + Geom::D2< Geom::SBasis > SBasisOut = out->first_segment()->toSBasis(); nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1],*out->first_segment())); nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2],*out->first_segment()));; nextPointAt3 = (*cubic)[3]; @@ -160,33 +143,41 @@ LPEBSpline::doEffect(SPCurve * curve) //con el punto situado en la posición 1/3 del segmento de salida //Estos dos puntos ademas estan posicionados en el lugas correspondiente de //los manejadores de la curva + SPCurve *lineHelper = new SPCurve(); lineHelper->moveto(pointAt2); lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); + Geom::D2< Geom::SBasis > SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); + delete lineHelper; //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva previousNode = node; //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); + SPCurve *curveHelper = new SPCurve(); curveHelper->moveto(previousNode); curveHelper->curveto(pointAt1, pointAt2, node); //añadimos la curva generada a la curva pricipal nCurve->append_continuous(curveHelper, 0.0625); curveHelper->reset(); + delete curveHelper; //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; - //Damos valor a el objeto para el path de entrada y el de salida in->reset(); + delete in; + SPCurve * in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); out->reset(); - if(curve_it1 != curve_end){ + delete out; + if(curve_it1 != curve_endit){ + SPCurve * out = new SPCurve(); out->moveto(curve_it2->initialPoint()); out->lineto(curve_it2->finalPoint()); } } //Aberiguamos la ultima parte de la curva correspondiente al último segmento + SPCurve *curveHelper = new SPCurve(); curveHelper->moveto(node); //Si está cerrada la curva, la cerramos sobre el valor guardado previamente //Si no finalizamos en el punto final @@ -197,26 +188,21 @@ LPEBSpline::doEffect(SPCurve * curve) } //añadimos este último segmento nCurve->append_continuous(curveHelper, 0.0625); + curveHelper->reset(); + delete curveHelper; //y cerramos la curva if (path_it->closed()) { nCurve->closepath_current(); } curve->append(nCurve,false); nCurve->reset(); + delete nCurve; //Limpiamos in->reset(); out->reset(); - end->reset(); - lineHelper->reset(); - curveHelper->reset(); + delete in; + delete out; } - delete in; - delete out; - delete end; - delete lineHelper; - delete curveHelper; - //Todo: remove? - //delete SBasisHelper; } }; //namespace LivePathEffect -- cgit v1.2.3 From b2981a3b8f54bccfa45c76f57b38c9c93808d2fc Mon Sep 17 00:00:00 2001 From: root Date: Tue, 12 Mar 2013 00:48:05 +0100 Subject: ~sub fix, double click to reset default handles and control to 10% step (bzr r11950.1.51) --- src/live_effects/lpe-bspline.cpp | 135 ++++++++++++++++++++++++++++++++++++++- src/live_effects/lpe-bspline.h | 5 +- 2 files changed, 137 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index d91f7297e..fcca38e4c 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -11,7 +11,7 @@ #include <2geom/affine.h> #include <2geom/bezier-curve.h> #include "helper/geom-curves.h" - +#include // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -21,8 +21,11 @@ namespace Inkscape { namespace LivePathEffect { LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : - Effect(lpeobject) + Effect(lpeobject),unify_weights(_("Unify weights:"), + _("Percent of the with for all poinrs"), "unify_weights", &wr, this, 33.) { + registerParameter( dynamic_cast(&unify_weights) ); + unify_weights.param_set_range(0, 100.); } LPEBSpline::~LPEBSpline() @@ -205,6 +208,134 @@ LPEBSpline::doEffect(SPCurve * curve) } } +std::vector +LPEBSpline::doEffect_path (std::vector const &path_in) +{ + Geom::PathVector const original_pathv = path_in; + SPCurve *curve = new SPCurve(); + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo + 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 + + 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 + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point previousNode(0,0); + Geom::Point node(0,0); + Geom::Point pointAt0(0,0); + Geom::Point pointAt1(0,0); + Geom::Point pointAt2(0,0); + Geom::Point pointAt3(0,0); + double pos1 = 0; + double pos2 = 0; + Geom::Point nextPointAt1(0,0); + Geom::Point nextPointAt2(0,0); + Geom::Point nextPointAt3(0,0); + Geom::D2< Geom::SBasis > SBasisIn; + Geom::D2< Geom::SBasis > SBasisOut; + Geom::D2< Geom::SBasis > SBasisHelper; + Geom::CubicBezier const *cubic = NULL; + 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(); + } + } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo BSPline + + //Recorremos todos los segmentos menos el último + while ( curve_it2 != curve_endit ) + { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida + SPCurve * in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + if(cubic){ + SBasisIn = in->first_segment()->toSBasis(); + pointAt0 = in->first_segment()->initialPoint(); + pos1 = unify_weights/100; + pos2 = 1-unify_weights/100; + pointAt1 = SBasisIn.valueAt(pos1); + pointAt2 = SBasisIn.valueAt(pos2); + pointAt3 = in->first_segment()->finalPoint(); + }else{ + pointAt0 = in->first_segment()->initialPoint(); + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + pointAt3 = in->first_segment()->finalPoint(); + } + in->reset(); + delete in; + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + SPCurve * out = new SPCurve(); + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + cubic = dynamic_cast(&*curve_it2); + if(cubic){ + SBasisOut = out->first_segment()->toSBasis(); + pos1 = unify_weights/100; + pos2 = 1-unify_weights/100; + nextPointAt1 = SBasisOut.valueAt(pos1); + nextPointAt2 = SBasisOut.valueAt(pos2); + nextPointAt3 = (*cubic)[3]; + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; + //Y este hará de final de curva + SPCurve *curveHelper = new SPCurve(); + curveHelper->moveto(pointAt0); + curveHelper->curveto(pointAt1, pointAt2, pointAt3); + //añadimos la curva generada a la curva pricipal + nCurve->append_continuous(curveHelper, 0.0625); + curveHelper->reset(); + delete curveHelper; + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + //Aberiguamos la ultima parte de la curva correspondiente al último segmento + SPCurve *curveHelper = new SPCurve(); + curveHelper->moveto(node); + //Si está cerrada la curva, la cerramos sobre el valor guardado previamente + //Si no finalizamos en el punto final + Geom::Point startNode(0,0); + startNode = path_it->begin()->initialPoint(); + curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->append_continuous(curveHelper, 0.0625); + nCurve->move_endpoints(startNode,nextPointAt3); + curveHelper->reset(); + delete curveHelper; + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); + } + curve->append(nCurve,false); + nCurve->reset(); + delete nCurve; + } + return curve->get_pathvector(); +} + }; //namespace LivePathEffect }; /* namespace Inkscape */ diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index d983a7654..27c79f040 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -8,7 +8,7 @@ */ #include "live_effects/effect.h" - +#include "live_effects/parameter/parameter.h" namespace Inkscape { namespace LivePathEffect { @@ -18,11 +18,14 @@ public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); + virtual std::vector doEffect_path (std::vector const & input_path); + virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } virtual void doEffect(SPCurve * curve); private: + ScalarParam unify_weights; LPEBSpline(const LPEBSpline&); LPEBSpline& operator=(const LPEBSpline&); }; -- cgit v1.2.3 From d0bebd018087b363bfde91bce46744dfd004549c Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 14 Mar 2013 22:28:34 +0100 Subject: Updating original path (bzr r11950.1.53) --- src/live_effects/lpe-bspline.cpp | 208 +++++++++++-------------------- src/live_effects/lpe-bspline.h | 6 + src/live_effects/parameter/parameter.cpp | 7 +- 3 files changed, 85 insertions(+), 136 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index fcca38e4c..f5dff3abe 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -34,6 +34,11 @@ LPEBSpline::~LPEBSpline() void LPEBSpline::doEffect(SPCurve * curve) +{ +LPEBSpline::doEffect(curve,NULL) +} +void +LPEBSpline::doEffect(SPCurve * curve,int value) { if(curve->get_segment_count() < 2) return; @@ -91,11 +96,21 @@ LPEBSpline::doEffect(SPCurve * curve) cubic = dynamic_cast(&*curve_it1); if(cubic){ SBasisIn = in->first_segment()->toSBasis(); - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2],*in->first_segment())); + if(value){ + pointAt1 = SBasisIn.valueAt(value); + pointAt2 = SBasisIn.valueAt(1-value); + }else{ + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); + pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2],*in->first_segment())); + } }else{ - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); + if(value){ + pointAt1 = SBasisIn.valueAt(value); + pointAt2 = SBasisIn.valueAt(1-value); + }else{ + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } } in->reset(); delete in; @@ -107,12 +122,22 @@ LPEBSpline::doEffect(SPCurve * curve) cubic = dynamic_cast(&*curve_it2); if(cubic){ SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1],*out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2],*out->first_segment()));; + if(value){ + nextPointAt1 = SBasisIn.valueAt(value); + nextPointAt2 = SBasisIn.valueAt(1-value); + }else{ + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1],*out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2],*out->first_segment()));; + ] nextPointAt3 = (*cubic)[3]; }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); + if(value){ + nextPointAt1 = SBasisIn.valueAt(value); + nextPointAt2 = SBasisIn.valueAt(1-value); + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } nextPointAt3 = out->first_segment()->finalPoint(); } out->reset(); @@ -133,8 +158,13 @@ LPEBSpline::doEffect(SPCurve * curve) //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(previousNode); - curveHelper->curveto(pointAt1, pointAt2, node); + if(value){ + curveHelper->moveto(*in->first_segment()->initialPoint()); + curveHelper->curveto(pointAt1, pointAt2, *in->first_segment()->finalPoint()); + }else{ + curveHelper->moveto(previousNode); + curveHelper->curveto(pointAt1, pointAt2, node); + } //añadimos la curva generada a la curva pricipal nCurve->append_continuous(curveHelper, 0.0625); curveHelper->reset(); @@ -181,7 +211,10 @@ LPEBSpline::doEffect(SPCurve * curve) lineHelper->reset(); delete lineHelper; //Guardamos el principio de la curva - startNode = SBasisHelper.valueAt(0.5); + if(value) + startNode = path_it->begin()->initialPoint(); + else + startNode = SBasisHelper.valueAt(0.5); curveHelper->curveto(nextPointAt1, nextPointAt2, startNode); nCurve->append_continuous(curveHelper, 0.0625); nCurve->move_endpoints(startNode,startNode); @@ -208,132 +241,37 @@ LPEBSpline::doEffect(SPCurve * curve) } } -std::vector -LPEBSpline::doEffect_path (std::vector const &path_in) +void +LPEBSpline::updateAllHandles(int value) { - Geom::PathVector const original_pathv = path_in; - SPCurve *curve = new SPCurve(); - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo - 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 - - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point previousNode(0,0); - Geom::Point node(0,0); - Geom::Point pointAt0(0,0); - Geom::Point pointAt1(0,0); - Geom::Point pointAt2(0,0); - Geom::Point pointAt3(0,0); - double pos1 = 0; - double pos2 = 0; - Geom::Point nextPointAt1(0,0); - Geom::Point nextPointAt2(0,0); - Geom::Point nextPointAt3(0,0); - Geom::D2< Geom::SBasis > SBasisIn; - Geom::D2< Geom::SBasis > SBasisOut; - Geom::D2< Geom::SBasis > SBasisHelper; - Geom::CubicBezier const *cubic = NULL; - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo BSPline - - //Recorremos todos los segmentos menos el último - while ( curve_it2 != curve_endit ) - { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - SPCurve * in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - if(cubic){ - SBasisIn = in->first_segment()->toSBasis(); - pointAt0 = in->first_segment()->initialPoint(); - pos1 = unify_weights/100; - pos2 = 1-unify_weights/100; - pointAt1 = SBasisIn.valueAt(pos1); - pointAt2 = SBasisIn.valueAt(pos2); - pointAt3 = in->first_segment()->finalPoint(); - }else{ - pointAt0 = in->first_segment()->initialPoint(); - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - pointAt3 = in->first_segment()->finalPoint(); - } - in->reset(); - delete in; - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - SPCurve * out = new SPCurve(); - out->moveto(curve_it2->initialPoint()); - out->lineto(curve_it2->finalPoint()); - cubic = dynamic_cast(&*curve_it2); - if(cubic){ - SBasisOut = out->first_segment()->toSBasis(); - pos1 = unify_weights/100; - pos2 = 1-unify_weights/100; - nextPointAt1 = SBasisOut.valueAt(pos1); - nextPointAt2 = SBasisOut.valueAt(pos2); - nextPointAt3 = (*cubic)[3]; - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //Y este hará de final de curva - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(pointAt0); - curveHelper->curveto(pointAt1, pointAt2, pointAt3); - //añadimos la curva generada a la curva pricipal - nCurve->append_continuous(curveHelper, 0.0625); - curveHelper->reset(); - delete curveHelper; - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - //Aberiguamos la ultima parte de la curva correspondiente al último segmento - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(node); - //Si está cerrada la curva, la cerramos sobre el valor guardado previamente - //Si no finalizamos en el punto final - Geom::Point startNode(0,0); - startNode = path_it->begin()->initialPoint(); - curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->append_continuous(curveHelper, 0.0625); - nCurve->move_endpoints(startNode,nextPointAt3); - curveHelper->reset(); - delete curveHelper; - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); - } - curve->append(nCurve,false); - nCurve->reset(); - delete nCurve; + SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop? + Inkscape::Selection *selection = sp_desktop_selection(desktop); + for (GSList *items = (GSList *) selection->itemList(); + items != NULL; + items = items->next) { + if (SP_IS_LPE_ITEM(items->data) && sp_lpe_item_has_path_effect(items->data)){ + PathEffectList effect_list = sp_lpe_item_get_effect_list(SP_LPE_ITEM(_path)); + lpe_bsp = dynamic_cast( effect_list.front()->lpeobject->get_lpe()); + if(lpe_bsp) + LPEBSpline::updateHandles((SPItem *) items->data,value); + } +} +void +LPEBSpline::updateHandles(SPItem * item,int value){ + + Inkscape::XML::Node *newitem = item->getRepr(); + Inkscape::XML::Node *path = sp_repr_lookup_child(newitem,"svg:path", -1); //unlimited search depth + if ( path != NULL ){ + gchar const *svgd = path->attribute("d"); } - return curve->get_pathvector(); + + SPCurve *original = new SPCurve(); + original = (SPPath *)item->original_curve(); + LPEBSpline::doEffect(original,value); + gchar *str = sp_svg_write_path( original->get_pathvector() ); + g_assert( str != NULL ); + path->setAttribute ("inkscaspe:original-d", str); + item->updateRepr(); } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 27c79f040..501b1fdaf 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -23,6 +23,12 @@ public: virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } virtual void doEffect(SPCurve * curve); + + virtual void doEffect(SPCurve * curve, int value); + + virtual void updateAllHandles(int value); + + virtual void updateHandles(SPItem * item , int value); private: ScalarParam unify_weights; diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 8615721b0..30414842d 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -128,7 +128,12 @@ ScalarParam::param_newWidget() { Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar( param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); - + //BSpline + lpe_bsp = dynamic_cast(param_effect->get_lpe()); + if(lpe_bsp){ + lpe_bsp->updateAllHandles(value/100); + } + //BSpline End rsu->setValue(value); rsu->setDigits(digits); rsu->setIncrements(inc_step, inc_page); -- cgit v1.2.3 From 732618cd7d6159ee47cc0dd8b86cf07790e3e724 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 17 Mar 2013 13:29:02 +0100 Subject: Working with widjets (bzr r11950.1.56) --- src/live_effects/lpe-bspline.cpp | 48 +++++++++++------------------- src/live_effects/lpe-bspline.h | 32 ++++++++------------ src/live_effects/lpe-recursiveskeleton.cpp | 3 +- 3 files changed, 31 insertions(+), 52 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 785c545b5..b1e40655d 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -39,13 +39,18 @@ using Inkscape::DocumentUndo; - namespace Inkscape { namespace LivePathEffect { LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject) { + Glib::ustring title = Glib::ustring(_("Ignore cusp nodes")); + Glib::ustring tip = Glib::ustring(_("Ignore cusp nodes")); + LPEBSpline::Gtk::Widget *noCusp = new LPEBSpline::newCheckButton(title,tip); + title = Glib::ustring(_("Unify weights:")); + tip = Glib::ustring(_("Percent of the with for all poinrs")); + LPEBSpline::Gtk::Widget *scal = new LPEBSpline::newScalar(title,tip); } LPEBSpline::~LPEBSpline() @@ -239,25 +244,20 @@ Gtk::Widget * LPEBSpline::newWidget() { Gtk::VBox * vbox = dynamic_cast(Effect::newWidget()); - Glib::ustring title = Glib::ustring(_("Ignore cusp nodes")); - Glib::ustring tip = Glib::ustring(_("Ignore cusp nodes")); - this->setNoCuspWidget(this->newCheckButton(title)); - title = Glib::ustring(_("Unify weights:")); - tip = Glib::ustring(_("Percent of the with for all poinrs")); - this->setScalWidget(this->newScalar(title,tip)); vbox->set_border_width(5); - vbox->pack_start(*this->getNoCuspWidget(), true, true,2); - vbox->pack_start(*this->getScalWidget(),true,true,(guint)2); + vbox->pack_start(&noCusp,true,true,(guint)2); + vbox->pack_start(&scal, true, true,2); return dynamic_cast (vbox); } Gtk::Widget * LPEBSpline::newScalar(Glib::ustring title, Glib::ustring tip) { - Inkscape::UI::Widget::Scalar * scal = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip, 2)); - scal->setRange(0.01, 100.); - scal->setIncrements(1., 5.); + scal = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip)); scal->setValue(33.); + scal->setDigits(2); + scal->setIncrements(1., 5.); + scal->setRange(0, 100.); scal->setProgrammatically = false; scal->addSlider(); scal->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::updateAllHandles)); @@ -265,20 +265,17 @@ LPEBSpline::newScalar(Glib::ustring title, Glib::ustring tip) } Gtk::Widget * -LPEBSpline::newCheckButton(Glib::ustring title) +LPEBSpline::newCheckButton(Glib::ustring title, Glib::ustring tip) { - Gtk::CheckButton * noCusp = Gtk::manage( new Gtk::CheckButton(title,true)); - noCusp->set_alignment(1.0,0.0); + noCusp = Gtk::manage( new Gtk::CheckButton(title,tip)); return dynamic_cast(noCusp); } void LPEBSpline::updateAllHandles() { - Inkscape::UI::Widget::Scalar * scal = dynamic_cast(this->getScalWidget()); - double value = scal->getValue()/100; - Gtk::CheckButton * noCusp = dynamic_cast(this->getNoCuspWidget()); - bool noCuspValue = noCusp->get_active(); + double value = scal->setValue(33.); + bool noCusp = false; SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop? Inkscape::Selection *selection = sp_desktop_selection(desktop); for (GSList *items = (GSList *) selection->itemList(); @@ -291,7 +288,7 @@ LPEBSpline::updateAllHandles() SPItem *item = (SPItem *) items->data; SPPath *path = SP_PATH(item); SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve,value,noCuspValue); + LPEBSpline::doBSplineFromWidget(curve,value,noCusp); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); g_free(str); @@ -313,8 +310,6 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); - using Geom::X; - using Geom::Y; //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { @@ -368,20 +363,16 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) if(cubic){ if(!noCusp || (*cubic)[1] != in->first_segment()->initialPoint()) pointAt1 = SBasisIn.valueAt(value); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); else pointAt1 = in->first_segment()->initialPoint(); if(!noCusp || (*cubic)[2] != in->first_segment()->finalPoint()) pointAt2 = SBasisIn.valueAt(1-value); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); else pointAt2 = in->first_segment()->finalPoint(); }else{ if(!noCusp){ pointAt1 = SBasisIn.valueAt(value); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); pointAt2 = SBasisIn.valueAt(1-value); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); @@ -400,20 +391,16 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) if(cubic){ if(!noCusp || (*cubic)[1] != out->first_segment()->initialPoint()) nextPointAt1 = SBasisOut.valueAt(value); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); else nextPointAt1 = out->first_segment()->initialPoint(); if(!noCusp || (*cubic)[2] != out->first_segment()->finalPoint()) nextPointAt2 = SBasisOut.valueAt(1-value); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); else nextPointAt2 = out->first_segment()->finalPoint(); }else{ if(!noCusp){ nextPointAt1 = SBasisOut.valueAt(value); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); nextPointAt2 = SBasisOut.valueAt(1-value); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ nextPointAt1 = out->first_segment()->initialPoint(); nextPointAt2 = out->first_segment()->finalPoint(); @@ -422,7 +409,6 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) nextPointAt3 = out->first_segment()->finalPoint(); out->reset(); delete out; - //La curva BSpline se forma calculando el centro del segmanto de unión //de el punto situado en las 2/3 partes de el segmento de entrada //con el punto situado en la posición 1/3 del segmento de salida diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index a0f1554d0..dbe0789f2 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -8,7 +8,9 @@ */ #include "live_effects/effect.h" - +#include "live_effects/parameter/parameter.h" +#include "ui/widget/scalar.h" +#include namespace Inkscape { namespace LivePathEffect { @@ -16,13 +18,6 @@ namespace LivePathEffect { class LPEBSpline : public Effect { - -private: - double scalWidget; - bool noCuspWidget; - LPEBSpline(const LPEBSpline&); - LPEBSpline& operator=(const LPEBSpline&); - public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); @@ -35,22 +30,21 @@ public: virtual void updateAllHandles(); - virtual Gtk::Widget* newScalar(Glib::ustring title, Glib::ustring tip); + virtual void newScalar(Glib::ustring title, Glib::ustring tip); + + virtual void newCheckButton(Glib::ustring title, Glib::ustring tip); - virtual Gtk::Widget* newCheckButton(Glib::ustring title); virtual void doBSplineFromWidget(SPCurve * curve, double value, bool noCusp); - virtual double getScal(){return scal;}; - - virtual double setScal(double setScal){scal = setScal;}; - - virtual bool getNoCusp(){return noCusp;}; - - virtual bool setNoCusp(bool setNoCusp){noCusp = setNoCusp;}; - - virtual Gtk::Widget* newWidget(); + virtual Gtk::Widget * newWidget(); + +private: + Gtk::Widget * scal; + Gtk::Widget * noCusp; + LPEBSpline(const LPEBSpline&); + LPEBSpline& operator=(const LPEBSpline&); }; }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp index ac571d963..452139344 100644 --- a/src/live_effects/lpe-recursiveskeleton.cpp +++ b/src/live_effects/lpe-recursiveskeleton.cpp @@ -91,8 +91,7 @@ LPERecursiveSkeleton::doEffect_pwd2 (Geom::Piecewise > co double scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); // TODO investigate why pattWidth is not being used: - // - Doesn't appear to have been used anywhere in bzr history (Alex V: 2013-03-16) - // double pattWidth = pattBndsX->extent() * scaling; + double pattWidth = pattBndsX->extent() * scaling; if (scaling != 1.0) { x*=scaling; -- cgit v1.2.3 From a5fc5840c370d58f395b7b256a11fd11ef3a9a54 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 18 Mar 2013 02:53:59 +0100 Subject: working whith widgets (bzr r11950.1.57) --- src/live_effects/lpe-bspline.cpp | 94 +++++++++++++++++++++++++++++----------- src/live_effects/lpe-bspline.h | 47 +++++++++++++++----- 2 files changed, 104 insertions(+), 37 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index b1e40655d..5d50eae87 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -31,7 +31,6 @@ #include "helper/geom-curves.h" #include "ui/widget/scalar.h" - // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -42,15 +41,20 @@ using Inkscape::DocumentUndo; namespace Inkscape { namespace LivePathEffect { + LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject) { - Glib::ustring title = Glib::ustring(_("Ignore cusp nodes")); - Glib::ustring tip = Glib::ustring(_("Ignore cusp nodes")); - LPEBSpline::Gtk::Widget *noCusp = new LPEBSpline::newCheckButton(title,tip); - title = Glib::ustring(_("Unify weights:")); - tip = Glib::ustring(_("Percent of the with for all poinrs")); - LPEBSpline::Gtk::Widget *scal = new LPEBSpline::newScalar(title,tip); + Glib::ustring title = Glib::ustring(_("Unify weights:")); + Glib::ustring tip = Glib::ustring(_("Percent of the with for all poinrs")); + registerScal(title,tip); + title = Glib::ustring(_("Ignore cusp nodes")); + registerNoCusp(title); + title = Glib::ustring(_("Reset")); + registerReset(title); + title = Glib::ustring(_("CTRL handle steps:")); + tip = Glib::ustring(_("CTRL handle steps")); + registerStepsHandles(title,tip); } LPEBSpline::~LPEBSpline() @@ -243,39 +247,79 @@ LPEBSpline::doEffect(SPCurve * curve) Gtk::Widget * LPEBSpline::newWidget() { - Gtk::VBox * vbox = dynamic_cast(Effect::newWidget()); + Gtk::VBox * vbox = Gtk::manage( dynamic_cast(LPEBSpline::newWidget())); vbox->set_border_width(5); - vbox->pack_start(&noCusp,true,true,(guint)2); - vbox->pack_start(&scal, true, true,2); + vbox->pack_start(*noCusp,true,true,2); + vbox->pack_start(*scal, true, true,2); + vbox->pack_start(*reset, true, true,2); + vbox->pack_start(*stepsHandles, true, true,2); return dynamic_cast (vbox); } Gtk::Widget * -LPEBSpline::newScalar(Glib::ustring title, Glib::ustring tip) +LPEBSpline::newScal(Glib::ustring title, Glib::ustring tip) +{ + Inkscape::UI::Widget::Scalar *scalIn = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip)); + scalIn->setRange(0, 100.); + scalIn->setDigits(2); + scalIn->setIncrements(1., 5.); + scalIn->setValue(33.33); + scalIn->setProgrammatically = false; + scalIn->addSlider(); + scalIn->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::updateAllHandles)); + return dynamic_cast(scalIn); +} + +Gtk::Widget * +LPEBSpline::newNoCusp(Glib::ustring title) +{ + Gtk::CheckButton * noCuspIn = Gtk::manage( new Gtk::CheckButton(title,true)); + noCuspIn->set_alignment(0.0, 0.5); + return dynamic_cast(noCuspIn); +} + +Gtk::Widget * +LPEBSpline::newReset(Glib::ustring title) { - scal = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip)); - scal->setValue(33.); - scal->setDigits(2); - scal->setIncrements(1., 5.); - scal->setRange(0, 100.); - scal->setProgrammatically = false; - scal->addSlider(); - scal->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::updateAllHandles)); - return dynamic_cast(scal); + Gtk::Button * resetIn = Gtk::manage(new Gtk::Button(title)); + resetIn->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::resetHandles)); + resetIn->set_alignment(0.0, 0.5); + return dynamic_cast(resetIn); } Gtk::Widget * -LPEBSpline::newCheckButton(Glib::ustring title, Glib::ustring tip) +LPEBSpline::newStepsHandles(Glib::ustring title, Glib::ustring tip) { - noCusp = Gtk::manage( new Gtk::CheckButton(title,tip)); - return dynamic_cast(noCusp); + Inkscape::UI::Widget::Scalar *stepsIn = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip)); + stepsIn->setRange(1, 10); + stepsIn->setDigits(0); + stepsIn->setIncrements(1.,1.); + stepsIn->setValue(2); + stepsIn->setProgrammatically = false; + stepsIn->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::updateSteps)); + return dynamic_cast(stepsIn); +} + +void +LPEBSpline::resetHandles(){ + Inkscape::UI::Widget::Scalar * scalIn = dynamic_cast(scal); + scalIn->setValue(33.33); + updateAllHandles(); +} + +void +LPEBSpline::updateSteps(){ + Inkscape::UI::Widget::Scalar * stepsIn = dynamic_cast(stepsHandles); + updateStepsValue(stepsIn->getValue()); } void LPEBSpline::updateAllHandles() { - double value = scal->setValue(33.); - bool noCusp = false; + Inkscape::UI::Widget::Scalar * scalIn = dynamic_cast(scal); + double value = scalIn->getValue()/100; + Gtk::CheckButton * noCuspIn = dynamic_cast(noCusp); + bool noCusp = noCuspIn->get_active(); SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop? Inkscape::Selection *selection = sp_desktop_selection(desktop); for (GSList *items = (GSList *) selection->itemList(); diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index dbe0789f2..3915a476c 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -8,16 +8,12 @@ */ #include "live_effects/effect.h" -#include "live_effects/parameter/parameter.h" -#include "ui/widget/scalar.h" -#include namespace Inkscape { namespace LivePathEffect { - - class LPEBSpline : public Effect { + public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); @@ -28,23 +24,50 @@ public: virtual void doEffect(SPCurve * curve); - virtual void updateAllHandles(); + virtual void doBSplineFromWidget(SPCurve * curve, double value, bool noCusp); - virtual void newScalar(Glib::ustring title, Glib::ustring tip); + virtual Gtk::Widget * newWidget(); - virtual void newCheckButton(Glib::ustring title, Glib::ustring tip); + int steps; +protected: - virtual void doBSplineFromWidget(SPCurve * curve, double value, bool noCusp); + Gtk::Widget* scal; - virtual Gtk::Widget * newWidget(); + Gtk::Widget* noCusp; + + Gtk::Widget* reset; + + Gtk::Widget* stepsHandles; + + virtual void registerScal(Glib::ustring title, Glib::ustring tip){scal = LPEBSpline::newScal(title,tip);}; + + virtual void registerNoCusp(Glib::ustring title){noCusp = LPEBSpline::newNoCusp(title);}; + + virtual void registerReset(Glib::ustring title){reset = LPEBSpline::newReset(title);}; + + virtual void registerStepsHandles(Glib::ustring title, Glib::ustring tip){stepsHandles = LPEBSpline::newStepsHandles(title,tip);}; + + virtual Gtk::Widget* newScal(Glib::ustring title, Glib::ustring tip); + + virtual Gtk::Widget* newNoCusp(Glib::ustring title); + + virtual Gtk::Widget* newReset(Glib::ustring title); + + virtual Gtk::Widget* newStepsHandles(Glib::ustring title, Glib::ustring tip); + + virtual void updateAllHandles(); + + virtual void resetHandles(); + + virtual void updateSteps(); + virtual void updateStepsValue(int stepsValue){steps=stepsValue;}; private: - Gtk::Widget * scal; - Gtk::Widget * noCusp; LPEBSpline(const LPEBSpline&); LPEBSpline& operator=(const LPEBSpline&); + }; }; //namespace LivePathEffect -- cgit v1.2.3 From 4e41340374ba833e748ffbbc610a28c7c3559557 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 19 Mar 2013 04:35:35 +0100 Subject: Working width widgets (bzr r11950.1.58) --- src/live_effects/lpe-bspline.cpp | 236 +++++++++++++++++++-------------------- src/live_effects/lpe-bspline.h | 49 ++------ 2 files changed, 124 insertions(+), 161 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 5d50eae87..e6461e94c 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -13,23 +13,20 @@ #include "style.h" #include "document.h" #include "document-undo.h" -#include "selection.h" -#include "desktop.h" -#include "verbs.h" #include "desktop-handles.h" -#include -#include -#include -#include +#include "verbs.h" #include "live_effects/lpe-bspline.h" -#include "live_effects/lpeobject.h" -#include "live_effects/lpeobject-reference.h" +#include +#include #include "sp-lpe-item.h" +#include "live_effects/lpeobject.h" +#include "live_effects/parameter/parameter.h" #include "display/sp-canvas.h" #include #include <2geom/bezier-curve.h> #include "helper/geom-curves.h" #include "ui/widget/scalar.h" +#include "selection.h" // For handling un-continuous paths: #include "message-stack.h" @@ -38,23 +35,29 @@ using Inkscape::DocumentUndo; + namespace Inkscape { namespace LivePathEffect { + LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : - Effect(lpeobject) + Effect(lpeobject), + // initialise your parameters here: + //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, Geom::Point(100,100)), + ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 33.33), + steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2) { - Glib::ustring title = Glib::ustring(_("Unify weights:")); - Glib::ustring tip = Glib::ustring(_("Percent of the with for all poinrs")); - registerScal(title,tip); - title = Glib::ustring(_("Ignore cusp nodes")); - registerNoCusp(title); - title = Glib::ustring(_("Reset")); - registerReset(title); - title = Glib::ustring(_("CTRL handle steps:")); - tip = Glib::ustring(_("CTRL handle steps")); - registerStepsHandles(title,tip); + registerParameter( dynamic_cast(&ignoreCusp) ); + registerParameter( dynamic_cast(&weight) ); + registerParameter( dynamic_cast(&steps) ); + weight.param_set_range(0.00, 100); + weight.param_set_increments(1., 1.); + weight.param_set_digits(2); + steps.param_set_range(1, 10); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); } LPEBSpline::~LPEBSpline() @@ -247,108 +250,81 @@ LPEBSpline::doEffect(SPCurve * curve) Gtk::Widget * LPEBSpline::newWidget() { - Gtk::VBox * vbox = Gtk::manage( dynamic_cast(LPEBSpline::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->pack_start(*noCusp,true,true,2); - vbox->pack_start(*scal, true, true,2); - vbox->pack_start(*reset, true, true,2); - vbox->pack_start(*stepsHandles, true, true,2); - return dynamic_cast (vbox); -} -Gtk::Widget * -LPEBSpline::newScal(Glib::ustring title, Glib::ustring tip) -{ - Inkscape::UI::Widget::Scalar *scalIn = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip)); - scalIn->setRange(0, 100.); - scalIn->setDigits(2); - scalIn->setIncrements(1., 5.); - scalIn->setValue(33.33); - scalIn->setProgrammatically = false; - scalIn->addSlider(); - scalIn->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::updateAllHandles)); - return dynamic_cast(scalIn); -} + Gtk::Button* defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); + defaultWeight->set_alignment(0.0, 0.5); + Gtk::Widget* defaultWeightWidget = dynamic_cast(defaultWeight); + defaultWeight->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::toDefaultWeight)); + vbox->pack_start(*defaultWeightWidget, true, true,2); -Gtk::Widget * -LPEBSpline::newNoCusp(Glib::ustring title) -{ - Gtk::CheckButton * noCuspIn = Gtk::manage( new Gtk::CheckButton(title,true)); - noCuspIn->set_alignment(0.0, 0.5); - return dynamic_cast(noCuspIn); -} - -Gtk::Widget * -LPEBSpline::newReset(Glib::ustring title) -{ - Gtk::Button * resetIn = Gtk::manage(new Gtk::Button(title)); - resetIn->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::resetHandles)); - resetIn->set_alignment(0.0, 0.5); - return dynamic_cast(resetIn); -} + std::vector::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter * param = *it; + Gtk::Widget * widg = param->param_newWidget(); + if(param->param_key == "weight"){ + Inkscape::UI::Widget::Scalar * widgRegistered = dynamic_cast(widg); + widgRegistered->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::toWeight)); + } + 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); + } + } + } -Gtk::Widget * -LPEBSpline::newStepsHandles(Glib::ustring title, Glib::ustring tip) -{ - Inkscape::UI::Widget::Scalar *stepsIn = Gtk::manage( new Inkscape::UI::Widget::Scalar(title, tip)); - stepsIn->setRange(1, 10); - stepsIn->setDigits(0); - stepsIn->setIncrements(1.,1.); - stepsIn->setValue(2); - stepsIn->setProgrammatically = false; - stepsIn->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::updateSteps)); - return dynamic_cast(stepsIn); + ++it; + } + return dynamic_cast(vbox); } -void -LPEBSpline::resetHandles(){ - Inkscape::UI::Widget::Scalar * scalIn = dynamic_cast(scal); - scalIn->setValue(33.33); - updateAllHandles(); +void +LPEBSpline::toDefaultWeight(){ +double weightValue = 0.3333; +changeWeight(weightValue); +weight.param_set_value(33.33); +gtk_widget_draw(GTK_WIDGET(LPEBSpline::newWidget()), NULL); } -void -LPEBSpline::updateSteps(){ - Inkscape::UI::Widget::Scalar * stepsIn = dynamic_cast(stepsHandles); - updateStepsValue(stepsIn->getValue()); +void +LPEBSpline::toWeight(){ +double weightValue = weight/100; +changeWeight(weightValue); } void -LPEBSpline::updateAllHandles() +LPEBSpline::changeWeight(double weightValue) { - Inkscape::UI::Widget::Scalar * scalIn = dynamic_cast(scal); - double value = scalIn->getValue()/100; - Gtk::CheckButton * noCuspIn = dynamic_cast(noCusp); - bool noCusp = noCuspIn->get_active(); - SPDesktop *desktop = inkscape_active_desktop(); // TODO: Is there a better method to find the item's desktop? + SPDesktop *desktop = inkscape_active_desktop(); Inkscape::Selection *selection = sp_desktop_selection(desktop); - for (GSList *items = (GSList *) selection->itemList(); - items != NULL; - items = items->next) { - if (SP_IS_LPE_ITEM((SPLPEItem *)items->data) && sp_lpe_item_has_path_effect((SPLPEItem *)items->data)){ - LivePathEffect::LPEBSpline *lpe_bsp = NULL; - lpe_bsp = dynamic_cast(sp_lpe_item_has_path_effect_of_type(SP_LPE_ITEM((SPLPEItem *)items->data),Inkscape::LivePathEffect::BSPLINE)->getLPEObj()->get_lpe()); - if(lpe_bsp){ - SPItem *item = (SPItem *) items->data; - SPPath *path = SP_PATH(item); - SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve,value,noCusp); - gchar *str = sp_svg_write_path(curve->get_pathvector()); - path->getRepr()->setAttribute("inkscape:original-d", str); - g_free(str); - curve->unref(); - SPDesktop *desktop = inkscape_active_desktop(); - desktop->clearWaitingCursor(); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, - _("Modified the weight of the BSpline")); - } - } - } + GSList *items = (GSList *) selection->itemList(); + SPItem *item = (SPItem *)g_slist_nth(items,0)->data; + SPPath *path = SP_PATH(item); + SPCurve *curve = path->get_curve_for_edit(); + LPEBSpline::doBSplineFromWidget(curve,weightValue,ignoreCusp); + gchar *str = sp_svg_write_path(curve->get_pathvector()); + path->getRepr()->setAttribute("inkscape:original-d", str); + g_free(str); + curve->unref(); + desktop->clearWaitingCursor(); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, + _("Modified the weight of the BSpline")); } void -LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) +LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignoreCusp) { + using Geom::X; + using Geom::Y; if(curve->get_segment_count() < 2) return; // Make copy of old path as it is changed during processing @@ -404,19 +380,25 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) cubic = dynamic_cast(&*curve_it1); pointAt0 = in->first_segment()->initialPoint(); SBasisIn = in->first_segment()->toSBasis(); - if(cubic){ - if(!noCusp || (*cubic)[1] != in->first_segment()->initialPoint()) - pointAt1 = SBasisIn.valueAt(value); - else + if(cubic){ + if(!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())){ + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + }else{ pointAt1 = in->first_segment()->initialPoint(); - if(!noCusp || (*cubic)[2] != in->first_segment()->finalPoint()) - pointAt2 = SBasisIn.valueAt(1-value); - else + } + if(!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())){ + pointAt2 = SBasisIn.valueAt(1-weightValue); + pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + }else{ pointAt2 = in->first_segment()->finalPoint(); + } }else{ - if(!noCusp){ - pointAt1 = SBasisIn.valueAt(value); - pointAt2 = SBasisIn.valueAt(1-value); + if(!ignoreCusp){ + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + pointAt2 = SBasisIn.valueAt(1-weightValue); + pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); @@ -433,18 +415,24 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double value , bool noCusp) SBasisOut = out->first_segment()->toSBasis(); cubic = dynamic_cast(&*curve_it2); if(cubic){ - if(!noCusp || (*cubic)[1] != out->first_segment()->initialPoint()) - nextPointAt1 = SBasisOut.valueAt(value); - else + if(!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint())){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + }else{ nextPointAt1 = out->first_segment()->initialPoint(); - if(!noCusp || (*cubic)[2] != out->first_segment()->finalPoint()) - nextPointAt2 = SBasisOut.valueAt(1-value); - else + } + if(!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint())){ + nextPointAt2 = SBasisOut.valueAt(1-weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + }else{ nextPointAt2 = out->first_segment()->finalPoint(); + } }else{ - if(!noCusp){ - nextPointAt1 = SBasisOut.valueAt(value); - nextPointAt2 = SBasisOut.valueAt(1-value); + if(!ignoreCusp){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + nextPointAt2 = SBasisOut.valueAt(1-weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ nextPointAt1 = out->first_segment()->initialPoint(); nextPointAt2 = out->first_segment()->finalPoint(); diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 3915a476c..10d157ac1 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -8,12 +8,20 @@ */ #include "live_effects/effect.h" +#include "live_effects/parameter/bool.h" namespace Inkscape { namespace LivePathEffect { class LPEBSpline : public Effect { +private: + BoolParam ignoreCusp; + ScalarParam weight; + + LPEBSpline(const LPEBSpline&); + LPEBSpline& operator=(const LPEBSpline&); + public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); @@ -28,49 +36,16 @@ public: virtual Gtk::Widget * newWidget(); - int steps; - -protected: - - Gtk::Widget* scal; - - Gtk::Widget* noCusp; - - Gtk::Widget* reset; - - Gtk::Widget* stepsHandles; - - virtual void registerScal(Glib::ustring title, Glib::ustring tip){scal = LPEBSpline::newScal(title,tip);}; + virtual void changeWeight(double weightValue); - virtual void registerNoCusp(Glib::ustring title){noCusp = LPEBSpline::newNoCusp(title);}; + virtual void toDefaultWeight(); - virtual void registerReset(Glib::ustring title){reset = LPEBSpline::newReset(title);}; + virtual void toWeight(); - virtual void registerStepsHandles(Glib::ustring title, Glib::ustring tip){stepsHandles = LPEBSpline::newStepsHandles(title,tip);}; + ScalarParam steps; - virtual Gtk::Widget* newScal(Glib::ustring title, Glib::ustring tip); - - virtual Gtk::Widget* newNoCusp(Glib::ustring title); - - virtual Gtk::Widget* newReset(Glib::ustring title); - - virtual Gtk::Widget* newStepsHandles(Glib::ustring title, Glib::ustring tip); - - virtual void updateAllHandles(); - - virtual void resetHandles(); - - virtual void updateSteps(); - - virtual void updateStepsValue(int stepsValue){steps=stepsValue;}; - -private: - LPEBSpline(const LPEBSpline&); - LPEBSpline& operator=(const LPEBSpline&); - }; }; //namespace LivePathEffect }; //namespace Inkscape - #endif -- cgit v1.2.3 From fc95705f9d5761fe111a445c51afc505d08738a7 Mon Sep 17 00:00:00 2001 From: jtx Date: Tue, 19 Mar 2013 17:56:26 +0100 Subject: Fixing regression (bzr r11950.1.61) --- src/live_effects/lpe-recursiveskeleton.cpp | 3 ++- src/live_effects/parameter/parameter.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp index 452139344..ac571d963 100644 --- a/src/live_effects/lpe-recursiveskeleton.cpp +++ b/src/live_effects/lpe-recursiveskeleton.cpp @@ -91,7 +91,8 @@ LPERecursiveSkeleton::doEffect_pwd2 (Geom::Piecewise > co double scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); // TODO investigate why pattWidth is not being used: - double pattWidth = pattBndsX->extent() * scaling; + // - Doesn't appear to have been used anywhere in bzr history (Alex V: 2013-03-16) + // double pattWidth = pattBndsX->extent() * scaling; if (scaling != 1.0) { x*=scaling; diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 7e155cb92..8615721b0 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -5,7 +5,7 @@ */ #include -#include "live_effects/lpe-bspline.h" + #include "live_effects/parameter/parameter.h" #include "live_effects/effect.h" #include "svg/svg.h" @@ -128,6 +128,7 @@ ScalarParam::param_newWidget() { Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar( param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); + rsu->setValue(value); rsu->setDigits(digits); rsu->setIncrements(inc_step, inc_page); -- cgit v1.2.3 From b887e821e03cae71b2116d58e64efb62eb9be0be Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 20 Mar 2013 01:47:49 +0100 Subject: For testing, widget added, regression fixed (bzr r11950.1.62) --- src/live_effects/lpe-bspline.cpp | 35 ++++++++++++++++++++++++----------- src/live_effects/lpe-bspline.h | 18 +++++++++--------- 2 files changed, 33 insertions(+), 20 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index e6461e94c..d3c64bb67 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -11,6 +11,7 @@ #include #include "sp-path.h" #include "style.h" +#include "document-private.h" #include "document.h" #include "document-undo.h" #include "desktop-handles.h" @@ -45,9 +46,9 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, Geom::Point(100,100)), + steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 33.33), - steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2) + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 33.33) { registerParameter( dynamic_cast(&ignoreCusp) ); registerParameter( dynamic_cast(&weight) ); @@ -64,11 +65,24 @@ LPEBSpline::~LPEBSpline() { } -void -LPEBSpline::doOnApply(SPLPEItem const* lpeitem) +void +LPEBSpline::createAndApply(const char* name, SPDocument *doc, SPItem *item) { - if (!SP_IS_SHAPE(lpeitem)) { + if (!SP_IS_SHAPE(item)) { g_warning("LPE BSpline can only be applied to shapes (not groups)."); + }else{ + // Path effect definition + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); + repr->setAttribute("effect", name); + + doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to and assigns the 'id' attribute + const gchar * repr_id = repr->attribute("id"); + Inkscape::GC::release(repr); + + gchar *href = g_strdup_printf("#%s", repr_id); + sp_lpe_item_add_path_effect(SP_LPE_ITEM(item), href, true); + g_free(href); } } @@ -289,16 +303,15 @@ LPEBSpline::newWidget() void LPEBSpline::toDefaultWeight(){ -double weightValue = 0.3333; -changeWeight(weightValue); -weight.param_set_value(33.33); -gtk_widget_draw(GTK_WIDGET(LPEBSpline::newWidget()), NULL); + double weightValue = 0.3334; + weight.param_set_value(33.33); + changeWeight(weightValue); } void LPEBSpline::toWeight(){ -double weightValue = weight/100; -changeWeight(weightValue); + double weightValue = weight/100; + changeWeight(weightValue); } void diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 10d157ac1..44c3f451c 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -15,20 +15,13 @@ namespace LivePathEffect { class LPEBSpline : public Effect { -private: - BoolParam ignoreCusp; - ScalarParam weight; - - LPEBSpline(const LPEBSpline&); - LPEBSpline& operator=(const LPEBSpline&); - public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); - virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } + virtual void createAndApply(const char* name, SPDocument *doc, SPItem *item); - virtual void doOnApply(SPLPEItem const* lpeitem); + virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } virtual void doEffect(SPCurve * curve); @@ -44,6 +37,13 @@ public: ScalarParam steps; +private: + BoolParam ignoreCusp; + ScalarParam weight; + + LPEBSpline(const LPEBSpline&); + LPEBSpline& operator=(const LPEBSpline&); + }; }; //namespace LivePathEffect -- cgit v1.2.3 From d142ebe8740c40922c1a6aa423ca4e0e7d2335d6 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 22 Mar 2013 01:50:18 +0100 Subject: Fixed end extremium node delete fault, ready for testing (bzr r11950.1.66) --- src/live_effects/lpe-bspline.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 44c3f451c..20012f894 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -38,6 +38,7 @@ public: ScalarParam steps; private: + BoolParam ignoreCusp; ScalarParam weight; -- cgit v1.2.3 From 37d99686ec9b0a49c1ef07483967571da674e65e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 23 Mar 2013 20:09:28 +0100 Subject: Fix weight 0 by widget now give a full cusp node (bzr r11950.1.70) --- src/live_effects/lpe-bspline.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 0a13c17b2..ee771a54e 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -399,20 +399,20 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignor pointAt0 = in->first_segment()->initialPoint(); SBasisIn = in->first_segment()->toSBasis(); if(cubic){ - if(!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())){ + if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); }else{ pointAt1 = in->first_segment()->initialPoint(); } - if(!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())){ + if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ pointAt2 = SBasisIn.valueAt(1-weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt2 = in->first_segment()->finalPoint(); } }else{ - if(!ignoreCusp){ + if(!ignoreCusp && weightValue !=0){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); pointAt2 = SBasisIn.valueAt(1-weightValue); @@ -433,20 +433,20 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignor SBasisOut = out->first_segment()->toSBasis(); cubic = dynamic_cast(&*curve_it2); if(cubic){ - if(!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint())){ + if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()))&& weightValue !=0){ nextPointAt1 = SBasisOut.valueAt(weightValue); nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); }else{ nextPointAt1 = out->first_segment()->initialPoint(); } - if(!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint())){ + if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint()))&& weightValue !=0){ nextPointAt2 = SBasisOut.valueAt(1-weightValue); nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ nextPointAt2 = out->first_segment()->finalPoint(); } }else{ - if(!ignoreCusp){ + if(!ignoreCusp && weightValue !=0){ nextPointAt1 = SBasisOut.valueAt(weightValue); nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); nextPointAt2 = SBasisOut.valueAt(1-weightValue); -- cgit v1.2.3 From a7ced41f3fa6933d0da0151ef42e82e0862581fb Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 1 Apr 2013 01:09:52 +0200 Subject: Fix scale and rotate some nodes (bzr r11950.1.78) --- src/live_effects/lpe-bspline.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index ee771a54e..37d6a86a5 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -29,6 +29,7 @@ #include "ui/widget/scalar.h" #include "selection.h" #include "gtkmm/checkbutton.h" +#include "ui/tool/node.h" // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -337,15 +338,34 @@ LPEBSpline::changeWeight(double weightValue) DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, _("Modified the weight of the BSpline")); } - +//bool +//LPEBspline::selectedPoint(Geom::Point p){ +// for (SubpathList::iterator i = NodeIterator.begin(); i != NodeIterator.end(); ++i) { +// if (i->selected() && i.ptr()->getPosition() == p) { +// return true; +// } +// } +// return false; +//} +//bool +//LPEBspline::hasNodesSelected(){ +// for (SubpathList::iterator i = NodeIterator.begin(); i != NodeIterator.end(); ++i) { +// if (i->selected() && i.ptr()->getPosition() == p) { +// return true; +// } +// } +// return false; +//} void LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignoreCusp) { using Geom::X; using Geom::Y; + //bool hasNodesSelected = LPEBspline::hasNodesSelected(); if(curve->get_segment_count() < 2) return; // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); -- cgit v1.2.3 From 0b6a723f67700368d3585fc9b8009a3db30b5473 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 4 Apr 2013 19:34:41 +0200 Subject: Changing width only to selected nodes (bzr r11950.1.81) --- src/live_effects/lpe-bspline.cpp | 282 ++++++++++++++++++++++++++++----------- src/live_effects/lpe-bspline.h | 9 +- 2 files changed, 214 insertions(+), 77 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 37d6a86a5..389c11a23 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -3,12 +3,25 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include "xml/repr.h" -#include "svg/svg.h" -#include "display/curve.h" +#include +#include +#include #include #include +#include "display/curve.h" +#include <2geom/bezier-curve.h> +#include "helper/geom-curves.h" +#include "live_effects/lpe-bspline.h" +#include "live_effects/lpeobject.h" +#include "live_effects/parameter/parameter.h" +#include "ui/widget/scalar.h" +#include "ui/tool/node.h" +#include "ui/tool/node-tool.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/selectable-control-point.h" +#include "selection.h" +#include "xml/repr.h" +#include "svg/svg.h" #include "sp-path.h" #include "style.h" #include "document-private.h" @@ -16,20 +29,10 @@ #include "document-undo.h" #include "desktop-handles.h" #include "verbs.h" -#include "live_effects/lpe-bspline.h" -#include -#include #include "sp-lpe-item.h" -#include "live_effects/lpeobject.h" -#include "live_effects/parameter/parameter.h" #include "display/sp-canvas.h" #include -#include <2geom/bezier-curve.h> -#include "helper/geom-curves.h" -#include "ui/widget/scalar.h" -#include "selection.h" -#include "gtkmm/checkbutton.h" -#include "ui/tool/node.h" +#include // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -49,9 +52,11 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, Geom::Point(100,100)), steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), + onlySelected(_("Change only selected nodes:"), _("Change only selected nodes"), "onlySelected", &wr, this, false), weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 0.3334) { registerParameter( dynamic_cast(&ignoreCusp) ); + registerParameter( dynamic_cast(&onlySelected) ); registerParameter( dynamic_cast(&weight) ); registerParameter( dynamic_cast(&steps) ); weight.param_set_range(0.0000, 1); @@ -279,6 +284,10 @@ LPEBSpline::newWidget() widgRegistered->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::toWeight)); widg = dynamic_cast(widgRegistered); } + if(param->param_key == "onlySelected"){ + Gtk::CheckButton * widgRegistered = Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } if(param->param_key == "ignoreCusp"){ Gtk::CheckButton * widgRegistered = Gtk::manage(dynamic_cast(widg)); widg = dynamic_cast(widgRegistered); @@ -307,7 +316,7 @@ LPEBSpline::newWidget() void LPEBSpline::toDefaultWeight(){ - Gtk::Widget * widg = dynamic_cast(param_vector[2]->param_newWidget()); + Gtk::Widget * widg = dynamic_cast(param_vector[3]->param_newWidget()); Inkscape::UI::Widget::Scalar * widgRegistered = Gtk::manage(dynamic_cast(widg)); widgRegistered->setValue(0.3334); widgRegistered->update(); @@ -329,7 +338,7 @@ LPEBSpline::changeWeight(double weightValue) SPItem *item = (SPItem *)g_slist_nth(items,0)->data; SPPath *path = SP_PATH(item); SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve,weightValue,ignoreCusp); + LPEBSpline::doBSplineFromWidget(curve,weightValue); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); g_free(str); @@ -338,34 +347,42 @@ LPEBSpline::changeWeight(double weightValue) DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, _("Modified the weight of the BSpline")); } -//bool -//LPEBspline::selectedPoint(Geom::Point p){ -// for (SubpathList::iterator i = NodeIterator.begin(); i != NodeIterator.end(); ++i) { -// if (i->selected() && i.ptr()->getPosition() == p) { -// return true; -// } -// } -// return false; -//} -//bool -//LPEBspline::hasNodesSelected(){ -// for (SubpathList::iterator i = NodeIterator.begin(); i != NodeIterator.end(); ++i) { -// if (i->selected() && i.ptr()->getPosition() == p) { -// return true; -// } -// } -// return false; -//} + +bool +LPEBSpline::nodeIsSelected(Geom::Point nodePoint, int index){ + volatile int index2 = index; + volatile Geom::Point aa = nodePoint; + volatile std::vector x2 = points; + if(points.size() > 0){ + volatile double dist = Geom::distance(points[index], nodePoint); + if(dist == 0 ){ + return true; + } + } + return false; +} + void -LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignoreCusp) +LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) { using Geom::X; using Geom::Y; + SPDesktop *desktop = inkscape_active_desktop(); + if(INK_IS_NODE_TOOL(desktop->event_context)){ + InkNodeTool *nt = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); + points.clear(); + for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i){ + if ((*i)->selected()) { + Inkscape::UI::Node *n = static_cast(*i); + points.push_back(n->position()); + } + } + } //bool hasNodesSelected = LPEBspline::hasNodesSelected(); if(curve->get_segment_count() < 2) return; // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); @@ -388,12 +405,14 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignor Geom::Point pointAt1(0,0); Geom::Point pointAt2(0,0); Geom::Point pointAt3(0,0); + Geom::Point nextPointAt0(0,0); Geom::Point nextPointAt1(0,0); Geom::Point nextPointAt2(0,0); Geom::Point nextPointAt3(0,0); Geom::D2< Geom::SBasis > SBasisIn; Geom::D2< Geom::SBasis > SBasisOut; Geom::CubicBezier const *cubic = NULL; + int i = 0; 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. @@ -417,32 +436,88 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignor in->lineto(curve_it1->finalPoint()); cubic = dynamic_cast(&*curve_it1); pointAt0 = in->first_segment()->initialPoint(); + pointAt3 = in->first_segment()->finalPoint(); SBasisIn = in->first_segment()->toSBasis(); - if(cubic){ - if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ - pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + if(!onlySelected){ + if(cubic){ + if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + }else{ + pointAt1 = in->first_segment()->initialPoint(); + } + if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ + pointAt2 = SBasisIn.valueAt(1-weightValue); + pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ - pointAt1 = in->first_segment()->initialPoint(); - } - if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ - pointAt2 = SBasisIn.valueAt(1-weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); - }else{ - pointAt2 = in->first_segment()->finalPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + }else{ + if(!ignoreCusp && weightValue !=0){ + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + pointAt2 = SBasisIn.valueAt(1-weightValue); + pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + }else{ + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } } }else{ - if(!ignoreCusp && weightValue !=0){ - pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); - pointAt2 = SBasisIn.valueAt(1-weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + if(cubic){ + if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ + if(nodeIsSelected(pointAt0,i)){ + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + }else{ + pointAt1 = (*cubic)[1]; + } + }else{ + if(nodeIsSelected(pointAt0,i)){ + pointAt1 = in->first_segment()->initialPoint(); + }else{ + pointAt1 = (*cubic)[1]; + } + } + i++; + if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ + if(nodeIsSelected(pointAt3,i)){ + pointAt2 = SBasisIn.valueAt(1-weightValue); + pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + }else{ + pointAt2 = (*cubic)[2]; + i--; + } + }else{ + if(nodeIsSelected(pointAt3,i)){ + pointAt2 = in->first_segment()->finalPoint(); + }else{ + pointAt2 = (*cubic)[2]; + i--; + } + } }else{ - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); + if(!ignoreCusp && weightValue !=0){ + if(nodeIsSelected(pointAt0,i)){ + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + }else{ + pointAt1 = in->first_segment()->initialPoint(); + } + i++; + if(nodeIsSelected(pointAt3,i)){ + pointAt2 = SBasisIn.valueAt(weightValue); + pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + }else{ + pointAt2 = in->first_segment()->finalPoint(); + i--; + } + }else{ + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } } } - pointAt3 = in->first_segment()->finalPoint(); in->reset(); delete in; //Y hacemos lo propio con el path de salida @@ -451,32 +526,89 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue , bool ignor out->moveto(curve_it2->initialPoint()); out->lineto(curve_it2->finalPoint()); SBasisOut = out->first_segment()->toSBasis(); + nextPointAt0 = out->first_segment()->initialPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); cubic = dynamic_cast(&*curve_it2); - if(cubic){ - if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()))&& weightValue !=0){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + if(!onlySelected){ + if(cubic){ + if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()))&& weightValue !=0){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + } + if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint()))&& weightValue !=0){ + nextPointAt2 = SBasisOut.valueAt(1-weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + }else{ + nextPointAt2 = out->first_segment()->finalPoint(); + } }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - } - if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint()))&& weightValue !=0){ - nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); - }else{ - nextPointAt2 = out->first_segment()->finalPoint(); + if(!ignoreCusp && weightValue !=0){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + nextPointAt2 = SBasisOut.valueAt(1-weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } } }else{ - if(!ignoreCusp && weightValue !=0){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); - nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + if(cubic){ + if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint())) && weightValue !=0){ + if(nodeIsSelected(nextPointAt0,i)){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + }else{ + nextPointAt1 = (*cubic)[1]; + } + }else{ + if(nodeIsSelected(nextPointAt0,i)){ + nextPointAt1 = out->first_segment()->initialPoint(); + }else{ + nextPointAt1 = (*cubic)[1]; + } + } + i++; + if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint())) && weightValue !=0){ + if(nodeIsSelected(nextPointAt3,i)){ + nextPointAt2 = SBasisOut.valueAt(1-weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + }else{ + nextPointAt2 = (*cubic)[2]; + i--; + } + }else{ + if(nodeIsSelected(nextPointAt3,i)){ + nextPointAt2 = out->first_segment()->finalPoint(); + }else{ + nextPointAt2 = (*cubic)[2]; + i--; + } + } }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); + if(!ignoreCusp && weightValue !=0){ + if(nodeIsSelected(nextPointAt0,i)){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + } + i++; + if(nodeIsSelected(nextPointAt3,i)){ + nextPointAt2 = SBasisOut.valueAt(weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + }else{ + nextPointAt2 = out->first_segment()->finalPoint(); + i--; + } + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } } } - nextPointAt3 = out->first_segment()->finalPoint(); out->reset(); delete out; //La curva BSpline se forma calculando el centro del segmanto de unión diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 20012f894..2361c10d0 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -9,6 +9,8 @@ #include "live_effects/effect.h" #include "live_effects/parameter/bool.h" +#include + namespace Inkscape { namespace LivePathEffect { @@ -25,7 +27,9 @@ public: virtual void doEffect(SPCurve * curve); - virtual void doBSplineFromWidget(SPCurve * curve, double value, bool noCusp); + virtual void doBSplineFromWidget(SPCurve * curve, double value); + + virtual bool nodeIsSelected(Geom::Point nodePoint, int index); virtual Gtk::Widget * newWidget(); @@ -38,8 +42,9 @@ public: ScalarParam steps; private: - + std::vector points; BoolParam ignoreCusp; + BoolParam onlySelected; ScalarParam weight; LPEBSpline(const LPEBSpline&); -- cgit v1.2.3 From 30858428c74d1fa0f119f40b99fa5e51836d8599 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 8 Apr 2013 00:50:31 +0200 Subject: Change width only for selected nodes by widget (bzr r11950.1.83) --- src/live_effects/lpe-bspline.cpp | 46 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 389c11a23..e93fd62d2 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -10,6 +10,7 @@ #include #include "display/curve.h" #include <2geom/bezier-curve.h> +#include <2geom/point.h> #include "helper/geom-curves.h" #include "live_effects/lpe-bspline.h" #include "live_effects/lpeobject.h" @@ -341,6 +342,10 @@ LPEBSpline::changeWeight(double weightValue) LPEBSpline::doBSplineFromWidget(curve,weightValue); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); + if(INK_IS_NODE_TOOL(desktop->event_context)){ + InkNodeTool *nt = INK_NODE_TOOL(desktop->event_context); + nt->desktop->updateNow(); + } g_free(str); curve->unref(); desktop->clearWaitingCursor(); @@ -350,12 +355,8 @@ LPEBSpline::changeWeight(double weightValue) bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint, int index){ - volatile int index2 = index; - volatile Geom::Point aa = nodePoint; - volatile std::vector x2 = points; if(points.size() > 0){ - volatile double dist = Geom::distance(points[index], nodePoint); - if(dist == 0 ){ + if(Geom::are_near(points[index], nodePoint)){ return true; } } @@ -373,9 +374,12 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); points.clear(); for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i){ - if ((*i)->selected()) { - Inkscape::UI::Node *n = static_cast(*i); - points.push_back(n->position()); + if(onlySelected){ + if ((*i)->selected()) { + Inkscape::UI::Node *n = static_cast(*i); + n->bsplineWeight = weightValue; + points.insert(points.begin(),desktop->doc2dt(n->position())); + } } } } @@ -469,31 +473,30 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) if(nodeIsSelected(pointAt0,i)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + i++; }else{ pointAt1 = (*cubic)[1]; } }else{ if(nodeIsSelected(pointAt0,i)){ pointAt1 = in->first_segment()->initialPoint(); + i++; }else{ pointAt1 = (*cubic)[1]; } } - i++; if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ if(nodeIsSelected(pointAt3,i)){ pointAt2 = SBasisIn.valueAt(1-weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt2 = (*cubic)[2]; - i--; } }else{ if(nodeIsSelected(pointAt3,i)){ pointAt2 = in->first_segment()->finalPoint(); }else{ pointAt2 = (*cubic)[2]; - i--; } } }else{ @@ -501,20 +504,22 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) if(nodeIsSelected(pointAt0,i)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + i++; }else{ pointAt1 = in->first_segment()->initialPoint(); } - i++; if(nodeIsSelected(pointAt3,i)){ pointAt2 = SBasisIn.valueAt(weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt2 = in->first_segment()->finalPoint(); - i--; } }else{ pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); + if(nodeIsSelected(pointAt0,i)){ + i++; + } } } } @@ -560,51 +565,50 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) if(nodeIsSelected(nextPointAt0,i)){ nextPointAt1 = SBasisOut.valueAt(weightValue); nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + if (path_it->closed()) i++; }else{ nextPointAt1 = (*cubic)[1]; } }else{ if(nodeIsSelected(nextPointAt0,i)){ - nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt1 = out->first_segment()->initialPoint(); + if (path_it->closed()) i++; }else{ nextPointAt1 = (*cubic)[1]; } } - i++; if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint())) && weightValue !=0){ if(nodeIsSelected(nextPointAt3,i)){ nextPointAt2 = SBasisOut.valueAt(1-weightValue); nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ nextPointAt2 = (*cubic)[2]; - i--; - } + } }else{ if(nodeIsSelected(nextPointAt3,i)){ nextPointAt2 = out->first_segment()->finalPoint(); }else{ nextPointAt2 = (*cubic)[2]; - i--; - } + } } }else{ if(!ignoreCusp && weightValue !=0){ if(nodeIsSelected(nextPointAt0,i)){ nextPointAt1 = SBasisOut.valueAt(weightValue); nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + if (path_it->closed()) i++; }else{ nextPointAt1 = out->first_segment()->initialPoint(); } - i++; if(nodeIsSelected(nextPointAt3,i)){ nextPointAt2 = SBasisOut.valueAt(weightValue); nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ nextPointAt2 = out->first_segment()->finalPoint(); - i--; } }else{ nextPointAt1 = out->first_segment()->initialPoint(); + if (path_it->closed()&&nodeIsSelected(nextPointAt0,i)) i++; nextPointAt2 = out->first_segment()->finalPoint(); } } -- cgit v1.2.3 From d2e58f51d29c5da3f82d29883c0a07ce9573f8ca Mon Sep 17 00:00:00 2001 From: root Date: Wed, 10 Apr 2013 06:08:17 +0200 Subject: fixing error moving selected nodes (bzr r11950.1.86) --- src/live_effects/lpe-bspline.cpp | 102 +++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 52 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index e93fd62d2..657b2ded3 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -374,13 +374,10 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); points.clear(); for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i){ - if(onlySelected){ if ((*i)->selected()) { Inkscape::UI::Node *n = static_cast(*i); - n->bsplineWeight = weightValue; points.insert(points.begin(),desktop->doc2dt(n->position())); } - } } } //bool hasNodesSelected = LPEBspline::hasNodesSelected(); @@ -416,7 +413,7 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) Geom::D2< Geom::SBasis > SBasisIn; Geom::D2< Geom::SBasis > SBasisOut; Geom::CubicBezier const *cubic = NULL; - int i = 0; + int j = 0; 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. @@ -470,30 +467,30 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) }else{ if(cubic){ if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ - if(nodeIsSelected(pointAt0,i)){ + if(nodeIsSelected(pointAt0,j)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); - i++; + j++; }else{ pointAt1 = (*cubic)[1]; } }else{ - if(nodeIsSelected(pointAt0,i)){ + if(nodeIsSelected(pointAt0,j)){ pointAt1 = in->first_segment()->initialPoint(); - i++; + j++; }else{ pointAt1 = (*cubic)[1]; } } if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ - if(nodeIsSelected(pointAt3,i)){ + if(nodeIsSelected(pointAt3,j)){ pointAt2 = SBasisIn.valueAt(1-weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt2 = (*cubic)[2]; } }else{ - if(nodeIsSelected(pointAt3,i)){ + if(nodeIsSelected(pointAt3,j)){ pointAt2 = in->first_segment()->finalPoint(); }else{ pointAt2 = (*cubic)[2]; @@ -501,14 +498,14 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) } }else{ if(!ignoreCusp && weightValue !=0){ - if(nodeIsSelected(pointAt0,i)){ + if(nodeIsSelected(pointAt0,j)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); - i++; + j++; }else{ pointAt1 = in->first_segment()->initialPoint(); } - if(nodeIsSelected(pointAt3,i)){ + if(nodeIsSelected(pointAt3,j)){ pointAt2 = SBasisIn.valueAt(weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ @@ -517,24 +514,42 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) }else{ pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); - if(nodeIsSelected(pointAt0,i)){ - i++; + if(nodeIsSelected(pointAt0,j)){ + j++; } } } } in->reset(); delete in; - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - SPCurve * out = new SPCurve(); - out->moveto(curve_it2->initialPoint()); - out->lineto(curve_it2->finalPoint()); - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt0 = out->first_segment()->initialPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - cubic = dynamic_cast(&*curve_it2); - if(!onlySelected){ + + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente de + //los manejadores de la curva + SPCurve *curveHelper = new SPCurve(); + curveHelper->moveto(pointAt0); + curveHelper->curveto(pointAt1, pointAt2, pointAt3); + //añadimos la curva generada a la curva pricipal + nCurve->append_continuous(curveHelper, 0.0625); + curveHelper->reset(); + delete curveHelper; + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + //Aberiguamos la ultima parte de la curva correspondiente al último segmento + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + SPCurve * out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt0 = out->first_segment()->initialPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + cubic = dynamic_cast(&*curve_it1); + if(!onlySelected){ if(cubic){ if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()))&& weightValue !=0){ nextPointAt1 = SBasisOut.valueAt(weightValue); @@ -562,30 +577,30 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) }else{ if(cubic){ if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint())) && weightValue !=0){ - if(nodeIsSelected(nextPointAt0,i)){ + if(nodeIsSelected(nextPointAt0,j)){ nextPointAt1 = SBasisOut.valueAt(weightValue); nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); - if (path_it->closed()) i++; + j++; }else{ nextPointAt1 = (*cubic)[1]; } }else{ - if(nodeIsSelected(nextPointAt0,i)){ + if(nodeIsSelected(nextPointAt0,j)){ nextPointAt1 = out->first_segment()->initialPoint(); - if (path_it->closed()) i++; + j++; }else{ nextPointAt1 = (*cubic)[1]; } } if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint())) && weightValue !=0){ - if(nodeIsSelected(nextPointAt3,i)){ + if(nodeIsSelected(nextPointAt3,j)){ nextPointAt2 = SBasisOut.valueAt(1-weightValue); nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ nextPointAt2 = (*cubic)[2]; } }else{ - if(nodeIsSelected(nextPointAt3,i)){ + if(nodeIsSelected(nextPointAt3,j)){ nextPointAt2 = out->first_segment()->finalPoint(); }else{ nextPointAt2 = (*cubic)[2]; @@ -593,14 +608,14 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) } }else{ if(!ignoreCusp && weightValue !=0){ - if(nodeIsSelected(nextPointAt0,i)){ + if(nodeIsSelected(nextPointAt0,j)){ nextPointAt1 = SBasisOut.valueAt(weightValue); nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); - if (path_it->closed()) i++; + j++; }else{ nextPointAt1 = out->first_segment()->initialPoint(); } - if(nodeIsSelected(nextPointAt3,i)){ + if(nodeIsSelected(nextPointAt3,j)){ nextPointAt2 = SBasisOut.valueAt(weightValue); nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ @@ -608,30 +623,13 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) } }else{ nextPointAt1 = out->first_segment()->initialPoint(); - if (path_it->closed()&&nodeIsSelected(nextPointAt0,i)) i++; + if(nodeIsSelected(nextPointAt0,j)) j++; nextPointAt2 = out->first_segment()->finalPoint(); } } } out->reset(); delete out; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente de - //los manejadores de la curva - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(pointAt0); - curveHelper->curveto(pointAt1, pointAt2, pointAt3); - //añadimos la curva generada a la curva pricipal - nCurve->append_continuous(curveHelper, 0.0625); - curveHelper->reset(); - delete curveHelper; - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - //Aberiguamos la ultima parte de la curva correspondiente al último segmento SPCurve *curveHelper = new SPCurve(); curveHelper->moveto(pointAt3); if (path_it->closed()) { -- cgit v1.2.3 From 1290320ca882992345418ce8572af053f1659628 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 10 Apr 2013 21:45:15 +0200 Subject: Fixed bug moving selected nodes (bzr r11950.1.88) --- src/live_effects/lpe-bspline.cpp | 168 ++++++++++++++------------------------- src/live_effects/lpe-bspline.h | 2 +- 2 files changed, 61 insertions(+), 109 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index e7adab071..37bf24021 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -140,7 +140,7 @@ LPEBSpline::doEffect(SPCurve * curve) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - + nCurve->moveto(curve_it1->initialPoint()); //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { @@ -193,20 +193,11 @@ LPEBSpline::doEffect(SPCurve * curve) previousNode = node; //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(previousNode); - curveHelper->curveto(pointAt1, pointAt2, node); - //añadimos la curva generada a la curva pricipal - nCurve->append_continuous(curveHelper, 0.0625); - curveHelper->reset(); - delete curveHelper; + nCurve->curveto(pointAt1, pointAt2, node); //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; } - //Aberiguamos la ultima parte de la curva correspondiente al último segmento - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(node); //Si está cerrada la curva, la cerramos sobre el valor guardado previamente //Si no finalizamos en el punto final Geom::Point startNode(0,0); @@ -242,8 +233,7 @@ LPEBSpline::doEffect(SPCurve * curve) lineHelper->reset(); delete lineHelper; startNode = SBasisHelper.valueAt(0.5); - curveHelper->curveto(nextPointAt1, nextPointAt2, startNode); - nCurve->append_continuous(curveHelper, 0.0625); + nCurve->curveto(nextPointAt1, nextPointAt2, startNode); nCurve->move_endpoints(startNode,startNode); }else{ SPCurve * start = new SPCurve(); @@ -252,12 +242,9 @@ LPEBSpline::doEffect(SPCurve * curve) startNode = start->first_segment()->initialPoint(); start->reset(); delete start; - curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->append_continuous(curveHelper, 0.0625); + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); nCurve->move_endpoints(startNode,nextPointAt3); } - curveHelper->reset(); - delete curveHelper; //y cerramos la curva if (path_it->closed()) { nCurve->closepath_current(); @@ -354,10 +341,15 @@ LPEBSpline::changeWeight(double weightValue) } bool -LPEBSpline::nodeIsSelected(Geom::Point nodePoint, int index){ +LPEBSpline::nodeIsSelected(Geom::Point nodePoint){ if(points.size() > 0){ - if(Geom::are_near(points[index], nodePoint)){ - return true; + for(std::vector::iterator i = points.begin(); i != points.end();){ + Geom::Point p = static_cast(*i); + if(Geom::are_near(p, nodePoint)){ + return true; + points.erase(i); + } + i++; } } return false; @@ -415,7 +407,6 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) Geom::D2< Geom::SBasis > SBasisIn; Geom::D2< Geom::SBasis > SBasisOut; Geom::CubicBezier const *cubic = NULL; - int j = 0; 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. @@ -428,7 +419,7 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) //Si la curva está cerrada calculamos el punto donde //deveria estar el nodo BSpline de cierre/inicio de la curva //en posible caso de que se cierre con una linea recta creando un nodo BSPline - + nCurve->moveto(curve_it1->initialPoint()); //Recorremos todos los segmentos menos el último while ( curve_it2 != curve_endit ) { @@ -443,7 +434,7 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) SBasisIn = in->first_segment()->toSBasis(); if(!onlySelected){ if(cubic){ - if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ + if(!ignoreCusp || (!Geom::are_near((*cubic)[1],in->first_segment()->initialPoint()) && weightValue !=0)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); }else{ @@ -468,46 +459,35 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) } }else{ if(cubic){ - if((!ignoreCusp || !Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())) && weightValue !=0){ - if(nodeIsSelected(pointAt0,j)){ + if(!ignoreCusp || (!Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())&& weightValue !=0)){ + if(nodeIsSelected(pointAt0)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); - j++; }else{ pointAt1 = (*cubic)[1]; } }else{ - if(nodeIsSelected(pointAt0,j)){ pointAt1 = in->first_segment()->initialPoint(); - j++; - }else{ - pointAt1 = (*cubic)[1]; - } } - if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ - if(nodeIsSelected(pointAt3,j)){ + if(!ignoreCusp || (!Geom::are_near((*cubic)[2],in->first_segment()->finalPoint()) && weightValue !=0)){ + if(nodeIsSelected(pointAt3)){ pointAt2 = SBasisIn.valueAt(1-weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ pointAt2 = (*cubic)[2]; } }else{ - if(nodeIsSelected(pointAt3,j)){ pointAt2 = in->first_segment()->finalPoint(); - }else{ - pointAt2 = (*cubic)[2]; - } } }else{ if(!ignoreCusp && weightValue !=0){ - if(nodeIsSelected(pointAt0,j)){ + if(nodeIsSelected(pointAt0)){ pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); - j++; }else{ pointAt1 = in->first_segment()->initialPoint(); } - if(nodeIsSelected(pointAt3,j)){ + if(nodeIsSelected(pointAt3)){ pointAt2 = SBasisIn.valueAt(weightValue); pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); }else{ @@ -516,34 +496,21 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) }else{ pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); - if(nodeIsSelected(pointAt0,j)){ - j++; - } } } } in->reset(); delete in; - //La curva BSpline se forma calculando el centro del segmanto de unión //de el punto situado en las 2/3 partes de el segmento de entrada //con el punto situado en la posición 1/3 del segmento de salida //Estos dos puntos ademas estan posicionados en el lugas correspondiente de //los manejadores de la curva - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(pointAt0); - curveHelper->curveto(pointAt1, pointAt2, pointAt3); - //añadimos la curva generada a la curva pricipal - nCurve->append_continuous(curveHelper, 0.0625); - curveHelper->reset(); - delete curveHelper; + nCurve->curveto(pointAt1, pointAt2, pointAt3); //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; } - //Aberiguamos la ultima parte de la curva correspondiente al último segmento - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); SPCurve * out = new SPCurve(); out->moveto(curve_it1->initialPoint()); out->lineto(curve_it1->finalPoint()); @@ -576,75 +543,60 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) nextPointAt2 = out->first_segment()->finalPoint(); } } - }else{ - if(cubic){ - if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint())) && weightValue !=0){ - if(nodeIsSelected(nextPointAt0,j)){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); - j++; - }else{ - nextPointAt1 = (*cubic)[1]; - } + }else{ + if(cubic){ + if(!ignoreCusp || (!Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()) && weightValue !=0)){ + if(nodeIsSelected(nextPointAt0)){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); }else{ - if(nodeIsSelected(nextPointAt0,j)){ - nextPointAt1 = out->first_segment()->initialPoint(); - j++; - }else{ - nextPointAt1 = (*cubic)[1]; - } + nextPointAt1 = (*cubic)[1]; } - if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint())) && weightValue !=0){ - if(nodeIsSelected(nextPointAt3,j)){ - nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); - }else{ - nextPointAt2 = (*cubic)[2]; - } + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + } + if(!ignoreCusp || (!Geom::are_near((*cubic)[2],out->first_segment()->finalPoint()) && weightValue !=0)){ + if(nodeIsSelected(nextPointAt3)){ + nextPointAt2 = SBasisOut.valueAt(1-weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); }else{ - if(nodeIsSelected(nextPointAt3,j)){ - nextPointAt2 = out->first_segment()->finalPoint(); - }else{ - nextPointAt2 = (*cubic)[2]; - } - } + nextPointAt2 = (*cubic)[2]; + } }else{ - if(!ignoreCusp && weightValue !=0){ - if(nodeIsSelected(nextPointAt0,j)){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); - j++; - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - } - if(nodeIsSelected(nextPointAt3,j)){ - nextPointAt2 = SBasisOut.valueAt(weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); - }else{ - nextPointAt2 = out->first_segment()->finalPoint(); - } + nextPointAt2 = out->first_segment()->finalPoint(); + } + }else{ + if(!ignoreCusp && weightValue !=0){ + if(nodeIsSelected(nextPointAt0)){ + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); }else{ nextPointAt1 = out->first_segment()->initialPoint(); - if(nodeIsSelected(nextPointAt0,j)) j++; + } + if(nodeIsSelected(nextPointAt3)){ + nextPointAt2 = SBasisOut.valueAt(weightValue); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + }else{ nextPointAt2 = out->first_segment()->finalPoint(); } + }else{ + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); } } - out->reset(); - delete out; - SPCurve *curveHelper = new SPCurve(); - curveHelper->moveto(pointAt3); + } + out->reset(); + delete out; + //Aberiguamos la ultima parte de la curva correspondiente al último segmento + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); if (path_it->closed()) { - curveHelper->curveto(nextPointAt1, nextPointAt2, path_it->begin()->initialPoint()); - nCurve->append_continuous(curveHelper, 0.0625); + nCurve->curveto(nextPointAt1, nextPointAt2, path_it->begin()->initialPoint()); nCurve->move_endpoints(path_it->begin()->initialPoint(),path_it->begin()->initialPoint()); }else{ - curveHelper->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->append_continuous(curveHelper, 0.0625); + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); nCurve->move_endpoints(path_it->begin()->initialPoint(),nextPointAt3); } - curveHelper->reset(); - delete curveHelper; //y cerramos la curva if (path_it->closed()) { nCurve->closepath_current(); diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 2361c10d0..103f09338 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -29,7 +29,7 @@ public: virtual void doBSplineFromWidget(SPCurve * curve, double value); - virtual bool nodeIsSelected(Geom::Point nodePoint, int index); + virtual bool nodeIsSelected(Geom::Point nodePoint); virtual Gtk::Widget * newWidget(); -- cgit v1.2.3 From 458ca2842297a5eae7e4f6fc394b227d61881c8d Mon Sep 17 00:00:00 2001 From: root Date: Wed, 17 Apr 2013 23:03:51 +0200 Subject: Update color lines overlay, with halo of 1 px matched by Gez. Fix some crash snapping. Added new button widget to make cusp node (bzr r11950.1.96) --- src/live_effects/lpe-bspline.cpp | 95 +++++++++++++++++++++++++--------------- src/live_effects/lpe-bspline.h | 2 + 2 files changed, 62 insertions(+), 35 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 37bf24021..cc1b86e72 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -170,7 +170,7 @@ LPEBSpline::doEffect(SPCurve * curve) SBasisOut = out->first_segment()->toSBasis(); nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1],*out->first_segment())); nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2],*out->first_segment()));; - nextPointAt3 = (*cubic)[3]; + nextPointAt3 = out->first_segment()->finalPoint(); }else{ nextPointAt1 = out->first_segment()->initialPoint(); nextPointAt2 = out->first_segment()->finalPoint(); @@ -299,19 +299,24 @@ LPEBSpline::newWidget() defaultWeight->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::toDefaultWeight)); Gtk::Widget* defaultWeightWidget = dynamic_cast(defaultWeight); vbox->pack_start(*defaultWeightWidget, true, true,2); + Gtk::Button* makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); + makeCusp->set_alignment(0.0, 0.5); + makeCusp->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::toMakeCusp)); + Gtk::Widget* makeCuspWidget = dynamic_cast(makeCusp); + vbox->pack_start(*makeCuspWidget, true, true,2); return dynamic_cast(vbox); } void LPEBSpline::toDefaultWeight(){ - Gtk::Widget * widg = dynamic_cast(param_vector[3]->param_newWidget()); - Inkscape::UI::Widget::Scalar * widgRegistered = Gtk::manage(dynamic_cast(widg)); - widgRegistered->setValue(0.3334); - widgRegistered->update(); - weight.param_set_value(0.3334); changeWeight(0.3334); } +void +LPEBSpline::toMakeCusp(){ + changeWeight(0.0000); +} + void LPEBSpline::toWeight(){ changeWeight(weight); @@ -434,24 +439,32 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) SBasisIn = in->first_segment()->toSBasis(); if(!onlySelected){ if(cubic){ - if(!ignoreCusp || (!Geom::are_near((*cubic)[1],in->first_segment()->initialPoint()) && weightValue !=0)){ + if(!ignoreCusp || !Geom::are_near((*cubic)[1],pointAt0)){ pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + if(weightValue !=0.0000){ + pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); + } }else{ pointAt1 = in->first_segment()->initialPoint(); } - if((!ignoreCusp || !Geom::are_near((*cubic)[2],in->first_segment()->finalPoint())) && weightValue !=0){ + if(!ignoreCusp || !Geom::are_near((*cubic)[2],pointAt3)){ pointAt2 = SBasisIn.valueAt(1-weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); - }else{ + if(weightValue !=0.0000){ + pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); + } + }else{ pointAt2 = in->first_segment()->finalPoint(); } }else{ - if(!ignoreCusp && weightValue !=0){ + if(!ignoreCusp && weightValue !=0.0000){ pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + if(weightValue !=0.0000){ + pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); + } pointAt2 = SBasisIn.valueAt(1-weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + if(weightValue !=0.0000){ + pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); + } }else{ pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); @@ -459,20 +472,24 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) } }else{ if(cubic){ - if(!ignoreCusp || (!Geom::are_near((*cubic)[1],in->first_segment()->initialPoint())&& weightValue !=0)){ + if(!ignoreCusp || !Geom::are_near((*cubic)[1],pointAt0)){ if(nodeIsSelected(pointAt0)){ pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + if(weightValue !=0.0000){ + pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); + } }else{ pointAt1 = (*cubic)[1]; } }else{ pointAt1 = in->first_segment()->initialPoint(); } - if(!ignoreCusp || (!Geom::are_near((*cubic)[2],in->first_segment()->finalPoint()) && weightValue !=0)){ + if(!ignoreCusp || !Geom::are_near((*cubic)[2],pointAt3)){ if(nodeIsSelected(pointAt3)){ pointAt2 = SBasisIn.valueAt(1-weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + if(weightValue !=0.0000){ + pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); + } }else{ pointAt2 = (*cubic)[2]; } @@ -480,16 +497,16 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) pointAt2 = in->first_segment()->finalPoint(); } }else{ - if(!ignoreCusp && weightValue !=0){ + if(!ignoreCusp && weightValue !=0.000){ if(nodeIsSelected(pointAt0)){ pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0625,pointAt1[Y] + 0.0625); + pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); }else{ pointAt1 = in->first_segment()->initialPoint(); } if(nodeIsSelected(pointAt3)){ pointAt2 = SBasisIn.valueAt(weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0625,pointAt2[Y] + 0.0625); + pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); }else{ pointAt2 = in->first_segment()->finalPoint(); } @@ -520,24 +537,28 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) cubic = dynamic_cast(&*curve_it1); if(!onlySelected){ if(cubic){ - if((!ignoreCusp || !Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()))&& weightValue !=0){ + if(!ignoreCusp || !Geom::are_near((*cubic)[1],nextPointAt0)){ nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + if(weightValue !=0.0000){ + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); + } }else{ nextPointAt1 = out->first_segment()->initialPoint(); } - if((!ignoreCusp || !Geom::are_near((*cubic)[2],out->first_segment()->finalPoint()))&& weightValue !=0){ + if(!ignoreCusp || !Geom::are_near((*cubic)[2],nextPointAt3)){ nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + if(weightValue !=0.0000){ + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); + } }else{ nextPointAt2 = out->first_segment()->finalPoint(); } }else{ - if(!ignoreCusp && weightValue !=0){ + if(!ignoreCusp && weightValue !=0.0000){ nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); }else{ nextPointAt1 = out->first_segment()->initialPoint(); nextPointAt2 = out->first_segment()->finalPoint(); @@ -545,20 +566,24 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) } }else{ if(cubic){ - if(!ignoreCusp || (!Geom::are_near((*cubic)[1],out->first_segment()->initialPoint()) && weightValue !=0)){ + if(!ignoreCusp || !Geom::are_near((*cubic)[1],nextPointAt0)){ if(nodeIsSelected(nextPointAt0)){ nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + if(weightValue !=0.0000){ + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); + } }else{ nextPointAt1 = (*cubic)[1]; } }else{ nextPointAt1 = out->first_segment()->initialPoint(); } - if(!ignoreCusp || (!Geom::are_near((*cubic)[2],out->first_segment()->finalPoint()) && weightValue !=0)){ + if(!ignoreCusp || !Geom::are_near((*cubic)[2],nextPointAt3)){ if(nodeIsSelected(nextPointAt3)){ nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + if(weightValue !=0.0000){ + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); + } }else{ nextPointAt2 = (*cubic)[2]; } @@ -566,16 +591,16 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) nextPointAt2 = out->first_segment()->finalPoint(); } }else{ - if(!ignoreCusp && weightValue !=0){ + if(!ignoreCusp && weightValue !=0.0000){ if(nodeIsSelected(nextPointAt0)){ nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0625,nextPointAt1[Y] + 0.0625); + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); }else{ nextPointAt1 = out->first_segment()->initialPoint(); } if(nodeIsSelected(nextPointAt3)){ nextPointAt2 = SBasisOut.valueAt(weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0625,nextPointAt2[Y] + 0.0625); + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); }else{ nextPointAt2 = out->first_segment()->finalPoint(); } diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 103f09338..510f9c989 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -37,6 +37,8 @@ public: virtual void toDefaultWeight(); + virtual void toMakeCusp(); + virtual void toWeight(); ScalarParam steps; -- cgit v1.2.3 From 9291d4e3a3ad22bef4669b74568ee6d43ba74547 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 18 May 2013 10:38:35 +0200 Subject: Fix error with envelope lpe (bzr r11950.1.117) --- src/live_effects/effect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 8bf8bab6c..b84403495 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -8,7 +8,7 @@ //#define LPE_ENABLE_TEST_EFFECTS #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif // include effects: -- cgit v1.2.3 From 0bd0fa66b7825f0d4e0c9051aa527ba91e415683 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 19 Aug 2013 01:10:42 +0200 Subject: Reverted po files to master branch, now the diff of launchpad is more usable (bzr r11950.1.136) --- src/live_effects/lpe-bspline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index cc1b86e72..c2749e393 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -2,7 +2,7 @@ /* * Released under GNU GPL, read the file 'COPYING' for more information */ - + #include #include #include -- cgit v1.2.3 From 9737c8d04d0ad85bf6a61d36edf7d717419b30f2 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 27 Sep 2013 01:39:44 +0200 Subject: update to trunk (bzr r11950.1.152) --- src/live_effects/lpe-bendpath.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bendpath.h b/src/live_effects/lpe-bendpath.h index 16b8c6137..d3564bac4 100644 --- a/src/live_effects/lpe-bendpath.h +++ b/src/live_effects/lpe-bendpath.h @@ -39,9 +39,9 @@ public: virtual void resetDefaults(SPItem const* item); + PathParam bend_path; private: - PathParam bend_path; ScalarParam prop_scale; BoolParam scale_y_rel; BoolParam vertical_pattern; -- cgit v1.2.3 From f3a885546d1bd971c5bd4a6bbdbaedb59557007d Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 27 Sep 2013 01:42:10 +0200 Subject: error bend lpe (bzr r11950.1.153) --- src/live_effects/lpe-bendpath.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bendpath.h b/src/live_effects/lpe-bendpath.h index d3564bac4..38b1a1446 100644 --- a/src/live_effects/lpe-bendpath.h +++ b/src/live_effects/lpe-bendpath.h @@ -39,9 +39,8 @@ public: virtual void resetDefaults(SPItem const* item); - PathParam bend_path; - private: + PathParam bend_path; ScalarParam prop_scale; BoolParam scale_y_rel; BoolParam vertical_pattern; -- cgit v1.2.3 From cdf6320ab752de234f986031bfdd7dcb8e705e69 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 8 Nov 2013 10:13:22 +0100 Subject: Fixing bugs on update to trunk (bzr r11950.1.194) --- src/live_effects/lpe-bspline.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 84f3fbb33..ef03d8ef0 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -335,7 +335,7 @@ LPEBSpline::changeWeight(double weightValue) gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); if(INK_IS_NODE_TOOL(desktop->event_context)){ - InkNodeTool *nt = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); nt->desktop->updateNow(); } g_free(str); @@ -367,7 +367,7 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) using Geom::Y; SPDesktop *desktop = inkscape_active_desktop(); if(INK_IS_NODE_TOOL(desktop->event_context)){ - InkNodeTool *nt = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); points.clear(); std::vector::iterator pbegin; -- cgit v1.2.3 From 3ed9b4ff7ebbae3ba6446d911001688bcbbdc847 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 10 Nov 2013 12:17:23 +0100 Subject: Update to trunk (bzr r11950.1.196) --- src/live_effects/lpe-bspline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index ef03d8ef0..c19eda8f0 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -17,7 +17,7 @@ #include "live_effects/parameter/parameter.h" #include "ui/widget/scalar.h" #include "ui/tool/node.h" -#include "ui/tool/node-tool.h" +#include "ui/tools/node-tool.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/selectable-control-point.h" #include "selection.h" -- cgit v1.2.3 From 4c6918c72721a35e0347e9e087396238e72eb62e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 30 Dec 2013 20:41:32 +0100 Subject: Refactorizing (bzr r11950.1.212) --- src/live_effects/effect-enum.h | 2 -- src/live_effects/effect.cpp | 6 ------ src/live_effects/lpe-bendpath.h | 1 - 3 files changed, 9 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index cf97dd87f..342a2c849 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -45,9 +45,7 @@ enum EffectType { PATH_LENGTH, LINE_SEGMENT, DOEFFECTSTACK_TEST, - //BSpline BSPLINE, - //BSpline End DYNASTROKE, RECURSIVE_SKELETON, EXTRUDE, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 3289c239e..29da403e8 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -21,9 +21,7 @@ #include "live_effects/lpe-rough-hatches.h" #include "live_effects/lpe-dynastroke.h" #include "live_effects/lpe-test-doEffect-stack.h" -//BSpline #include "live_effects/lpe-bspline.h" -//BSpline End #include "live_effects/lpe-gears.h" #include "live_effects/lpe-curvestitch.h" #include "live_effects/lpe-circle_with_radius.h" @@ -125,9 +123,7 @@ const Util::EnumData LPETypeData[] = { /* 0.49 */ {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, - //BSpline {BSPLINE, N_("BSpline"), "bspline"}, - //BSpline End }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -236,11 +232,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case DOEFFECTSTACK_TEST: neweffect = static_cast ( new LPEdoEffectStackTest(lpeobj) ); break; - //BSpline case BSPLINE: neweffect = static_cast ( new LPEBSpline(lpeobj) ); break; - //BSpline End case DYNASTROKE: neweffect = static_cast ( new LPEDynastroke(lpeobj) ); break; diff --git a/src/live_effects/lpe-bendpath.h b/src/live_effects/lpe-bendpath.h index 38b1a1446..554f20413 100644 --- a/src/live_effects/lpe-bendpath.h +++ b/src/live_effects/lpe-bendpath.h @@ -38,7 +38,6 @@ public: virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); virtual void resetDefaults(SPItem const* item); - private: PathParam bend_path; ScalarParam prop_scale; -- cgit v1.2.3 From df2cf6584407ae3744aac917039681fb3a04a678 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 30 Dec 2013 23:32:51 +0100 Subject: refactor, fixing some diff diferences (bzr r11950.1.219) --- src/live_effects/lpe-bendpath.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bendpath.h b/src/live_effects/lpe-bendpath.h index 554f20413..16b8c6137 100644 --- a/src/live_effects/lpe-bendpath.h +++ b/src/live_effects/lpe-bendpath.h @@ -38,6 +38,8 @@ public: virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); virtual void resetDefaults(SPItem const* item); + + private: PathParam bend_path; ScalarParam prop_scale; -- cgit v1.2.3 From 1d854ff519b9c0867bfa4ecaf2f6329ca256f06a Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 2 Mar 2014 10:29:06 -0500 Subject: Experimental merge of Ponyscape features into trunk (will not compile) (bzr r13090.1.1) --- src/live_effects/CMakeLists.txt | 13 + src/live_effects/Makefile_insert | 14 +- src/live_effects/effect-enum.h | 6 + src/live_effects/effect.cpp | 39 +- src/live_effects/lpe-attach-path.cpp | 203 ++++++ src/live_effects/lpe-attach-path.h | 54 ++ src/live_effects/lpe-bounding-box.cpp | 67 ++ src/live_effects/lpe-bounding-box.h | 37 + src/live_effects/lpe-ellipse_5pts.cpp | 214 ++++++ src/live_effects/lpe-ellipse_5pts.h | 50 ++ src/live_effects/lpe-fill-between-many.cpp | 77 +++ src/live_effects/lpe-fill-between-many.h | 36 + src/live_effects/lpe-fill-between-strokes.cpp | 116 ++++ src/live_effects/lpe-fill-between-strokes.h | 38 + src/live_effects/lpe-jointype.cpp | 203 ++++++ src/live_effects/lpe-jointype.h | 43 ++ src/live_effects/lpe-powerstroke-interpolators.h | 42 +- src/live_effects/lpe-powerstroke.cpp | 97 ++- src/live_effects/lpe-powerstroke.h | 2 + src/live_effects/parameter/Makefile_insert | 4 + src/live_effects/parameter/originalpatharray.cpp | 486 +++++++++++++ src/live_effects/parameter/originalpatharray.h | 123 ++++ .../parameter/powerstrokepointarray.cpp | 39 +- src/live_effects/parameter/powerstrokepointarray.h | 23 +- src/live_effects/parameter/transformedpoint.cpp | 182 +++++ src/live_effects/parameter/transformedpoint.h | 87 +++ src/live_effects/pathoutlineprovider.h | 766 +++++++++++++++++++++ 27 files changed, 3037 insertions(+), 24 deletions(-) create mode 100644 src/live_effects/lpe-attach-path.cpp create mode 100644 src/live_effects/lpe-attach-path.h create mode 100644 src/live_effects/lpe-bounding-box.cpp create mode 100644 src/live_effects/lpe-bounding-box.h create mode 100644 src/live_effects/lpe-ellipse_5pts.cpp create mode 100644 src/live_effects/lpe-ellipse_5pts.h create mode 100644 src/live_effects/lpe-fill-between-many.cpp create mode 100644 src/live_effects/lpe-fill-between-many.h create mode 100644 src/live_effects/lpe-fill-between-strokes.cpp create mode 100644 src/live_effects/lpe-fill-between-strokes.h create mode 100644 src/live_effects/lpe-jointype.cpp create mode 100755 src/live_effects/lpe-jointype.h create mode 100644 src/live_effects/parameter/originalpatharray.cpp create mode 100644 src/live_effects/parameter/originalpatharray.h create mode 100644 src/live_effects/parameter/transformedpoint.cpp create mode 100644 src/live_effects/parameter/transformedpoint.h create mode 100755 src/live_effects/pathoutlineprovider.h (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index a5f50a69d..8ad1ccf9b 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -2,8 +2,10 @@ set(live_effects_SRC effect.cpp lpe-angle_bisector.cpp + lpe-attach-path.cpp lpe-bendpath.cpp lpe-boolops.cpp + lpe-bounding-box.cpp lpe-circle_3pts.cpp lpe-circle_with_radius.cpp lpe-clone-original.cpp @@ -11,8 +13,11 @@ set(live_effects_SRC lpe-copy_rotate.cpp lpe-curvestitch.cpp lpe-dynastroke.cpp + lpe-ellipse-5pts.cpp lpe-envelope.cpp lpe-extrude.cpp + lpe-fill-between-many.cpp + lpe-fill-between-strokes.cpp lpe-gears.cpp lpe-interpolate.cpp lpe-knot.cpp @@ -47,11 +52,13 @@ set(live_effects_SRC parameter/parameter.cpp parameter/path.cpp parameter/originalpath.cpp + parameter/originalpatharray.cpp parameter/path-reference.cpp parameter/point.cpp parameter/powerstrokepointarray.cpp parameter/random.cpp parameter/text.cpp + paramter/transformedpoint.cpp parameter/unit.cpp parameter/vector.cpp @@ -61,8 +68,10 @@ set(live_effects_SRC effect-enum.h effect.h lpe-angle_bisector.h + lpe-attach-path.h lpe-bendpath.h lpe-boolops.h + lpe-bounding-box.h lpe-circle_3pts.h lpe-circle_with_radius.h lpe-clone-original.h @@ -70,8 +79,11 @@ set(live_effects_SRC lpe-copy_rotate.h lpe-curvestitch.h lpe-dynastroke.h + lpe-ellipse-5pts.h lpe-envelope.h lpe-extrude.h + lpe-fill-between-many.h + lpe-fill-between-strokes.h lpe-gears.h lpe-interpolate.h lpe-knot.h @@ -109,6 +121,7 @@ set(live_effects_SRC parameter/path-reference.h parameter/path.h parameter/originalpath.h + parameter/originalpatharray.h parameter/point.h parameter/powerstrokepointarray.h parameter/random.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 9c3c171f2..76d7b418f 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -82,4 +82,16 @@ ink_common_sources += \ live_effects/lpe-path_length.cpp \ live_effects/lpe-path_length.h \ live_effects/lpe-line_segment.cpp \ - live_effects/lpe-line_segment.h + live_effects/lpe-line_segment.h \ + live_effects/lpe-bounding-box.cpp \ + live_effects/lpe-bounding-box.h \ + live_effects/lpe-attach-path.cpp \ + live_effects/lpe-attach-path.h \ + live_effects/lpe-fill-between-strokes.cpp \ + live_effects/lpe-fill-between-stroke.h \ + live_effects/lpe-fill-between-many.cpp \ + live_effects/lpe-fill-between-many.h \ + live_effects/lpe-ellipse_5pts.cpp \ + live_effects/lpe-ellipse_5pts.h \ + live_effects/lpe-jointype.cpp \ + live_effects/lpe-jointype.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 43af33b53..46bc56a81 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -50,6 +50,12 @@ enum EffectType { EXTRUDE, POWERSTROKE, CLONE_ORIGINAL, + ATTACH_PATH, + FILL_BETWEEN_STROKES, + FILL_BETWEEN_MANY, + ELLIPSE_5PTS, + BOUNDING_BOX, + JOIN_TYPE, 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 12990ee24..17b229352 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,7 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -//#define LPE_ENABLE_TEST_EFFECTS +#define LPE_ENABLE_TEST_EFFECTS #ifdef HAVE_CONFIG_H # include "config.h" @@ -47,6 +47,12 @@ #include "live_effects/lpe-extrude.h" #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-clone-original.h" +#include "live_effects/lpe-attach-path.h" +#include "live_effects/lpe-fill-between-strokes.h" +#include "live_effects/lpe-fill-between-many.h" +#include "live_effects/lpe-ellipse_5pts.h" +#include "live_effects/lpe-bounding-box.h" +#include "live_effects/lpe-jointype.h" #include "xml/node-event-vector.h" #include "sp-object.h" @@ -103,9 +109,10 @@ const Util::EnumData LPETypeData[] = { {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, + {JOIN_TYPE, N_("Join type"), "join_type"}, #endif /* 0.46 */ - {BEND_PATH, N_("Bend"), "bend_path"}, + {BEND_PATH, N_("Bend"), "bend_path"}, {GEARS, N_("Gears"), "gears"}, {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"}, @@ -120,8 +127,14 @@ const Util::EnumData LPETypeData[] = { {SKETCH, N_("Sketch"), "sketch"}, {RULER, N_("Ruler"), "ruler"}, /* 0.49 */ - {POWERSTROKE, N_("Power stroke"), "powerstroke"}, - {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, + {POWERSTROKE, N_("Power stroke"), "powerstroke"}, + {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, +/* Ponyscape */ + {ATTACH_PATH, N_("Attach path"), "attach_path"}, + {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, + {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, + {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, + {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -245,6 +258,24 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case CLONE_ORIGINAL: neweffect = static_cast ( new LPECloneOriginal(lpeobj) ); break; + case ATTACH_PATH: + neweffect = static_cast ( new LPEAttachPath(lpeobj) ); + break; + case FILL_BETWEEN_STROKES: + neweffect = static_cast ( new LPEFillBetweenStrokes(lpeobj) ); + break; + case FILL_BETWEEN_MANY: + neweffect = static_cast ( new LPEFillBetweenMany(lpeobj) ); + break; + case ELLIPSE_5PTS: + neweffect = static_cast ( new LPEEllipse5Pts(lpeobj) ); + break; + case BOUNDING_BOX: + neweffect = static_cast ( new LPEBoundingBox(lpeobj) ); + break; + case JOIN_TYPE: + neweffect = static_cast ( new LPEJoinType(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp new file mode 100644 index 000000000..b3d5ed9b7 --- /dev/null +++ b/src/live_effects/lpe-attach-path.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) Johan Engelen 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include + +#include "live_effects/lpe-attach-path.h" + +#include "display/curve.h" +#include "sp-item.h" +#include "2geom/path.h" +#include "sp-shape.h" +#include "sp-text.h" +#include "2geom/bezier-curve.h" +#include "2geom/path-sink.h" +#include "parameter/parameter.h" +#include "live_effects/parameter/point.h" +#include "parameter/originalpath.h" +#include "2geom/affine.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEAttachPath::LPEAttachPath(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + start_path(_("Start path:"), _("Path to attach to the start of this path"), "startpath", &wr, this), + start_path_position(_("Start path position:"), _("Position to attach path start to"), "startposition", &wr, this, 0.0), + start_path_curve_start(_("Start path curve start:"), _("Starting curve"), "startcurvestart", &wr, this, Geom::Point(20,0)/*, true*/), + start_path_curve_end(_("Start path curve end:"), _("Ending curve"), "startcurveend", &wr, this, Geom::Point(20,0)/*, true*/), + end_path(_("End path:"), _("Path to attach to the end of this path"), "endpath", &wr, this), + end_path_position(_("End path position:"), _("Position to attach path end to"), "endposition", &wr, this, 0.0), + end_path_curve_start(_("End path curve start:"), _("Starting curve"), "endcurvestart", &wr, this, Geom::Point(20,0)/*, true*/), + end_path_curve_end(_("End path curve end:"), _("Ending curve"), "endcurveend", &wr, this, Geom::Point(20,0)/*, true*/) +{ + registerParameter( dynamic_cast(&start_path) ); + registerParameter( dynamic_cast(&start_path_position) ); + registerParameter( dynamic_cast(&start_path_curve_start) ); + registerParameter( dynamic_cast(&start_path_curve_end) ); + + registerParameter( dynamic_cast(&end_path) ); + registerParameter( dynamic_cast(&end_path_position) ); + registerParameter( dynamic_cast(&end_path_curve_start) ); + registerParameter( dynamic_cast(&end_path_curve_end) ); + + //perceived_path = true; + show_orig_path = true; + curve_start_previous_origin = start_path_curve_end.getOrigin(); + curve_end_previous_origin = end_path_curve_end.getOrigin(); +} + +LPEAttachPath::~LPEAttachPath() +{ + +} + +void LPEAttachPath::resetDefaults(SPItem const * item) +{ + curve_start_previous_origin = start_path_curve_end.getOrigin(); + curve_end_previous_origin = end_path_curve_end.getOrigin(); +} + +void LPEAttachPath::doBeforeEffect(const SPLPEItem *lpeitem) +{ + lpe_effect = lpeitem; +} + +void LPEAttachPath::doEffect (SPCurve * curve) +{ + std::vector this_pathv = curve->get_pathvector(); + if (lpe_effect && !this_pathv.empty()) { + Geom::Path p = Geom::Path(this_pathv.front().initialPoint()); + + bool set_start_end = start_path_curve_end.getOrigin() != curve_start_previous_origin; + bool set_end_end = end_path_curve_end.getOrigin() != curve_end_previous_origin; + + if (start_path.linksToPath()) { + + std::vector linked_pathv = start_path.get_pathvector(); + Geom::Affine linkedtransform = start_path.getObject()->getRelativeTransform(lpe_effect); + + if ( !linked_pathv.empty() ) + { + Geom::Path transformedpath = linked_pathv.front() * linkedtransform; + start_path_curve_start.setOrigin(this_pathv.front().initialPoint()); + + std::vector derivs = this_pathv.front().front().pointAndDerivatives(0, 3); + + for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { + Geom::Coord length = derivs[deriv_n].length(); + if ( ! Geom::are_near(length, 0) ) { + if (set_start_end) { + start_path_position.param_set_value(transformedpath.nearestPoint(start_path_curve_end.getOrigin())); + } + + if (start_path_position > transformedpath.size()) { + start_path_position.param_set_value(transformedpath.size()); + } else if (start_path_position < 0) { + start_path_position.param_set_value(0); + } + const Geom::Curve *c = start_path_position >= transformedpath.size() ? &transformedpath.back() : &transformedpath.at_index((int)start_path_position); + + std::vector derivs_2 = c->pointAndDerivatives(start_path_position >= transformedpath.size() ? 1 : (start_path_position - (int)start_path_position), 3); + for (unsigned deriv_n_2 = 1; deriv_n_2 < derivs_2.size(); deriv_n_2++) { + Geom::Coord length_2 = derivs[deriv_n_2].length(); + if ( ! Geom::are_near(length_2, 0) ) { + start_path_curve_end.setOrigin(derivs_2[0]); + curve_start_previous_origin = start_path_curve_end.getOrigin(); + + double startangle = atan2(start_path_curve_start.getVector().y(), start_path_curve_start.getVector().x()); + double endangle = atan2(start_path_curve_end.getVector().y(), start_path_curve_end.getVector().x()); + double startderiv = atan2(derivs[deriv_n].y(), derivs[deriv_n].x()); + double endderiv = atan2(derivs_2[deriv_n_2].y(), derivs_2[deriv_n_2].x()); + Geom::Point pt1 = Geom::Point(start_path_curve_start.getVector().length() * cos(startangle + startderiv), start_path_curve_start.getVector().length() * sin(startangle + startderiv)); + Geom::Point pt2 = Geom::Point(start_path_curve_end.getVector().length() * cos(endangle + endderiv), start_path_curve_end.getVector().length() * sin(endangle + endderiv)); + p = Geom::Path(derivs_2[0]); + p.appendNew(-pt2 + derivs_2[0], -pt1 + this_pathv.front().initialPoint(), this_pathv.front().initialPoint()); + break; + + } + } + break; + } + } + } + } + + p.append(this_pathv.front()); + + if (end_path.linksToPath()) { + + std::vector linked_pathv = end_path.get_pathvector(); + Geom::Affine linkedtransform = end_path.getObject()->getRelativeTransform(lpe_effect); + + if ( !linked_pathv.empty() ) + { + Geom::Path transformedpath = linked_pathv.front() * linkedtransform; + Geom::Curve * last_seg_reverse = this_pathv.front().back().reverse(); + + end_path_curve_start.setOrigin(last_seg_reverse->initialPoint()); + + std::vector derivs = last_seg_reverse->pointAndDerivatives(0, 3); + for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { + Geom::Coord length = derivs[deriv_n].length(); + if ( ! Geom::are_near(length, 0) ) { + if (set_end_end) { + end_path_position.param_set_value(transformedpath.nearestPoint(end_path_curve_end.getOrigin())); + } + + if (end_path_position > transformedpath.size()) { + end_path_position.param_set_value(transformedpath.size()); + } else if (end_path_position < 0) { + end_path_position.param_set_value(0); + } + const Geom::Curve *c = end_path_position >= transformedpath.size() ? &transformedpath.back() : &transformedpath.at_index((int)end_path_position); + + std::vector derivs_2 = c->pointAndDerivatives(end_path_position >= transformedpath.size() ? 1 : (end_path_position - (int)end_path_position), 3); + for (unsigned deriv_n_2 = 1; deriv_n_2 < derivs_2.size(); deriv_n_2++) { + Geom::Coord length_2 = derivs[deriv_n_2].length(); + if ( ! Geom::are_near(length_2, 0) ) { + + end_path_curve_end.setOrigin(derivs_2[0]); + curve_end_previous_origin = end_path_curve_end.getOrigin(); + + double startangle = atan2(end_path_curve_start.getVector().y(), end_path_curve_start.getVector().x()); + double endangle = atan2(end_path_curve_end.getVector().y(), end_path_curve_end.getVector().x()); + double startderiv = atan2(derivs[deriv_n].y(), derivs[deriv_n].x()); + double endderiv = atan2(derivs_2[deriv_n_2].y(), derivs_2[deriv_n_2].x()); + Geom::Point pt1 = Geom::Point(end_path_curve_start.getVector().length() * cos(startangle + startderiv), end_path_curve_start.getVector().length() * sin(startangle + startderiv)); + Geom::Point pt2 = Geom::Point(end_path_curve_end.getVector().length() * cos(endangle + endderiv), end_path_curve_end.getVector().length() * sin(endangle + endderiv)); + p.appendNew(-pt1 + this_pathv.front().finalPoint(), -pt2 + derivs_2[0], derivs_2[0]); + + break; + + } + } + break; + } + } + delete last_seg_reverse; + } + } + Geom::PathVector outvector; + outvector.push_back(p); + curve->set_pathvector(outvector); + } +} + +} // 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-attach-path.h b/src/live_effects/lpe-attach-path.h new file mode 100644 index 000000000..3dda189d6 --- /dev/null +++ b/src/live_effects/lpe-attach-path.h @@ -0,0 +1,54 @@ +#ifndef INKSCAPE_LPE_ATTACH_PATH_H +#define INKSCAPE_LPE_ATTACH_PATH_H + +/* + * Inkscape::LPEAttachPath + * + * Copyright (C) Ted Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/point.h" +#include "live_effects/parameter/originalpath.h" +#include "live_effects/parameter/vector.h" +#include "live_effects/parameter/bool.h" +#include "live_effects/parameter/transformedpoint.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEAttachPath : public Effect { +public: + LPEAttachPath(LivePathEffectObject *lpeobject); + virtual ~LPEAttachPath(); + + virtual void doBeforeEffect(const SPLPEItem *lpeitem); + virtual void doEffect (SPCurve * curve); + virtual void resetDefaults(SPItem const * item); + +private: + LPEAttachPath(const LPEAttachPath&); + LPEAttachPath& operator=(const LPEAttachPath&); + + Geom::Point curve_start_previous_origin; + Geom::Point curve_end_previous_origin; + + OriginalPathParam start_path; + ScalarParam start_path_position; + TransformedPointParam start_path_curve_start; + VectorParam start_path_curve_end; + + OriginalPathParam end_path; + ScalarParam end_path_position; + TransformedPointParam end_path_curve_start; + VectorParam end_path_curve_end; + const SPLPEItem * lpe_effect; +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-bounding-box.cpp b/src/live_effects/lpe-bounding-box.cpp new file mode 100644 index 000000000..bafd5e70e --- /dev/null +++ b/src/live_effects/lpe-bounding-box.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include "live_effects/lpe-bounding-box.h" + +#include "display/curve.h" +#include "sp-item.h" +#include "2geom/path.h" +#include "sp-shape.h" +#include "sp-text.h" +#include "2geom/bezier-curve.h" +#include "lpe-bounding-box.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEBoundingBox::LPEBoundingBox(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), + visual_bounds(_("Visual Bounds"), _("Uses the visual bounding box"), "visualbounds", &wr, this) +{ + registerParameter( dynamic_cast(&linked_path) ); + registerParameter( dynamic_cast(&visual_bounds) ); + //perceived_path = true; +} + +LPEBoundingBox::~LPEBoundingBox() +{ + +} + +void LPEBoundingBox::doEffect (SPCurve * curve) +{ + if (curve) { + if ( linked_path.linksToPath() && linked_path.getObject() ) { + SPItem * item = linked_path.getObject(); + Geom::OptRect bbox = visual_bounds.get_value() ? item->visualBounds() : item->geometricBounds(); + Geom::Path p(Geom::Point(bbox->left(), bbox->top())); + p.appendNew(Geom::Point(bbox->right(), bbox->top())); + p.appendNew(Geom::Point(bbox->right(), bbox->bottom())); + p.appendNew(Geom::Point(bbox->left(), bbox->bottom())); + p.appendNew(Geom::Point(bbox->left(), bbox->top())); + std::vector out; + out.push_back(p); + curve->set_pathvector(out); + } + } +} + +} // 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-bounding-box.h b/src/live_effects/lpe-bounding-box.h new file mode 100644 index 000000000..d028a20ac --- /dev/null +++ b/src/live_effects/lpe-bounding-box.h @@ -0,0 +1,37 @@ +#ifndef INKSCAPE_LPE_BOUNDING_BOX_H +#define INKSCAPE_LPE_BOUNDING_BOX_H + +/* + * Inkscape::LPEFillBetweenStrokes + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/originalpath.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEBoundingBox : public Effect { +public: + LPEBoundingBox(LivePathEffectObject *lpeobject); + virtual ~LPEBoundingBox(); + + virtual void doEffect (SPCurve * curve); + +private: + OriginalPathParam linked_path; + BoolParam visual_bounds; + +private: + LPEBoundingBox(const LPEBoundingBox&); + LPEBoundingBox& operator=(const LPEBoundingBox&); +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-ellipse_5pts.cpp b/src/live_effects/lpe-ellipse_5pts.cpp new file mode 100644 index 000000000..b0a5919fe --- /dev/null +++ b/src/live_effects/lpe-ellipse_5pts.cpp @@ -0,0 +1,214 @@ +/** \file + * LPE "Ellipse through 5 points" implementation + */ + +/* + * Authors: + * Theodore Janeczko + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-ellipse_5pts.h" + +// You might need to include other 2geom files. You can add them here: +#include +#include <2geom/path.h> +#include <2geom/circle.h> +#include <2geom/ellipse.h> +#include <2geom/path-sink.h> +#include "inkscape.h" +#include "desktop.h" +#include "message-stack.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEEllipse5Pts::LPEEllipse5Pts(LivePathEffectObject *lpeobject) : + Effect(lpeobject) +{ + //perceived_path = true; +} + +LPEEllipse5Pts::~LPEEllipse5Pts() +{ +} + +static double _det3(double (*mat)[3]) +{ + for (int i = 0; i < 2; i++) + { + for (int j = i + 1; j < 3; j++) + { + for (int k = i + 1; k < 3; k++) + { + mat[j][k] = (mat[j][k] * mat[i][i] - mat[j][i] * mat[i][k]); + if (i) mat[j][k] /= mat[i-1][i-1]; + } + } + } + return mat[2][2]; +} +static double _det5(double (*mat)[5]) +{ + for (int i = 0; i < 4; i++) + { + for (int j = i + 1; j < 5; j++) + { + for (int k = i + 1; k < 5; k++) + { + mat[j][k] = (mat[j][k] * mat[i][i] - mat[j][i] * mat[i][k]); + if (i) mat[j][k] /= mat[i-1][i-1]; + } + } + } + return mat[4][4]; +} + +std::vector +LPEEllipse5Pts::doEffect_path (std::vector const & path_in) +{ + std::vector path_out = std::vector(); + + if (path_in[0].size() < 4) { + + SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Five points required for constructing an ellipse")); + return path_in; + } + // we assume that the path has >= 3 nodes + Geom::Point A = path_in[0].initialPoint(); + Geom::Point B = path_in[0].pointAt(1); + Geom::Point C = path_in[0].pointAt(2); + Geom::Point D = path_in[0].pointAt(3); + Geom::Point E = path_in[0].pointAt(4); + + using namespace Geom; + + double rowmajor_matrix[5][6] = + { + {A.x()*A.x(), A.x()*A.y(), A.y()*A.y(), A.x(), A.y(), 1}, + {B.x()*B.x(), B.x()*B.y(), B.y()*B.y(), B.x(), B.y(), 1}, + {C.x()*C.x(), C.x()*C.y(), C.y()*C.y(), C.x(), C.y(), 1}, + {D.x()*D.x(), D.x()*D.y(), D.y()*D.y(), D.x(), D.y(), 1}, + {E.x()*E.x(), E.x()*E.y(), E.y()*E.y(), E.x(), E.y(), 1} + }; + + double mat_a[5][5] = + { + {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, + {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, + {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, + {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, + {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} + }; + double mat_b[5][5] = + { + {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, + {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, + {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, + {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, + {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} + }; + double mat_c[5][5] = + { + {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, + {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, + {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, + {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, + {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} + }; + double mat_d[5][5] = + { + {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, + {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, + {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, + {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]}, + {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} + }; + double mat_e[5][5] = + { + {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, + {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, + {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, + {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, + {rowmajor_matrix[0][5], rowmajor_matrix[1][5], rowmajor_matrix[2][5], rowmajor_matrix[3][5], rowmajor_matrix[4][5]} + }; + double mat_f[5][5] = + { + {rowmajor_matrix[0][0], rowmajor_matrix[1][0], rowmajor_matrix[2][0], rowmajor_matrix[3][0], rowmajor_matrix[4][0]}, + {rowmajor_matrix[0][1], rowmajor_matrix[1][1], rowmajor_matrix[2][1], rowmajor_matrix[3][1], rowmajor_matrix[4][1]}, + {rowmajor_matrix[0][2], rowmajor_matrix[1][2], rowmajor_matrix[2][2], rowmajor_matrix[3][2], rowmajor_matrix[4][2]}, + {rowmajor_matrix[0][3], rowmajor_matrix[1][3], rowmajor_matrix[2][3], rowmajor_matrix[3][3], rowmajor_matrix[4][3]}, + {rowmajor_matrix[0][4], rowmajor_matrix[1][4], rowmajor_matrix[2][4], rowmajor_matrix[3][4], rowmajor_matrix[4][4]} + }; + + double a1 = _det5(mat_a); + double b1 = -_det5(mat_b); + double c1 = _det5(mat_c); + double d1 = -_det5(mat_d); + double e1 = _det5(mat_e); + double f1 = -_det5(mat_f); + + double mat_check[][3] = + { + {a1, b1/2, d1/2}, + {b1/2, c1, e1/2}, + {d1/2, e1/2, f1} + }; + + if (_det3(mat_check) == 0 || a1*c1 - b1*b1/4 <= 0) { + SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No ellipse found for specified points")); + return path_in; + } + + Geom::Ellipse el(a1, b1, c1, d1, e1, f1); + + double s, e; + double x0, y0, x1, y1, x2, y2, x3, y3; + double len; + + // figure out if we have a slice, guarding against rounding errors + + Path p(Geom::Point(cos(0), sin(0))); + + double end = 2 * M_PI; + for (s = 0; s < end; s += M_PI_2) { + e = s + M_PI_2; + if (e > end) + e = end; + len = 4*tan((e - s)/4)/3; + x0 = cos(s); + y0 = sin(s); + x1 = x0 + len * cos(s + M_PI_2); + y1 = y0 + len * sin(s + M_PI_2); + x3 = cos(e); + y3 = sin(e); + x2 = x3 + len * cos(e - M_PI_2); + y2 = y3 + len * sin(e - M_PI_2); + p.appendNew(Geom::Point(x1,y1), Geom::Point(x2,y2), Geom::Point(x3,y3)); + } + + Geom::Affine aff = Geom::Scale(el.ray(Geom::X), el.ray(Geom::Y)) * Geom::Rotate(el.rot_angle()) * Geom::Translate(el.center()); + + path_out.push_back(p * aff); + + return path_out; +} + +/* ######################## */ + +} //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-ellipse_5pts.h b/src/live_effects/lpe-ellipse_5pts.h new file mode 100644 index 000000000..d3b1fccfa --- /dev/null +++ b/src/live_effects/lpe-ellipse_5pts.h @@ -0,0 +1,50 @@ +#ifndef INKSCAPE_LPE_ELLIPSE_5PTS_H +#define INKSCAPE_LPE_ELLIPSE_5PTS_H + +/** \file + * LPE "Ellipse through 5 points" implementation + */ + +/* + * Authors: + * Theodore Janeczko + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/point.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEEllipse5Pts : public Effect { +public: + LPEEllipse5Pts(LivePathEffectObject *lpeobject); + virtual ~LPEEllipse5Pts(); + + virtual std::vector doEffect_path (std::vector const & path_in); + +private: + LPEEllipse5Pts(const LPEEllipse5Pts&); + LPEEllipse5Pts& operator=(const LPEEllipse5Pts&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif + +/* + 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-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp new file mode 100644 index 000000000..00cc1fed5 --- /dev/null +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include + +#include "live_effects/lpe-fill-between-many.h" + +#include "display/curve.h" +#include "sp-item.h" +#include "2geom/path.h" +#include "sp-shape.h" +#include "sp-text.h" +#include "2geom/bezier-curve.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEFillBetweenMany::LPEFillBetweenMany(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + linked_paths(_("Linked path:"), _("Paths from which to take the original path data"), "linkedpaths", &wr, this) +{ + registerParameter( dynamic_cast(&linked_paths) ); + //perceived_path = true; +} + +LPEFillBetweenMany::~LPEFillBetweenMany() +{ + +} + +void LPEFillBetweenMany::doEffect (SPCurve * curve) +{ + std::vector res_pathv; + SPItem * firstObj = NULL; + for (std::vector::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); iter++) { + SPObject *obj; + if ((*iter)->ref.isAttached() && (obj = (*iter)->ref.getObject()) && SP_IS_ITEM(obj) && !(*iter)->_pathvector.empty()) { + Geom::Path linked_path; + if ((*iter)->reversed) { + linked_path = (*iter)->_pathvector.front().reverse(); + } else { + linked_path = (*iter)->_pathvector.front(); + } + + if (!res_pathv.empty()) { + linked_path = linked_path * SP_ITEM(obj)->getRelativeTransform(firstObj); + res_pathv.front().appendNew(linked_path.initialPoint()); + res_pathv.front().append(linked_path); + } else { + firstObj = SP_ITEM(obj); + res_pathv.push_back(linked_path); + } + } + } + if (!res_pathv.empty()) { + res_pathv.front().close(); + } + curve->set_pathvector(res_pathv); +} + +} // 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-fill-between-many.h b/src/live_effects/lpe-fill-between-many.h new file mode 100644 index 000000000..99ee8b15f --- /dev/null +++ b/src/live_effects/lpe-fill-between-many.h @@ -0,0 +1,36 @@ +#ifndef INKSCAPE_LPE_FILL_BETWEEN_MANY_H +#define INKSCAPE_LPE_FILL_BETWEEN_MANY_H + +/* + * Inkscape::LPEFillBetweenStrokes + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/originalpatharray.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEFillBetweenMany : public Effect { +public: + LPEFillBetweenMany(LivePathEffectObject *lpeobject); + virtual ~LPEFillBetweenMany(); + + virtual void doEffect (SPCurve * curve); + +private: + OriginalPathArrayParam linked_paths; + +private: + LPEFillBetweenMany(const LPEFillBetweenMany&); + LPEFillBetweenMany& operator=(const LPEFillBetweenMany&); +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-fill-between-strokes.cpp b/src/live_effects/lpe-fill-between-strokes.cpp new file mode 100644 index 000000000..e72979ed0 --- /dev/null +++ b/src/live_effects/lpe-fill-between-strokes.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include "live_effects/lpe-fill-between-strokes.h" + +#include "display/curve.h" +#include "sp-item.h" +#include "2geom/path.h" +#include "sp-shape.h" +#include "sp-text.h" +#include "2geom/bezier-curve.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEFillBetweenStrokes::LPEFillBetweenStrokes(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), + second_path(_("Second path:"), _("Second path from which to take the original path data"), "secondpath", &wr, this), + reverse_second(_("Reverse Second"), _("Reverses the second path order"), "reversesecond", &wr, this) +{ + registerParameter( dynamic_cast(&linked_path) ); + registerParameter( dynamic_cast(&second_path) ); + registerParameter( dynamic_cast(&reverse_second) ); + //perceived_path = true; +} + +LPEFillBetweenStrokes::~LPEFillBetweenStrokes() +{ + +} + +void LPEFillBetweenStrokes::doEffect (SPCurve * curve) +{ + if (curve) { + if ( linked_path.linksToPath() && second_path.linksToPath() && linked_path.getObject() && second_path.getObject() ) { + std::vector linked_pathv = linked_path.get_pathvector(); + std::vector second_pathv = second_path.get_pathvector(); + std::vector result_linked_pathv; + std::vector result_second_pathv; + Geom::Affine second_transform = second_path.getObject()->getRelativeTransform(linked_path.getObject()); + + for (std::vector::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) + { + result_linked_pathv.push_back((*iter)); + } + for (std::vector::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) + { + result_second_pathv.push_back((*iter) * second_transform); + } + + if ( !result_linked_pathv.empty() && !result_second_pathv.empty() && !result_linked_pathv.front().closed() ) { + if (reverse_second.get_value()) + { + result_linked_pathv.front().appendNew(result_second_pathv.front().finalPoint()); + result_linked_pathv.front().append(result_second_pathv.front().reverse()); + } + else + { + result_linked_pathv.front().appendNew(result_second_pathv.front().initialPoint()); + result_linked_pathv.front().append(result_second_pathv.front()); + } + curve->set_pathvector(result_linked_pathv); + } + else if ( !result_linked_pathv.empty() ) { + curve->set_pathvector(result_linked_pathv); + } + else if ( !result_second_pathv.empty() ) { + curve->set_pathvector(result_second_pathv); + } + } + else if ( linked_path.linksToPath() && linked_path.getObject() ) { + std::vector linked_pathv = linked_path.get_pathvector(); + std::vector result_pathv; + + for (std::vector::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) + { + result_pathv.push_back((*iter)); + } + if ( !result_pathv.empty() ) { + curve->set_pathvector(result_pathv); + } + } + else if ( second_path.linksToPath() && second_path.getObject() ) { + std::vector second_pathv = second_path.get_pathvector(); + std::vector result_pathv; + + for (std::vector::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) + { + result_pathv.push_back((*iter)); + } + if ( !result_pathv.empty() ) { + curve->set_pathvector(result_pathv); + } + } + } +} + +} // 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-fill-between-strokes.h b/src/live_effects/lpe-fill-between-strokes.h new file mode 100644 index 000000000..ec57b1852 --- /dev/null +++ b/src/live_effects/lpe-fill-between-strokes.h @@ -0,0 +1,38 @@ +#ifndef INKSCAPE_LPE_FILL_BETWEEN_STROKES_H +#define INKSCAPE_LPE_FILL_BETWEEN_STROKES_H + +/* + * Inkscape::LPEFillBetweenStrokes + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/originalpath.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEFillBetweenStrokes : public Effect { +public: + LPEFillBetweenStrokes(LivePathEffectObject *lpeobject); + virtual ~LPEFillBetweenStrokes(); + + virtual void doEffect (SPCurve * curve); + +private: + OriginalPathParam linked_path; + OriginalPathParam second_path; + BoolParam reverse_second; + +private: + LPEFillBetweenStrokes(const LPEFillBetweenStrokes&); + LPEFillBetweenStrokes& operator=(const LPEFillBetweenStrokes&); +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp new file mode 100644 index 000000000..97c0a1b8a --- /dev/null +++ b/src/live_effects/lpe-jointype.cpp @@ -0,0 +1,203 @@ +/** \file + * LPE "Join Type" implementation + */ + /* Authors: + * + * Liam P White + * + * Copyright (C) 2014 Authors + * + * Released under GNU GPL v2, read the file 'COPYING' for more information + */ + +#include + +#include "sp-shape.h" +#include "style.h" +#include "xml/repr.h" +#include "sp-paint-server.h" +#include "svg/svg-color.h" +#include "desktop-style.h" +#include "svg/css-ostringstream.h" +#include "display/curve.h" +#include "live_effects/parameter/enum.h" + +#include <2geom/path.h> +#include <2geom/svg-elliptical-arc.h> +#include "live_effects/pathoutlineprovider.h" + +#include "lpe-jointype.h" + +namespace Inkscape { +namespace LivePathEffect { + +static const Util::EnumData JoinTypeData[] = { + {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, + {LINEJOIN_ROUND, N_("Rounded"), "round"}, + {LINEJOIN_POINTY, N_("Miter"), "miter"}, + {LINEJOIN_REFLECTED, N_("Reflected"), "extrapolated"}, + {LINEJOIN_EXTRAPOLATED, N_("Extrapolated arc"), "extrp_arc"} +}; + +static const Util::EnumData CapTypeData[] = { + {butt_straight, N_("Butt"), "butt"}, + {butt_round, N_("Rounded"), "round"}, + {butt_square, N_("Square"), "square"}, + {butt_pointy, N_("Peak"), "peak"} +}; + +static const Util::EnumDataConverter CapTypeConverter(CapTypeData, sizeof(CapTypeData)/sizeof(*CapTypeData)); +static const Util::EnumDataConverter JoinTypeConverter(JoinTypeData, sizeof(JoinTypeData)/sizeof(*JoinTypeData)); + +LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 10.), + linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), + linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, join_pointy), + miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), + attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) +{ + show_orig_path = true; + registerParameter( dynamic_cast(&linecap_type) ); + registerParameter( dynamic_cast(&line_width) ); + registerParameter( dynamic_cast(&linejoin_type) ); + registerParameter( dynamic_cast(&miter_limit) ); + registerParameter( dynamic_cast(&attempt_force_join) ); + was_initialized = false; +} + +LPEJoinType::~LPEJoinType() +{ +} + +//from LPEPowerStroke -- sets fill if stroke color because we will +//be converting to a fill to make the new join. + +void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) +{ + if (SP_IS_SHAPE(lpeitem)) { + SPLPEItem* item = const_cast(lpeitem); + double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; + + SPCSSAttr *css = sp_repr_css_attr_new (); + if (lpeitem->style->stroke.isSet()) { + if (lpeitem->style->stroke.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getStrokePaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "fill", str.c_str()); + } + } else if (lpeitem->style->stroke.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "fill", c); + } else { + sp_repr_css_set_property (css, "fill", "none"); + } + } else { + sp_repr_css_unset_property (css, "fill"); + } + + sp_repr_css_set_property(css, "stroke", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); + if (!was_initialized) + { + was_initialized = true; + line_width.param_set_value(width); + } + } else { + g_warning("LPE Join Type can only be applied to paths (not groups)."); + } +} + +//from LPEPowerStroke -- sets stroke color from existing fill color + +void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) +{ + + if (SP_IS_SHAPE(lpeitem)) { + SPLPEItem *item = const_cast(lpeitem); + + SPCSSAttr *css = sp_repr_css_attr_new (); + if (lpeitem->style->fill.isSet()) { + if (lpeitem->style->fill.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getFillPaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "stroke", str.c_str()); + } + } else if (lpeitem->style->fill.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "stroke", c); + } else { + sp_repr_css_set_property (css, "stroke", "none"); + } + } else { + sp_repr_css_unset_property (css, "stroke"); + } + + Inkscape::CSSOStringStream os; + os << fabs(line_width); + sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); + + sp_repr_css_set_property(css, "fill", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); + item->updateRepr(); + } +} + + +std::vector LPEJoinType::doEffect_path(std::vector const & path_in) +{ + std::vector path_out = std::vector(); + if (path_in.empty()) + { + return path_out; + } + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + #define miter_lim ( (attempt_force_join) ? std::numeric_limits::max() : fabs(line_width * miter_limit)) + + //magic! + if (linejoin_type.get_value() <= 2) + { + p.Outline(&outlinepath, line_width / 2, static_cast( linejoin_type.get_value() ), + static_cast( linecap_type.get_value() ), miter_lim); + //fix memory leak + std::vector *pv_p = outlinepath.MakePathVector(); + path_out = *pv_p; + delete pv_p; + + } else if (linejoin_type.get_value() == 3) { + //reflected arc join + path_out = Outline::outlinePath(path_in, line_width, static_cast( linejoin_type.get_value() ), + static_cast( linecap_type.get_value() ), miter_lim); + + } else if (linejoin_type.get_value() == 4) { + //extrapolated arc join + path_out = Outline::outlinePath_extr(path_in, line_width, LINEJOIN_STRAIGHT, static_cast(linecap_type.get_value()), miter_lim); + + } + + #undef miter_lim + return path_out; +} + +} //namespace LivePathEffect +} //namespace Inkscape diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h new file mode 100755 index 000000000..db113c66a --- /dev/null +++ b/src/live_effects/lpe-jointype.h @@ -0,0 +1,43 @@ +/* Authors: + * Liam P White + * + * Copyright (C) 2014 Authors + * + * Released under GNU GPL v2, read the file COPYING for more information + */ +#ifndef INKSCAPE_LPE_JOINTYPE_H +#define INKSCAPE_LPE_JOINTYPE_H + +#include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/point.h" +#include "live_effects/parameter/enum.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEJoinType : public Effect { +public: + LPEJoinType(LivePathEffectObject *lpeobject); + virtual ~LPEJoinType(); + + virtual void doOnApply(SPLPEItem const* lpeitem); + virtual void doOnRemove(SPLPEItem const* lpeitem); + virtual std::vector doEffect_path (std::vector const & path_in); + +private: + LPEJoinType(const LPEJoinType&); + LPEJoinType& operator=(const LPEJoinType&); + + ScalarParam line_width; + EnumParam linecap_type; + EnumParam linejoin_type; + ScalarParam miter_limit; + BoolParam attempt_force_join; + bool was_initialized; +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index 6f5b75af8..f080b06e6 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -27,7 +27,8 @@ enum InterpolatorType { INTERP_LINEAR, INTERP_CUBICBEZIER, INTERP_CUBICBEZIER_JOHAN, - INTERP_SPIRO + INTERP_SPIRO, + INTERP_CUBICBEZIER_SMOOTH }; class Interpolator { @@ -133,6 +134,43 @@ private: CubicBezierJohan& operator=(const CubicBezierJohan&); }; +/// @todo invent name for this class +class CubicBezierSmooth : public Interpolator { +public: + CubicBezierSmooth(double beta = 0.2) { + _beta = beta; + }; + virtual ~CubicBezierSmooth() {}; + + virtual Path interpolateToPath(std::vector const &points) const { + Path fit; + fit.start(points.at(0)); + unsigned int num_points = points.size(); + for (unsigned int i = 1; i < num_points; ++i) { + Point p0 = points.at(i-1); + Point p1 = points.at(i); + Point dx = Point(p1[X] - p0[X], 0); + if (i == 1) { + fit.appendNew(p0, p1-0.75*dx, p1); + } else if (i == points.size() - 1) { + fit.appendNew(p0+0.75*dx, p1, p1); + } else { + fit.appendNew(p0+_beta*dx, p1-_beta*dx, p1); + } + } + return fit; + }; + + void setBeta(double beta) { + _beta = beta; + } + + double _beta; + +private: + CubicBezierSmooth(const CubicBezierSmooth&); + CubicBezierSmooth& operator=(const CubicBezierSmooth&); +}; class SpiroInterpolator : public Interpolator { public: @@ -179,6 +217,8 @@ Interpolator::create(InterpolatorType type) { return new Geom::Interpolate::CubicBezierJohan(); case INTERP_SPIRO: return new Geom::Interpolate::SpiroInterpolator(); + case INTERP_CUBICBEZIER_SMOOTH: + return new Geom::Interpolate::CubicBezierSmooth(); default: return new Geom::Interpolate::Linear(); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index acf8ab6a5..f6bc1de65 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -15,6 +15,11 @@ #include "sp-shape.h" #include "style.h" +#include "xml/repr.h" +#include "sp-paint-server.h" +#include "svg/svg-color.h" +#include "desktop-style.h" +#include "svg/css-ostringstream.h" #include "display/curve.h" #include <2geom/path.h> @@ -185,6 +190,7 @@ namespace Inkscape { namespace LivePathEffect { static const Util::EnumData InterpolatorTypeData[] = { + {Geom::Interpolate::INTERP_CUBICBEZIER_SMOOTH, N_("CubicBezierSmooth"), "CubicBezierSmooth"}, {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, @@ -222,9 +228,7 @@ static const Util::EnumData LineJoinTypeData[] = { {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, {LINEJOIN_MITER, N_("Miter"), "miter"}, {LINEJOIN_SPIRO, N_("Spiro"), "spiro"}, -#ifdef LPE_ENABLE_TEST_EFFECTS {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, -#endif }; static const Util::EnumDataConverter LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData)); @@ -232,12 +236,12 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this), sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve"), "sort_points", &wr, this, true), - interpolator_type(_("Interpolator type:"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN), + interpolator_type(_("Interpolator type:"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER), interpolator_beta(_("Smoothness:"), _("Sets the smoothness for the CubicBezierJohan interpolator; 0 = linear interpolation, 1 = smooth"), "interpolator_beta", &wr, this, 0.2), - start_linecap_type(_("Start cap:"), _("Determines the shape of the path's start"), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND), - linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_ROUND), + start_linecap_type(_("Start cap:"), _("Determines the shape of the path's start"), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_BUTT), + linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_EXTRP_MITER_ARC), miter_limit(_("Miter limit:"), _("Maximum length of the miter (in units of stroke width)"), "miter_limit", &wr, this, 4.), - end_linecap_type(_("End cap:"), _("Determines the shape of the path's end"), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND) + end_linecap_type(_("End cap:"), _("Determines the shape of the path's end"), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_BUTT) { show_orig_path = true; @@ -266,20 +270,52 @@ void LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) { if (SP_IS_SHAPE(lpeitem)) { + SPLPEItem* item = const_cast(lpeitem); std::vector points; Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector(); - double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; + double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.; + + SPCSSAttr *css = sp_repr_css_attr_new (); + if (lpeitem->style->stroke.isSet()) { + if (lpeitem->style->stroke.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getStrokePaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "fill", str.c_str()); + } + } else if (lpeitem->style->stroke.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "fill", c); + } else { + sp_repr_css_set_property (css, "fill", "none"); + } + } else { + sp_repr_css_unset_property (css, "fill"); + } + + sp_repr_css_set_property(css, "stroke", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); + + item->updateRepr(); if (pathv.empty()) { - points.push_back( Geom::Point(0.,width) ); + points.push_back( Geom::Point(0.2,width) ); points.push_back( Geom::Point(0.5,width) ); - points.push_back( Geom::Point(1.,width) ); + points.push_back( Geom::Point(0.8,width) ); } else { Geom::Path const &path = pathv.front(); Geom::Path::size_type const size = path.size_default(); - points.push_back( Geom::Point(0.,width) ); + if (!path.closed()) { + points.push_back( Geom::Point(0.2,width) ); + } points.push_back( Geom::Point(0.5*size,width) ); if (!path.closed()) { - points.push_back( Geom::Point(size,width) ); + points.push_back( Geom::Point(size - 0.2,width) ); } } offset_points.param_set_and_write_new_value(points); @@ -288,6 +324,45 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) } } +void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem) +{ + if (SP_IS_SHAPE(lpeitem)) { + SPLPEItem *item = const_cast(lpeitem); + SPCSSAttr *css = sp_repr_css_attr_new (); + if (lpeitem->style->fill.isSet()) { + if (lpeitem->style->fill.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getFillPaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "stroke", str.c_str()); + } + } else if (lpeitem->style->fill.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "stroke", c); + } else { + sp_repr_css_set_property (css, "stroke", "none"); + } + } else { + sp_repr_css_unset_property (css, "stroke"); + } + + Inkscape::CSSOStringStream os; + os << offset_points.median_width() * 2; + sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); + + sp_repr_css_set_property(css, "fill", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); + + item->updateRepr(); + } +} + void LPEPowerStroke::adjustForNewPath(std::vector const & path_in) { diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index 7bc736820..a773434aa 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -25,9 +25,11 @@ public: LPEPowerStroke(LivePathEffectObject *lpeobject); virtual ~LPEPowerStroke(); + virtual std::vector doEffect_path (std::vector const & path_in); virtual void doOnApply(SPLPEItem const* lpeitem); + virtual void doOnRemove(SPLPEItem const* lpeitem); // methods called by path-manipulator upon edits void adjustForNewPath(std::vector const & path_in); diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index efdda686a..37cc3dc62 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -18,10 +18,14 @@ ink_common_sources += \ live_effects/parameter/path.h \ live_effects/parameter/originalpath.cpp \ live_effects/parameter/originalpath.h \ + live_effects/parameter/originalpatharray.cpp \ + live_effects/parameter/originalpatharray.h \ live_effects/parameter/powerstrokepointarray.cpp \ live_effects/parameter/powerstrokepointarray.h \ live_effects/parameter/text.cpp \ live_effects/parameter/text.h \ + live_effects/parameter/transformedpoint.cpp \ + live_effects/parameter/transformedpoint.h \ live_effects/parameter/unit.cpp \ live_effects/parameter/unit.h \ live_effects/parameter/vector.cpp \ diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp new file mode 100644 index 000000000..29e4c409c --- /dev/null +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -0,0 +1,486 @@ +/* + * Copyright (C) Johan Engelen 2008 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/originalpatharray.h" + +#include +#include +#include +#include + +#include + +#include "inkscape.h" +#include "icon-size.h" +#include "widgets/icon.h" +#include "ui/clipboard.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "originalpath.h" +#include "uri.h" +#include "display/curve.h" + +#include +#include <2geom/coord.h> +#include <2geom/point.h> +#include "sp-shape.h" +#include "sp-text.h" +#include "live_effects/effect.h" + +#include "verbs.h" +#include "document-undo.h" +#include "document.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class OriginalPathArrayParam::ModelColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + + ModelColumns() + { + add(_colObject); + add(_colLabel); + add(_colReverse); + } + virtual ~ModelColumns() {} + + Gtk::TreeModelColumn _colObject; + Gtk::TreeModelColumn _colLabel; + Gtk::TreeModelColumn _colReverse; +}; + +OriginalPathArrayParam::OriginalPathArrayParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect ) +: Parameter(label, tip, key, wr, effect), + _vector(), + _tree(), + _text_renderer(), + _toggle_renderer(), + _scroller() +{ + _model = new ModelColumns(); + _store = Gtk::TreeStore::create(*_model); + _tree.set_model(_store); + + _tree.set_reorderable(true); + _tree.enable_model_drag_dest (Gdk::ACTION_MOVE); + + _text_renderer = manage(new Gtk::CellRendererText()); + int nameColNum = _tree.append_column(_("Name"), *_text_renderer) - 1; + _name_column = _tree.get_column(nameColNum); + _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); + + _tree.set_expander_column( *_tree.get_column(nameColNum) ); + _tree.set_search_column(_model->_colLabel); + + Gtk::CellRendererToggle * _toggle_renderer = manage(new Gtk::CellRendererToggle()); + int toggleColNum = _tree.append_column(_("Reverse"), *_toggle_renderer) - 1; + Gtk::TreeViewColumn* col = _tree.get_column(toggleColNum); + _toggle_renderer->set_activatable(true); + _toggle_renderer->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled)); + col->add_attribute(_toggle_renderer->property_active(), _model->_colReverse); + + _scroller.add(_tree); + _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + _scroller.set_shadow_type(Gtk::SHADOW_IN); + + oncanvas_editable = true; + +} + +OriginalPathArrayParam::~OriginalPathArrayParam() +{ + while (!_vector.empty()) { + PathAndDirection *w = _vector.back(); + _vector.pop_back(); + unlink(w); + delete w; + } + delete _model; +} + +void OriginalPathArrayParam::on_reverse_toggled(const Glib::ustring& path) +{ + Gtk::TreeModel::iterator iter = _store->get_iter(path); + Gtk::TreeModel::Row row = *iter; + PathAndDirection *w = row[_model->_colObject]; + row[_model->_colReverse] = !row[_model->_colReverse]; + w->reversed = row[_model->_colReverse]; + + gchar * full = param_getSVGValue(); + param_write_to_repr(full); + g_free(full); + DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Link path parameter to path")); +} + +void OriginalPathArrayParam::param_set_default() +{ + +} + +Gtk::Widget* OriginalPathArrayParam::param_newWidget() +{ + Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox()); + Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox()); + + vbox->pack_start(_scroller, Gtk::PACK_EXPAND_WIDGET); + + + { // Paste path to link button + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_PASTE, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_link_button_click)); + hbox->pack_start(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Link to path")); + } + + { // Remove linked path + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_REMOVE, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_remove_button_click)); + hbox->pack_start(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Remove Path")); + } + + { // Move Down + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_DOWN, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_down_button_click)); + hbox->pack_end(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Move Down")); + } + + { // Move Down + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_UP, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_up_button_click)); + hbox->pack_end(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Move Up")); + } + + vbox->pack_end(*hbox, Gtk::PACK_SHRINK); + + vbox->show_all_children(true); + + return vbox; +} + +bool OriginalPathArrayParam::_selectIndex(const Gtk::TreeIter& iter, int* i) +{ + if ((*i)-- <= 0) { + _tree.get_selection()->select(iter); + return true; + } + return false; +} + +void OriginalPathArrayParam::on_up_button_click() +{ + Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + + int i = -1; + std::vector::iterator piter = _vector.begin(); + for (std::vector::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, iter++) { + if (*iter == row[_model->_colObject]) { + _vector.erase(iter); + _vector.insert(piter, row[_model->_colObject]); + break; + } + } + + gchar * full = param_getSVGValue(); + param_write_to_repr(full); + g_free(full); + + DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Move path up")); + + _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_selectIndex), &i)); + } +} + +void OriginalPathArrayParam::on_down_button_click() +{ + Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + + int i = 0; + for (std::vector::iterator iter = _vector.begin(); iter != _vector.end(); i++, iter++) { + if (*iter == row[_model->_colObject]) { + std::vector::iterator niter = _vector.erase(iter); + if (niter != _vector.end()) { + niter++; + i++; + } + _vector.insert(niter, row[_model->_colObject]); + break; + } + } + + gchar * full = param_getSVGValue(); + param_write_to_repr(full); + g_free(full); + + DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Move path down")); + + _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_selectIndex), &i)); + } +} + +void OriginalPathArrayParam::on_remove_button_click() +{ + Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + remove_link(row[_model->_colObject]); + + gchar * full = param_getSVGValue(); + param_write_to_repr(full); + g_free(full); + + DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Remove path")); + } + +} + +void +OriginalPathArrayParam::on_link_button_click() +{ + Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); + Glib::ustring pathid = cm->getShapeOrTextObjectId(SP_ACTIVE_DESKTOP); + + if (pathid == "") { + return; + } + // add '#' at start to make it an uri. + pathid.insert(pathid.begin(), '#'); + + Inkscape::SVGOStringStream os; + bool foundOne = false; + for (std::vector::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) { + if (foundOne) { + os << "|"; + } else { + foundOne = true; + } + os << (*iter)->href << "," << ((*iter)->reversed ? "1" : "0"); + } + + if (foundOne) { + os << "|"; + } + + os << pathid.c_str() << ",0"; + + param_write_to_repr(os.str().c_str()); + DocumentUndo::done(param_effect->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Link path parameter to path")); +} + +void OriginalPathArrayParam::unlink(PathAndDirection* to) +{ + to->linked_modified_connection.disconnect(); + to->linked_delete_connection.disconnect(); + to->ref.detach(); + to->_pathvector = Geom::PathVector(); + if (to->href) { + g_free(to->href); + to->href = NULL; + } +} + +void OriginalPathArrayParam::remove_link(PathAndDirection* to) +{ + unlink(to); + for (std::vector::iterator iter = _vector.begin(); iter != _vector.end(); iter++) { + if (*iter == to) { + PathAndDirection *w = *iter; + _vector.erase(iter); + delete w; + return; + } + } +} + +void OriginalPathArrayParam::linked_delete(SPObject */*deleted*/, PathAndDirection* to) +{ + //remove_link(to); + + gchar * full = param_getSVGValue(); + param_write_to_repr(full); + g_free(full); +} + +bool OriginalPathArrayParam::_updateLink(const Gtk::TreeIter& iter, PathAndDirection* pd) +{ + Gtk::TreeModel::Row row = *iter; + if (row[_model->_colObject] == pd) { + SPObject *obj = pd->ref.getObject(); + row[_model->_colLabel] = obj && obj->getId() ? ( obj->label() ? obj->label() : obj->getId() ) : pd->href; + return true; + } + return false; +} + +void OriginalPathArrayParam::linked_changed(SPObject */*old_obj*/, SPObject *new_obj, PathAndDirection* to) +{ + to->linked_delete_connection.disconnect(); + to->linked_modified_connection.disconnect(); + to->linked_transformed_connection.disconnect(); + + if (new_obj && SP_IS_ITEM(new_obj)) { + to->linked_delete_connection = new_obj->connectDelete(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_delete), to)); + to->linked_modified_connection = new_obj->connectModified(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_modified), to)); + to->linked_transformed_connection = SP_ITEM(new_obj)->connectTransformed(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_transformed), to)); + + linked_modified(new_obj, SP_OBJECT_MODIFIED_FLAG, to); + } else { + to->_pathvector = Geom::PathVector(); + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); + _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); + } +} + +void OriginalPathArrayParam::linked_transformed(Geom::Affine const *mp, SPItem* original, PathAndDirection* to) +{ + +} + +void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint flags, PathAndDirection* to) +{ + if (!to) { + return; + } + SPCurve *curve = NULL; + if (SP_IS_SHAPE(linked_obj)) { + curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE(); + } + if (SP_IS_TEXT(linked_obj)) { + curve = SP_TEXT(linked_obj)->getNormalizedBpath(); + } + + if (curve == NULL) { + // curve invalid, set empty pathvector + to->_pathvector = Geom::PathVector(); + } else { + to->_pathvector = curve->get_pathvector(); + curve->unref(); + } +} + +void OriginalPathArrayParam::linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to) +{ + if (!to) { + return; + } + setPathVector(linked_obj, flags, to); + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); + _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); +} + +//void PathParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item) +//{ +// linked_transformed_callback(rel_transf, moved_item); +//} + +bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue) +{ + if (strvalue) { + while (!_vector.empty()) { + PathAndDirection *w = _vector.back(); + unlink(w); + _vector.pop_back(); + delete w; + } + _store->clear(); + + gchar ** strarray = g_strsplit(strvalue, "|", 0); + for (gchar ** iter = strarray; *iter != NULL; iter++) { + if ((*iter)[0] == '#') { + gchar ** substrarray = g_strsplit(*iter, ",", 0); + PathAndDirection* w = new PathAndDirection((SPObject *)param_effect->getLPEObj()); + w->href = g_strdup(*substrarray); + w->reversed = *(substrarray+1) != NULL && (*(substrarray+1))[0] == '1'; + + w->linked_changed_connection = w->ref.changedSignal().connect(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::linked_changed), w)); + w->ref.attach(URI(w->href)); + + _vector.push_back(w); + + Gtk::TreeModel::iterator iter = _store->append(); + Gtk::TreeModel::Row row = *iter; + SPObject *obj = w->ref.getObject(); + + row[_model->_colObject] = w; + row[_model->_colLabel] = obj ? ( obj->label() ? obj->label() : obj->getId() ) : w->href; + row[_model->_colReverse] = w->reversed; + g_strfreev (substrarray); + } + } + g_strfreev (strarray); + return true; + } + return false; +} + +gchar * OriginalPathArrayParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + bool foundOne = false; + for (std::vector::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) { + if (foundOne) { + os << "|"; + } else { + foundOne = true; + } + os << (*iter)->href << "," << ((*iter)->reversed ? "1" : "0"); + } + gchar * str = g_strdup(os.str().c_str()); + return str; +} + +} /* 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/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h new file mode 100644 index 000000000..865a3f8e5 --- /dev/null +++ b/src/live_effects/parameter/originalpatharray.h @@ -0,0 +1,123 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALPATHARRAY_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALPATHARRAY_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2008 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include +#include +#include +#include + +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/path-reference.h" + +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "path-reference.h" +#include "sp-object.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class PathAndDirection { +public: + PathAndDirection(SPObject *owner) + : href(NULL), + ref(owner), + _pathvector(Geom::PathVector()), + reversed(false) + { + + } + gchar *href; + URIReference ref; + //SPItem *obj; + std::vector _pathvector; + bool reversed; + + sigc::connection linked_changed_connection; + sigc::connection linked_delete_connection; + sigc::connection linked_modified_connection; + sigc::connection linked_transformed_connection; +}; + +class OriginalPathArrayParam : public Parameter { +public: + class ModelColumns; + + OriginalPathArrayParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect); + + virtual ~OriginalPathArrayParam(); + + virtual Gtk::Widget * param_newWidget(); + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + virtual void param_set_default(); + + /** Disable the canvas indicators of parent class by overriding this method */ + virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; + /** Disable the canvas indicators of parent class by overriding this method */ + virtual void addCanvasIndicators(SPLPEItem const* /*lpeitem*/, std::vector & /*hp_vec*/) {}; + + std::vector _vector; + +protected: + bool _updateLink(const Gtk::TreeIter& iter, PathAndDirection* pd); + bool _selectIndex(const Gtk::TreeIter& iter, int* i); + void unlink(PathAndDirection* to); + void remove_link(PathAndDirection* to); + void setPathVector(SPObject *linked_obj, guint flags, PathAndDirection* to); + + void linked_changed(SPObject *old_obj, SPObject *new_obj, PathAndDirection* to); + void linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to); + void linked_transformed(Geom::Affine const *mp, SPItem *original, PathAndDirection* to); + void linked_delete(SPObject *deleted, PathAndDirection* to); + + ModelColumns *_model; + Glib::RefPtr _store; + Gtk::TreeView _tree; + Gtk::CellRendererText *_text_renderer; + Gtk::CellRendererToggle *_toggle_renderer; + Gtk::TreeView::Column *_name_column; + Gtk::ScrolledWindow _scroller; + + void on_link_button_click(); + void on_remove_button_click(); + void on_up_button_click(); + void on_down_button_click(); + void on_reverse_toggled(const Glib::ustring& path); + +private: + OriginalPathArrayParam(const OriginalPathArrayParam&); + OriginalPathArrayParam& operator=(const OriginalPathArrayParam&); +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif + +/* + 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/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index fecdfeda8..ac0000b1a 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -6,6 +6,7 @@ #include +#include "ui/dialog/lpe-powerstroke-properties.h" #include "live_effects/parameter/powerstrokepointarray.h" #include "live_effects/effect.h" @@ -102,6 +103,23 @@ PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewi } } +float PowerStrokePointArrayParam::median_width() +{ + size_t size = _vector.size(); + if (size > 0) + { + if (size % 2 == 0) + { + return (_vector[size / 2 - 1].y() + _vector[size / 2].y()) / 2; + } + else + { + return _vector[size / 2].y(); + } + } + return 1; +} + void PowerStrokePointArrayParam::set_pwd2(Geom::Piecewise > const & pwd2_in, Geom::Piecewise > const & pwd2_normal_in) { @@ -117,7 +135,7 @@ PowerStrokePointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotMode knot_mode = mode; knot_color = color; } - +/* class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity { public: PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index); @@ -127,7 +145,7 @@ public: virtual Geom::Point knot_get() const; virtual void knot_click(guint state); - /** Checks whether the index falls within the size of the parameter's vector */ + /** Checks whether the index falls within the size of the parameter's vector / bool valid_index(unsigned int index) const { return (_pparam->_vector.size() > index); }; @@ -135,7 +153,7 @@ public: private: PowerStrokePointArrayParam *_pparam; unsigned int _index; -}; +};*/ PowerStrokePointArrayParamKnotHolderEntity::PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index) : _pparam(p), @@ -181,6 +199,12 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const return canvas_point; } +void PowerStrokePointArrayParamKnotHolderEntity::knot_set_offset(Geom::Point offset) +{ + _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y() / 2); + this->parent_holder->knot_ungrabbed_handler(this->knot); +} + void PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state) { @@ -223,10 +247,15 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state) // add knot to knotholder PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(_pparam, _index+1); e->create( this->desktop, this->item, parent_holder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Stroke width control point: drag to alter the stroke width. Ctrl+click adds a control point, Ctrl+Alt+click deletes it."), + _("Stroke width control point: drag to alter the stroke width. Ctrl+click adds a control point, Ctrl+Alt+click deletes it, Shift+click launches width dialog."), _pparam->knot_shape, _pparam->knot_mode, _pparam->knot_color); parent_holder->add(e); } + } + else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) + { + Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), _pparam->_vector.at(_index).y() * 2); + Inkscape::UI::Dialogs::PowerstrokePropertiesDialog::showDialog(this->desktop, offset, this); } } @@ -235,7 +264,7 @@ void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, S for (unsigned int i = 0; i < _vector.size(); ++i) { PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Stroke width control point: drag to alter the stroke width. Ctrl+click adds a control point, Ctrl+Alt+click deletes it."), + _("Stroke width control point: drag to alter the stroke width. Ctrl+click adds a control point, Ctrl+Alt+click deletes it, Shift+click launches width dialog."), knot_shape, knot_mode, knot_color); knotholder->add(e); } diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index e1fa440f2..911bbc82d 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -20,8 +20,6 @@ namespace Inkscape { namespace LivePathEffect { -class PowerStrokePointArrayParamKnotHolderEntity; - class PowerStrokePointArrayParam : public ArrayParam { public: PowerStrokePointArrayParam( const Glib::ustring& label, @@ -37,6 +35,8 @@ public: void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + float median_width(); + virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); @@ -60,6 +60,25 @@ private: Geom::Piecewise > last_pwd2_normal; }; +class PowerStrokePointArrayParamKnotHolderEntity : public KnotHolderEntity { +public: + PowerStrokePointArrayParamKnotHolderEntity(PowerStrokePointArrayParam *p, unsigned int index); + virtual ~PowerStrokePointArrayParamKnotHolderEntity() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + virtual void knot_set_offset(Geom::Point offset); + virtual void knot_click(guint state); + + /** Checks whether the index falls within the size of the parameter's vector */ + bool valid_index(unsigned int index) const { + return (_pparam->_vector.size() > index); + }; + +private: + PowerStrokePointArrayParam *_pparam; + unsigned int _index; +}; } //namespace LivePathEffect diff --git a/src/live_effects/parameter/transformedpoint.cpp b/src/live_effects/parameter/transformedpoint.cpp new file mode 100644 index 000000000..f5b01e267 --- /dev/null +++ b/src/live_effects/parameter/transformedpoint.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/transformedpoint.h" +#include "sp-lpe-item.h" +#include "knotholder.h" +#include "svg/svg.h" +#include "svg/stringstream.h" + +#include "live_effects/effect.h" +#include "desktop.h" +#include "verbs.h" + +namespace Inkscape { + +namespace LivePathEffect { + +TransformedPointParam::TransformedPointParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, Geom::Point default_vector, + bool dontTransform) + : Parameter(label, tip, key, wr, effect), + defvalue(default_vector), + origin(0.,0.), + vector(default_vector), + noTransform(dontTransform) +{ + vec_knot_shape = SP_KNOT_SHAPE_DIAMOND; + vec_knot_mode = SP_KNOT_MODE_XOR; + vec_knot_color = 0xffffb500; +} + +TransformedPointParam::~TransformedPointParam() +{ + +} + +void +TransformedPointParam::param_set_default() +{ + setOrigin(Geom::Point(0.,0.)); + setVector(defvalue); +} + +bool +TransformedPointParam::param_readSVGValue(const gchar * strvalue) +{ + gchar ** strarray = g_strsplit(strvalue, ",", 4); + if (!strarray) { + return false; + } + double val[4]; + unsigned int i = 0; + while (i < 4 && strarray[i]) { + if (sp_svg_number_read_d(strarray[i], &val[i]) != 0) { + i++; + } else { + break; + } + } + g_strfreev (strarray); + if (i == 4) { + setOrigin( Geom::Point(val[0], val[1]) ); + setVector( Geom::Point(val[2], val[3]) ); + return true; + } + return false; +} + +gchar * +TransformedPointParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + os << origin << " , " << vector; + gchar * str = g_strdup(os.str().c_str()); + return str; +} + +Gtk::Widget * +TransformedPointParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredVector * pointwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredVector( param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() ) ); + pointwdg->setPolarCoords(); + pointwdg->setValue( vector, origin ); + pointwdg->clearProgrammatically(); + pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change vector parameter")); + + Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); + static_cast(hbox)->pack_start(*pointwdg, true, true); + static_cast(hbox)->show_all_children(); + + return dynamic_cast (hbox); +} + +void +TransformedPointParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector) +{ + setValues(new_origin, new_vector); + gchar * str = param_getSVGValue(); + param_write_to_repr(str); + g_free(str); +} + +void +TransformedPointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) +{ + if (!noTransform) { + set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() ); + } +} + + +void +TransformedPointParam::set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) +{ + vec_knot_shape = shape; + vec_knot_mode = mode; + vec_knot_color = color; +} + +void +TransformedPointParam::set_oncanvas_color(guint32 color) +{ + vec_knot_color = color; +} + +class TransformedPointParamKnotHolderEntity_Vector : public KnotHolderEntity { +public: + TransformedPointParamKnotHolderEntity_Vector(TransformedPointParam *p) : param(p) { } + virtual ~TransformedPointParamKnotHolderEntity_Vector() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/) { + Geom::Point const s = p - param->origin; + /// @todo implement angle snapping when holding CTRL + param->setVector(s); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + }; + virtual Geom::Point knot_get() const{ + return param->origin + param->vector; + }; + virtual void knot_click(guint /*state*/){ + g_print ("This is the vector handle associated to parameter '%s'\n", param->param_key.c_str()); + }; + +private: + TransformedPointParam *param; +}; + +void +TransformedPointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ + TransformedPointParamKnotHolderEntity_Vector *vector_e = new TransformedPointParamKnotHolderEntity_Vector(this); + vector_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color); + knotholder->add(vector_e); +} + +} /* 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/parameter/transformedpoint.h b/src/live_effects/parameter/transformedpoint.h new file mode 100644 index 000000000..37af8b98f --- /dev/null +++ b/src/live_effects/parameter/transformedpoint.h @@ -0,0 +1,87 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_TRANSFORMED_POINT_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TRANSFORMED_POINT_H + +/* + * Inkscape::LivePathEffectParameters + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include <2geom/point.h> + +#include "live_effects/parameter/parameter.h" + +#include "knot-holder-entity.h" + +namespace Inkscape { + +namespace LivePathEffect { + + +class TransformedPointParam : public Parameter { +public: + TransformedPointParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + Geom::Point default_vector = Geom::Point(1,0), + bool dontTransform = false); + virtual ~TransformedPointParam(); + + virtual Gtk::Widget * param_newWidget(); + inline const gchar *handleTip() const { return param_tooltip.c_str(); } + + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + + Geom::Point getVector() const { return vector; }; + Geom::Point getOrigin() const { return origin; }; + void setValues(Geom::Point const &new_origin, Geom::Point const &new_vector) { setVector(new_vector); setOrigin(new_origin); }; + void setVector(Geom::Point const &new_vector) { vector = new_vector; }; + void setOrigin(Geom::Point const &new_origin) { origin = new_origin; }; + virtual void param_set_default(); + + void set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector); + + virtual void param_transform_multiply(Geom::Affine const &postmul, bool set); + + void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + //void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + void set_oncanvas_color(guint32 color); + + virtual bool providesKnotHolderEntities() const { return true; } + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + +private: + TransformedPointParam(const TransformedPointParam&); + TransformedPointParam& operator=(const TransformedPointParam&); + + Geom::Point defvalue; + + Geom::Point origin; + Geom::Point vector; + + bool noTransform; + + /// The looks of the vector and origin knots oncanvas + SPKnotShapeType vec_knot_shape; + SPKnotModeType vec_knot_mode; + guint32 vec_knot_color; +// SPKnotShapeType ori_knot_shape; +// SPKnotModeType ori_knot_mode; +// guint32 ori_knot_color; + +// friend class VectorParamKnotHolderEntity_Origin; + friend class TransformedPointParamKnotHolderEntity_Vector; +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h new file mode 100755 index 000000000..8aa2e38ad --- /dev/null +++ b/src/live_effects/pathoutlineprovider.h @@ -0,0 +1,766 @@ +#pragma once + +#include <2geom/path.h> +#include <2geom/circle.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/shape.h> +#include <2geom/transforms.h> +#include <2geom/path-sink.h> + +#include +#include + +enum LineJoinType { + LINEJOIN_STRAIGHT, + LINEJOIN_ROUND, + LINEJOIN_POINTY, + LINEJOIN_REFLECTED, + LINEJOIN_EXTRAPOLATED +}; + +namespace Geom +{ + /** + * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/Circle-CircleIntersection.html + * + * @return 0 if no intersection + * @return 1 if one circle is contained in the other + * @return 2 if intersections are found (they are written to p0 and p1) + */ + static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, + Point & p0, Point & p1) + { + Point X0 = circle0.center(); + double r0 = circle0.ray(); + Point X1 = circle1.center(); + double r1 = circle1.ray(); + + /* dx and dy are the vertical and horizontal distances between + * the circle centers. + */ + Point D = X1 - X0; + + /* Determine the straight-line distance between the centers. */ + double d = L2(D); + + /* Check for solvability. */ + if (d > (r0 + r1)) + { + /* no solution. circles do not intersect. */ + return 0; + } + if (d <= fabs(r0 - r1)) + { + /* no solution. one circle is contained in the other */ + return 1; + } + + /* 'point 2' is the point where the line through the circle + * intersection points crosses the line between the circle + * centers. + */ + + /* Determine the distance from point 0 to point 2. */ + double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; + + /* Determine the coordinates of point 2. */ + Point p2 = X0 + D * (a/d); + + /* Determine the distance from point 2 to either of the + * intersection points. + */ + double h = std::sqrt((r0*r0) - (a*a)); + + /* Now determine the offsets of the intersection points from + * point 2. + */ + Point r = (h/d)*rot90(D); + + /* Determine the absolute intersection points. */ + p0 = p2 + r; + p1 = p2 - r; + + return 2; + } + /** + * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. + * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). + */ + static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) + { + D2 dM=derivative(curve); + if ( are_near(L2sq(dM(t)),0.) ) { + dM=derivative(dM); + } + if ( are_near(L2sq(dM(t)),0.) ) { // try second time + dM=derivative(dM); + } + Piecewise > unitv = unitVector(dM,tol); + Piecewise dMlength = dot(Piecewise >(dM),unitv); + Piecewise k = cross(derivative(unitv),unitv); + k = divide(k,dMlength,tol,3); + double curv = k(t); // note that this value is signed + + Geom::Point normal = unitTangentAt(curve, t).cw(); + double radius = 1/curv; + Geom::Point center = curve(t) + radius*normal; + return Geom::Circle(center, fabs(radius)); + } + + static std::vector split_at_cusps(const Geom::Path& in) + { + Geom::PathVector out = Geom::PathVector(); + Geom::Path temp = Geom::Path(); + + for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) + { + temp = Geom::Path(); + temp.append(in[path_descr]); + out.push_back(temp); + } + + return out; + } + + static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) + { + std::vector temp; + sbasis_to_bezier(temp, sbasis_in, 4); + return Geom::CubicBezier( temp ); + } + + static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, + Geom::Point const & origin_b, Geom::Point const & vector_b) + { + Geom::Coord denom = cross(vector_b, vector_a); + if (!Geom::are_near(denom,0.)){ + Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + return origin_a + t * vector_a; + } + return boost::none; + } +} + +namespace Outline +{ + + typedef Geom::D2 D2SB; + typedef Geom::Piecewise PWD2; + + static void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve*cbc2, Geom::Point endPt, double miter_limit) +{ + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (cross.empty()) + { + Geom::Path pth; + pth.append(*cbc1); + + Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); + + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + + Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(cbc1->toSBasis()), 0.); + Geom::Circle circle2 = Geom::touching_circle(cbc2->toSBasis(), 0); + + Geom::Point points[2]; + int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); + if (solutions == 2) + { + Geom::Point sol(0,0); + if ( dot(tang2,points[0]-endPt) > 0 ) + { + // points[0] is bad, choose points[1] + sol = points[1]; + } + else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] + // points[1] is bad, choose points[0] + sol = points[0]; + } + else + { + // both points are good, choose nearest + sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? + points[0] : points[1]; + } + Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); + Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + + if (arc0) + { + path_builder.append (arc0->toSBasis()); + delete arc0; + arc0 = NULL; + } + + if (arc1) + { + path_builder.append (arc1->toSBasis()); + delete arc1; + arc1 = NULL; + } + } + else + { + path_builder.appendNew (endPt); + } + } + else + { + path_builder.appendNew (endPt); + } +} + static Geom::Path half_outline_extrp(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) + { + Geom::PathVector pv = split_at_cusps(path_in); + unsigned m; + Path path_outline = Path(); + Path path_tangent = Path(); + + Geom::Point initialPoint; + Geom::Point endPoint; + + Geom::Path path_builder = Geom::Path(); + Geom::PathVector * pathvec; + + //load the first portion in before the loop starts + { + path_outline = Path(); + path_outline.LoadPath(pv[0], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + //now half of first cusp has been loaded + + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + //instead of array accessing twice, dereferencing used for clarity + initialPoint = (*pathvec)[0].initialPoint(); + + path_builder.start(initialPoint); + path_builder.append( (*pathvec)[0] ); + + path_outline = Path(); + path_outline.LoadPath(pv[1], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + + path_builder.append( (*pathvec)[0] ); + + //always set pointers null after deleting + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + for (m = 2; m < pv.size(); m++) + { + path_outline = Path(); + path_outline.LoadPath(pv[m], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + path_builder.append( (*pathvec)[0] ); + + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + return path_builder; + } + + //Create a reflected outline join. + //Note: it is generally recommended to let half_outline do this for you! + //path_builder: the path to append the curves to + //cbc1: the curve before the join + //cbc2: the curve after the join + //endPt: the point to end at + //miter_limit: the miter parameter + static void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit) + { + //the most important work for the reflected join is done here + + //determine where we are in the path. If we're on the inside, ignore + //and just lineTo. On the outside, we'll do a little reflection magic :) + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (cross.empty()) + { + //probably on the outside of the corner + Geom::Path pth; + pth.append(*cbc1); + + Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); + + //reflect curves along the bevel + D2SB newcurve1 = pth.toPwSb()[0] * + Geom::reflection ( -Geom::rot90(tang1) , + cbc1->finalPoint() ); + + Geom::CubicBezier bzr1 = sbasis_to_cubicbezier(Geom::reverse(newcurve1)); + + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + D2SB newcurve2 = pth.toPwSb()[0] * + Geom::reflection ( -Geom::rot90(tang2) , + cbc2->initialPoint() ); + Geom::CubicBezier bzr2 = sbasis_to_cubicbezier(Geom::reverse(newcurve2)); + + cross = Geom::crossings(bzr1, bzr2); + if ( cross.empty() ) + { + //std::cout << "Oops, no crossings!" << std::endl; + //curves didn't cross; default to miter + /*boost::optional p = intersection_point (cbc1->finalPoint(), tang1, + cbc2->initialPoint(), tang2); + if (p) + { + path_builder.appendNew (*p); + }*/ + //bevel + path_builder.appendNew( endPt ); + } + else + { + //join + std::pair sub1 = bzr1.subdivide(cross[0].ta); + std::pair sub2 = bzr2.subdivide(cross[0].tb); + + //@TODO joins have a strange tendency to cross themselves twice. Check this. + + //sections commented out are for general stability + path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); + path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); + } + } + else // cross.empty() + { + //probably on the inside of the corner + path_builder.appendNew ( endPt ); + } + } + + /** @brief Converts a path to one half of an outline. + * path_in: The input path to use. (To create the other side use path_in.reverse() ) + * line_width: the line width to use (usually you want to divide this by 2) + * linecap_type: (not used here) the cap to apply. Passed to libvarot. + * miter_limit: the miter parameter + */ + static Geom::Path half_outline(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) + { + Geom::PathVector pv = split_at_cusps(path_in); + unsigned m; + Path path_outline = Path(); + Path path_tangent = Path(); + //needed for closing the path + Geom::Point initialPoint; + Geom::Point endPoint; + + //some issues prevented me from using a PathBuilder here + //it seems like PathBuilder::peek() gave me a null reference exception + //and I was unable to get a stack trace on Windows, so had to switch to Linux + //to see what the hell was wrong. :( + //I wasted five hours opening it in IDAPro, VS2012, and GDB Windows + + /*Program received signal SIGSEGV, Segmentation fault. + 0x00000000006539ac in get_curves (this=0x0) + at /usr/include/c++/4.6/bits/locale_facets.h:1077 + 1077 { return __c; } + */ + + Geom::Path path_builder = Geom::Path(); + Geom::PathVector * pathvec; + + //load the first portion in before the loop starts + { + path_outline = Path(); + path_outline.LoadPath(pv[0], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + //now half of first cusp has been loaded + + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + //instead of array accessing twice, dereferencing used for clarity + initialPoint = (*pathvec)[0].initialPoint(); + + path_builder.start(initialPoint); + path_builder.append( (*pathvec)[0] ); + + path_outline = Path(); + path_outline.LoadPath(pv[1], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + + path_builder.append( (*pathvec)[0] ); + + //always set pointers null after deleting + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + for (m = 2; m < pv.size(); m++) + { + path_outline = Path(); + path_outline.LoadPath(pv[m], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + path_builder.append( (*pathvec)[0] ); + + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + return path_builder; + } + + static Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim) + { + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + Geom::PathVector path_out; + for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) + { + if (path_in[lmnop].size() > 1) + { + Geom::Path p_init; + Geom::Path p_rev; + Geom::PathBuilder pb = Geom::PathBuilder(); + + if ( !path_in[lmnop].closed() ) + { + p_init = Outline::half_outline( path_in[lmnop], -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline( path_in[lmnop].reverse(), -line_width, butt, + miter_lim ); + + pb.moveTo(p_init.initialPoint() ); + pb.append(p_init); + + //cap + if (butt == butt_straight) { + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } + + pb.append(p_rev); + + if (butt == butt_straight) { + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); + //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); + + pb.lineTo(p_init.initialPoint() ); + } + } + else + { + //final join + //refer to half_outline for documentation + Geom::Path p_almost = path_in[lmnop]; + p_almost.appendNew ( path_in[lmnop].initialPoint() ); + p_init = Outline::half_outline( p_almost, -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline( p_almost.reverse(), -line_width, butt, + miter_lim ); + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + + //this is a kludge, because I can't find how to make this work properly + bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), + path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == + (path_in[lmnop] [path_in[lmnop].size()].length())); + + p_almost = p_init; + if (lastIsLinear) + { + p_almost.erase_last(); p_almost.erase_last(); + } + + //outside test + Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); + Geom::Curve* cbc2 = p_almost[0].duplicate(); + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //this is the outside path + + //reuse the old one + p_init = p_almost; + Outline::reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside, carry on :-) + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + + p_almost = p_rev; + if (lastIsLinear) + { + p_almost.erase(p_almost.begin() ); + p_almost.erase(p_almost.begin() ); + } + + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + + cbc1 = p_almost[p_almost.size() - 1].duplicate(); + cbc2 = p_almost[0].duplicate(); + + cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //outside path + + p_init = p_almost; + reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + //pb.closePath(); + pb.flush(); + Geom::PathVector pv_np = pb.peek(); + //hack + for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) + { + path_out.push_back( pv_np[abcd] ); + } + } + else + { + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + p.Outline(&outlinepath, line_width / 2, join, butt, miter_lim); + std::vector *pv_p = outlinepath.MakePathVector(); + //hack + path_out.push_back( (*pv_p)[0].reverse() ); + delete pv_p; + } + } + return path_out; + } + static Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim) + { + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + Geom::PathVector path_out; + for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) + { + if (path_in[lmnop].size() > 1) + { + Geom::Path p_init; + Geom::Path p_rev; + Geom::PathBuilder pb = Geom::PathBuilder(); + + if ( !path_in[lmnop].closed() ) + { + p_init = Outline::half_outline_extrp( path_in[lmnop], -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline_extrp( path_in[lmnop].reverse(), -line_width, butt, + miter_lim ); + + pb.moveTo(p_init.initialPoint() ); + pb.append(p_init); + + //cap + if (butt == butt_straight) { + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } + + pb.append(p_rev); + + if (butt == butt_straight) { + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); + //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); + + pb.lineTo(p_init.initialPoint() ); + } + } + else + { + //final join + //refer to half_outline for documentation + Geom::Path p_almost = path_in[lmnop]; + p_almost.appendNew ( path_in[lmnop].initialPoint() ); + p_init = Outline::half_outline_extrp( p_almost, -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline_extrp( p_almost.reverse(), -line_width, butt, + miter_lim ); + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + + //this is a kludge, because I can't find how to make this work properly + bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), + path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == + (path_in[lmnop] [path_in[lmnop].size()].length())); + + p_almost = p_init; + if (lastIsLinear) + { + p_almost.erase_last(); p_almost.erase_last(); + } + + //outside test + Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); + Geom::Curve* cbc2 = p_almost[0].duplicate(); + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //this is the outside path + + //reuse the old one + p_init = p_almost; + Outline::extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside, carry on :-) + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + + p_almost = p_rev; + if (lastIsLinear) + { + p_almost.erase(p_almost.begin() ); + p_almost.erase(p_almost.begin() ); + } + + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + + cbc1 = p_almost[p_almost.size() - 1].duplicate(); + cbc2 = p_almost[0].duplicate(); + + cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //outside path + + p_init = p_almost; + extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + //pb.closePath(); + pb.flush(); + Geom::PathVector pv_np = pb.peek(); + //hack + for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) + { + path_out.push_back( pv_np[abcd] ); + } + } + else + { + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + p.Outline(&outlinepath, line_width / 2, join_pointy, butt, miter_lim); + std::vector *pv_p = outlinepath.MakePathVector(); + //hack + path_out.push_back( (*pv_p)[0].reverse() ); + delete pv_p; + } + } + return path_out; + } + + +} // namespace Outline + +/* + 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:encoding=utf-8:textwidth=99 : -- cgit v1.2.3 From c3edf2beebfdf0cbb505d2accbddc4fec17dff7d Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 6 Mar 2014 21:05:19 -0500 Subject: Start cleanup for merge into trunk (bzr r13090.1.20) --- src/live_effects/effect.cpp | 8 ++++---- src/live_effects/lpe-fill-between-many.cpp | 3 ++- src/live_effects/lpe-jointype.cpp | 5 +++-- src/live_effects/parameter/originalpatharray.cpp | 12 +++++++++++- src/live_effects/parameter/powerstrokepointarray.cpp | 6 +++--- src/live_effects/parameter/transformedpoint.cpp | 4 ++-- 6 files changed, 25 insertions(+), 13 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 17b229352..2ffff153c 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -47,7 +47,7 @@ #include "live_effects/lpe-extrude.h" #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-clone-original.h" -#include "live_effects/lpe-attach-path.h" +//#include "live_effects/lpe-attach-path.h" #include "live_effects/lpe-fill-between-strokes.h" #include "live_effects/lpe-fill-between-many.h" #include "live_effects/lpe-ellipse_5pts.h" @@ -130,7 +130,7 @@ const Util::EnumData LPETypeData[] = { {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, /* Ponyscape */ - {ATTACH_PATH, N_("Attach path"), "attach_path"}, +// {ATTACH_PATH, N_("Attach path"), "attach_path"}, {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, @@ -258,9 +258,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case CLONE_ORIGINAL: neweffect = static_cast ( new LPECloneOriginal(lpeobj) ); break; - case ATTACH_PATH: + /*case ATTACH_PATH: neweffect = static_cast ( new LPEAttachPath(lpeobj) ); - break; + break;*/ case FILL_BETWEEN_STROKES: neweffect = static_cast ( new LPEFillBetweenStrokes(lpeobj) ); break; diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp index 00cc1fed5..7cf354044 100644 --- a/src/live_effects/lpe-fill-between-many.cpp +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -4,7 +4,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include #include #include "live_effects/lpe-fill-between-many.h" @@ -16,6 +15,8 @@ #include "sp-text.h" #include "2geom/bezier-curve.h" +#include + namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 97c0a1b8a..93e645783 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -12,6 +12,9 @@ #include +#include "live_effects/parameter/enum.h" +#include "live_effects/pathoutlineprovider.h" + #include "sp-shape.h" #include "style.h" #include "xml/repr.h" @@ -20,11 +23,9 @@ #include "desktop-style.h" #include "svg/css-ostringstream.h" #include "display/curve.h" -#include "live_effects/parameter/enum.h" #include <2geom/path.h> #include <2geom/svg-elliptical-arc.h> -#include "live_effects/pathoutlineprovider.h" #include "lpe-jointype.h" diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 29e4c409c..ed47db28d 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -4,6 +4,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #include "live_effects/parameter/originalpatharray.h" #include @@ -89,9 +97,11 @@ OriginalPathArrayParam::OriginalPathArrayParam( const Glib::ustring& label, _toggle_renderer->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled)); col->add_attribute(_toggle_renderer->property_active(), _model->_colReverse); + //quick little hack -- new versions of gtk did not give the item enough space + _scroller.property_height_request() = 120; _scroller.add(_tree); _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); - _scroller.set_shadow_type(Gtk::SHADOW_IN); + //_scroller.set_shadow_type(Gtk::SHADOW_IN); oncanvas_editable = true; diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index ac0000b1a..7fa837689 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -4,8 +4,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include - #include "ui/dialog/lpe-powerstroke-properties.h" #include "live_effects/parameter/powerstrokepointarray.h" @@ -22,6 +20,8 @@ #include "desktop.h" #include "live_effects/lpeobject.h" +#include + namespace Inkscape { namespace LivePathEffect { @@ -145,7 +145,7 @@ public: virtual Geom::Point knot_get() const; virtual void knot_click(guint state); - /** Checks whether the index falls within the size of the parameter's vector / + // Checks whether the index falls within the size of the parameter's vector bool valid_index(unsigned int index) const { return (_pparam->_vector.size() > index); }; diff --git a/src/live_effects/parameter/transformedpoint.cpp b/src/live_effects/parameter/transformedpoint.cpp index f5b01e267..0d03432c3 100644 --- a/src/live_effects/parameter/transformedpoint.cpp +++ b/src/live_effects/parameter/transformedpoint.cpp @@ -4,8 +4,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include - #include "ui/widget/registered-widget.h" #include "live_effects/parameter/transformedpoint.h" #include "sp-lpe-item.h" @@ -17,6 +15,8 @@ #include "desktop.h" #include "verbs.h" +#include + namespace Inkscape { namespace LivePathEffect { -- cgit v1.2.3 From fd36e8d406b5ca3bfdc575a949351c6ae4a45c57 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 8 Mar 2014 20:52:27 -0500 Subject: Remove all trace of the Tags dialog Fixed Attach Path and Fill Between Many LPEs Enabled Gradient Meshes (bzr r13090.1.21) --- src/live_effects/effect.cpp | 8 ++++---- src/live_effects/lpe-attach-path.cpp | 4 ++-- src/live_effects/lpe-attach-path.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 2ffff153c..17b229352 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -47,7 +47,7 @@ #include "live_effects/lpe-extrude.h" #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-clone-original.h" -//#include "live_effects/lpe-attach-path.h" +#include "live_effects/lpe-attach-path.h" #include "live_effects/lpe-fill-between-strokes.h" #include "live_effects/lpe-fill-between-many.h" #include "live_effects/lpe-ellipse_5pts.h" @@ -130,7 +130,7 @@ const Util::EnumData LPETypeData[] = { {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, /* Ponyscape */ -// {ATTACH_PATH, N_("Attach path"), "attach_path"}, + {ATTACH_PATH, N_("Attach path"), "attach_path"}, {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, @@ -258,9 +258,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case CLONE_ORIGINAL: neweffect = static_cast ( new LPECloneOriginal(lpeobj) ); break; - /*case ATTACH_PATH: + case ATTACH_PATH: neweffect = static_cast ( new LPEAttachPath(lpeobj) ); - break;*/ + break; case FILL_BETWEEN_STROKES: neweffect = static_cast ( new LPEFillBetweenStrokes(lpeobj) ); break; diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index b3d5ed9b7..0cceb1cb7 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -62,9 +62,9 @@ void LPEAttachPath::resetDefaults(SPItem const * item) curve_end_previous_origin = end_path_curve_end.getOrigin(); } -void LPEAttachPath::doBeforeEffect(const SPLPEItem *lpeitem) +void LPEAttachPath::doBeforeEffect(SPLPEItem const *lpeitem) { - lpe_effect = lpeitem; + lpe_effect = const_cast (lpeitem); } void LPEAttachPath::doEffect (SPCurve * curve) diff --git a/src/live_effects/lpe-attach-path.h b/src/live_effects/lpe-attach-path.h index 3dda189d6..390282f90 100644 --- a/src/live_effects/lpe-attach-path.h +++ b/src/live_effects/lpe-attach-path.h @@ -45,7 +45,7 @@ private: ScalarParam end_path_position; TransformedPointParam end_path_curve_start; VectorParam end_path_curve_end; - const SPLPEItem * lpe_effect; + SPLPEItem * lpe_effect; }; }; //namespace LivePathEffect -- cgit v1.2.3 From 13c192e2fa564c0a743e13e30b1cf6de9b1a39a6 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 12 Mar 2014 08:56:04 -0400 Subject: Reverted swatches Removed a toy effect (not ready yet) Fixed a bug with Livarot General cleanup (bzr r13090.1.23) --- src/live_effects/Makefile_insert | 4 +- src/live_effects/effect-enum.h | 2 +- src/live_effects/effect.cpp | 10 +- src/live_effects/lpe-jointype.h | 43 -- src/live_effects/parameter/originalpatharray.cpp | 7 +- src/live_effects/pathoutlineprovider.h | 766 ----------------------- 6 files changed, 11 insertions(+), 821 deletions(-) delete mode 100755 src/live_effects/lpe-jointype.h delete mode 100755 src/live_effects/pathoutlineprovider.h (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 76d7b418f..35a85b4aa 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -92,6 +92,4 @@ ink_common_sources += \ live_effects/lpe-fill-between-many.cpp \ live_effects/lpe-fill-between-many.h \ live_effects/lpe-ellipse_5pts.cpp \ - live_effects/lpe-ellipse_5pts.h \ - live_effects/lpe-jointype.cpp \ - live_effects/lpe-jointype.h + live_effects/lpe-ellipse_5pts.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 46bc56a81..9c76875e9 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -55,7 +55,7 @@ enum EffectType { FILL_BETWEEN_MANY, ELLIPSE_5PTS, BOUNDING_BOX, - JOIN_TYPE, +// JOIN_TYPE, 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 17b229352..eac0f79f4 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,7 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define LPE_ENABLE_TEST_EFFECTS +//#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects #ifdef HAVE_CONFIG_H # include "config.h" @@ -52,7 +52,7 @@ #include "live_effects/lpe-fill-between-many.h" #include "live_effects/lpe-ellipse_5pts.h" #include "live_effects/lpe-bounding-box.h" -#include "live_effects/lpe-jointype.h" +//#include "live_effects/lpe-jointype.h" #include "xml/node-event-vector.h" #include "sp-object.h" @@ -109,7 +109,7 @@ const Util::EnumData LPETypeData[] = { {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, - {JOIN_TYPE, N_("Join type"), "join_type"}, +// {JOIN_TYPE, N_("Join type"), "join_type"}, #endif /* 0.46 */ {BEND_PATH, N_("Bend"), "bend_path"}, @@ -273,9 +273,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case BOUNDING_BOX: neweffect = static_cast ( new LPEBoundingBox(lpeobj) ); break; - case JOIN_TYPE: + /*case JOIN_TYPE: neweffect = static_cast ( new LPEJoinType(lpeobj) ); - break; + break;*/ default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h deleted file mode 100755 index db113c66a..000000000 --- a/src/live_effects/lpe-jointype.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Authors: - * Liam P White - * - * Copyright (C) 2014 Authors - * - * Released under GNU GPL v2, read the file COPYING for more information - */ -#ifndef INKSCAPE_LPE_JOINTYPE_H -#define INKSCAPE_LPE_JOINTYPE_H - -#include "live_effects/effect.h" -#include "live_effects/parameter/parameter.h" -#include "live_effects/parameter/point.h" -#include "live_effects/parameter/enum.h" - -namespace Inkscape { -namespace LivePathEffect { - -class LPEJoinType : public Effect { -public: - LPEJoinType(LivePathEffectObject *lpeobject); - virtual ~LPEJoinType(); - - virtual void doOnApply(SPLPEItem const* lpeitem); - virtual void doOnRemove(SPLPEItem const* lpeitem); - virtual std::vector doEffect_path (std::vector const & path_in); - -private: - LPEJoinType(const LPEJoinType&); - LPEJoinType& operator=(const LPEJoinType&); - - ScalarParam line_width; - EnumParam linecap_type; - EnumParam linejoin_type; - ScalarParam miter_limit; - BoolParam attempt_force_join; - bool was_initialized; -}; - -} //namespace LivePathEffect -} //namespace Inkscape - -#endif diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index ed47db28d..514c9e23e 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -31,7 +32,6 @@ #include "uri.h" #include "display/curve.h" -#include #include <2geom/coord.h> #include <2geom/point.h> #include "sp-shape.h" @@ -97,8 +97,9 @@ OriginalPathArrayParam::OriginalPathArrayParam( const Glib::ustring& label, _toggle_renderer->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled)); col->add_attribute(_toggle_renderer->property_active(), _model->_colReverse); - //quick little hack -- new versions of gtk did not give the item enough space - _scroller.property_height_request() = 120; + //quick little hack -- newer versions of gtk gave the item zero space allotment + _scroller.set_size_request(-1, 120); + _scroller.add(_tree); _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); //_scroller.set_shadow_type(Gtk::SHADOW_IN); diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h deleted file mode 100755 index 8aa2e38ad..000000000 --- a/src/live_effects/pathoutlineprovider.h +++ /dev/null @@ -1,766 +0,0 @@ -#pragma once - -#include <2geom/path.h> -#include <2geom/circle.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/shape.h> -#include <2geom/transforms.h> -#include <2geom/path-sink.h> - -#include -#include - -enum LineJoinType { - LINEJOIN_STRAIGHT, - LINEJOIN_ROUND, - LINEJOIN_POINTY, - LINEJOIN_REFLECTED, - LINEJOIN_EXTRAPOLATED -}; - -namespace Geom -{ - /** - * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/Circle-CircleIntersection.html - * - * @return 0 if no intersection - * @return 1 if one circle is contained in the other - * @return 2 if intersections are found (they are written to p0 and p1) - */ - static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, - Point & p0, Point & p1) - { - Point X0 = circle0.center(); - double r0 = circle0.ray(); - Point X1 = circle1.center(); - double r1 = circle1.ray(); - - /* dx and dy are the vertical and horizontal distances between - * the circle centers. - */ - Point D = X1 - X0; - - /* Determine the straight-line distance between the centers. */ - double d = L2(D); - - /* Check for solvability. */ - if (d > (r0 + r1)) - { - /* no solution. circles do not intersect. */ - return 0; - } - if (d <= fabs(r0 - r1)) - { - /* no solution. one circle is contained in the other */ - return 1; - } - - /* 'point 2' is the point where the line through the circle - * intersection points crosses the line between the circle - * centers. - */ - - /* Determine the distance from point 0 to point 2. */ - double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; - - /* Determine the coordinates of point 2. */ - Point p2 = X0 + D * (a/d); - - /* Determine the distance from point 2 to either of the - * intersection points. - */ - double h = std::sqrt((r0*r0) - (a*a)); - - /* Now determine the offsets of the intersection points from - * point 2. - */ - Point r = (h/d)*rot90(D); - - /* Determine the absolute intersection points. */ - p0 = p2 + r; - p1 = p2 - r; - - return 2; - } - /** - * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. - * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). - */ - static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) - { - D2 dM=derivative(curve); - if ( are_near(L2sq(dM(t)),0.) ) { - dM=derivative(dM); - } - if ( are_near(L2sq(dM(t)),0.) ) { // try second time - dM=derivative(dM); - } - Piecewise > unitv = unitVector(dM,tol); - Piecewise dMlength = dot(Piecewise >(dM),unitv); - Piecewise k = cross(derivative(unitv),unitv); - k = divide(k,dMlength,tol,3); - double curv = k(t); // note that this value is signed - - Geom::Point normal = unitTangentAt(curve, t).cw(); - double radius = 1/curv; - Geom::Point center = curve(t) + radius*normal; - return Geom::Circle(center, fabs(radius)); - } - - static std::vector split_at_cusps(const Geom::Path& in) - { - Geom::PathVector out = Geom::PathVector(); - Geom::Path temp = Geom::Path(); - - for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) - { - temp = Geom::Path(); - temp.append(in[path_descr]); - out.push_back(temp); - } - - return out; - } - - static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) - { - std::vector temp; - sbasis_to_bezier(temp, sbasis_in, 4); - return Geom::CubicBezier( temp ); - } - - static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, - Geom::Point const & origin_b, Geom::Point const & vector_b) - { - Geom::Coord denom = cross(vector_b, vector_a); - if (!Geom::are_near(denom,0.)){ - Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; - return origin_a + t * vector_a; - } - return boost::none; - } -} - -namespace Outline -{ - - typedef Geom::D2 D2SB; - typedef Geom::Piecewise PWD2; - - static void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve*cbc2, Geom::Point endPt, double miter_limit) -{ - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - if (cross.empty()) - { - Geom::Path pth; - pth.append(*cbc1); - - Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); - - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - - Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(cbc1->toSBasis()), 0.); - Geom::Circle circle2 = Geom::touching_circle(cbc2->toSBasis(), 0); - - Geom::Point points[2]; - int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); - if (solutions == 2) - { - Geom::Point sol(0,0); - if ( dot(tang2,points[0]-endPt) > 0 ) - { - // points[0] is bad, choose points[1] - sol = points[1]; - } - else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] - // points[1] is bad, choose points[0] - sol = points[0]; - } - else - { - // both points are good, choose nearest - sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? - points[0] : points[1]; - } - Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); - Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); - - if (arc0) - { - path_builder.append (arc0->toSBasis()); - delete arc0; - arc0 = NULL; - } - - if (arc1) - { - path_builder.append (arc1->toSBasis()); - delete arc1; - arc1 = NULL; - } - } - else - { - path_builder.appendNew (endPt); - } - } - else - { - path_builder.appendNew (endPt); - } -} - static Geom::Path half_outline_extrp(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) - { - Geom::PathVector pv = split_at_cusps(path_in); - unsigned m; - Path path_outline = Path(); - Path path_tangent = Path(); - - Geom::Point initialPoint; - Geom::Point endPoint; - - Geom::Path path_builder = Geom::Path(); - Geom::PathVector * pathvec; - - //load the first portion in before the loop starts - { - path_outline = Path(); - path_outline.LoadPath(pv[0], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - //now half of first cusp has been loaded - - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - //instead of array accessing twice, dereferencing used for clarity - initialPoint = (*pathvec)[0].initialPoint(); - - path_builder.start(initialPoint); - path_builder.append( (*pathvec)[0] ); - - path_outline = Path(); - path_outline.LoadPath(pv[1], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - - path_builder.append( (*pathvec)[0] ); - - //always set pointers null after deleting - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - for (m = 2; m < pv.size(); m++) - { - path_outline = Path(); - path_outline.LoadPath(pv[m], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - path_builder.append( (*pathvec)[0] ); - - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - return path_builder; - } - - //Create a reflected outline join. - //Note: it is generally recommended to let half_outline do this for you! - //path_builder: the path to append the curves to - //cbc1: the curve before the join - //cbc2: the curve after the join - //endPt: the point to end at - //miter_limit: the miter parameter - static void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit) - { - //the most important work for the reflected join is done here - - //determine where we are in the path. If we're on the inside, ignore - //and just lineTo. On the outside, we'll do a little reflection magic :) - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - if (cross.empty()) - { - //probably on the outside of the corner - Geom::Path pth; - pth.append(*cbc1); - - Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); - - //reflect curves along the bevel - D2SB newcurve1 = pth.toPwSb()[0] * - Geom::reflection ( -Geom::rot90(tang1) , - cbc1->finalPoint() ); - - Geom::CubicBezier bzr1 = sbasis_to_cubicbezier(Geom::reverse(newcurve1)); - - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - D2SB newcurve2 = pth.toPwSb()[0] * - Geom::reflection ( -Geom::rot90(tang2) , - cbc2->initialPoint() ); - Geom::CubicBezier bzr2 = sbasis_to_cubicbezier(Geom::reverse(newcurve2)); - - cross = Geom::crossings(bzr1, bzr2); - if ( cross.empty() ) - { - //std::cout << "Oops, no crossings!" << std::endl; - //curves didn't cross; default to miter - /*boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { - path_builder.appendNew (*p); - }*/ - //bevel - path_builder.appendNew( endPt ); - } - else - { - //join - std::pair sub1 = bzr1.subdivide(cross[0].ta); - std::pair sub2 = bzr2.subdivide(cross[0].tb); - - //@TODO joins have a strange tendency to cross themselves twice. Check this. - - //sections commented out are for general stability - path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); - path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); - } - } - else // cross.empty() - { - //probably on the inside of the corner - path_builder.appendNew ( endPt ); - } - } - - /** @brief Converts a path to one half of an outline. - * path_in: The input path to use. (To create the other side use path_in.reverse() ) - * line_width: the line width to use (usually you want to divide this by 2) - * linecap_type: (not used here) the cap to apply. Passed to libvarot. - * miter_limit: the miter parameter - */ - static Geom::Path half_outline(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) - { - Geom::PathVector pv = split_at_cusps(path_in); - unsigned m; - Path path_outline = Path(); - Path path_tangent = Path(); - //needed for closing the path - Geom::Point initialPoint; - Geom::Point endPoint; - - //some issues prevented me from using a PathBuilder here - //it seems like PathBuilder::peek() gave me a null reference exception - //and I was unable to get a stack trace on Windows, so had to switch to Linux - //to see what the hell was wrong. :( - //I wasted five hours opening it in IDAPro, VS2012, and GDB Windows - - /*Program received signal SIGSEGV, Segmentation fault. - 0x00000000006539ac in get_curves (this=0x0) - at /usr/include/c++/4.6/bits/locale_facets.h:1077 - 1077 { return __c; } - */ - - Geom::Path path_builder = Geom::Path(); - Geom::PathVector * pathvec; - - //load the first portion in before the loop starts - { - path_outline = Path(); - path_outline.LoadPath(pv[0], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - //now half of first cusp has been loaded - - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - //instead of array accessing twice, dereferencing used for clarity - initialPoint = (*pathvec)[0].initialPoint(); - - path_builder.start(initialPoint); - path_builder.append( (*pathvec)[0] ); - - path_outline = Path(); - path_outline.LoadPath(pv[1], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - - path_builder.append( (*pathvec)[0] ); - - //always set pointers null after deleting - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - for (m = 2; m < pv.size(); m++) - { - path_outline = Path(); - path_outline.LoadPath(pv[m], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - path_builder.append( (*pathvec)[0] ); - - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - return path_builder; - } - - static Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim) - { - Path p = Path(); - Path outlinepath = Path(); - for (unsigned i = 0; i < path_in.size(); i++) - { - p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); - } - - Geom::PathVector path_out; - for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) - { - if (path_in[lmnop].size() > 1) - { - Geom::Path p_init; - Geom::Path p_rev; - Geom::PathBuilder pb = Geom::PathBuilder(); - - if ( !path_in[lmnop].closed() ) - { - p_init = Outline::half_outline( path_in[lmnop], -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline( path_in[lmnop].reverse(), -line_width, butt, - miter_lim ); - - pb.moveTo(p_init.initialPoint() ); - pb.append(p_init); - - //cap - if (butt == butt_straight) { - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } - - pb.append(p_rev); - - if (butt == butt_straight) { - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); - //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); - - pb.lineTo(p_init.initialPoint() ); - } - } - else - { - //final join - //refer to half_outline for documentation - Geom::Path p_almost = path_in[lmnop]; - p_almost.appendNew ( path_in[lmnop].initialPoint() ); - p_init = Outline::half_outline( p_almost, -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline( p_almost.reverse(), -line_width, butt, - miter_lim ); - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - - //this is a kludge, because I can't find how to make this work properly - bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), - path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == - (path_in[lmnop] [path_in[lmnop].size()].length())); - - p_almost = p_init; - if (lastIsLinear) - { - p_almost.erase_last(); p_almost.erase_last(); - } - - //outside test - Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); - Geom::Curve* cbc2 = p_almost[0].duplicate(); - - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //this is the outside path - - //reuse the old one - p_init = p_almost; - Outline::reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside, carry on :-) - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - - p_almost = p_rev; - if (lastIsLinear) - { - p_almost.erase(p_almost.begin() ); - p_almost.erase(p_almost.begin() ); - } - - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - - cbc1 = p_almost[p_almost.size() - 1].duplicate(); - cbc2 = p_almost[0].duplicate(); - - cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //outside path - - p_init = p_almost; - reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - //pb.closePath(); - pb.flush(); - Geom::PathVector pv_np = pb.peek(); - //hack - for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) - { - path_out.push_back( pv_np[abcd] ); - } - } - else - { - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - p.Outline(&outlinepath, line_width / 2, join, butt, miter_lim); - std::vector *pv_p = outlinepath.MakePathVector(); - //hack - path_out.push_back( (*pv_p)[0].reverse() ); - delete pv_p; - } - } - return path_out; - } - static Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim) - { - Path p = Path(); - Path outlinepath = Path(); - for (unsigned i = 0; i < path_in.size(); i++) - { - p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); - } - - Geom::PathVector path_out; - for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) - { - if (path_in[lmnop].size() > 1) - { - Geom::Path p_init; - Geom::Path p_rev; - Geom::PathBuilder pb = Geom::PathBuilder(); - - if ( !path_in[lmnop].closed() ) - { - p_init = Outline::half_outline_extrp( path_in[lmnop], -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline_extrp( path_in[lmnop].reverse(), -line_width, butt, - miter_lim ); - - pb.moveTo(p_init.initialPoint() ); - pb.append(p_init); - - //cap - if (butt == butt_straight) { - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } - - pb.append(p_rev); - - if (butt == butt_straight) { - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); - //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); - - pb.lineTo(p_init.initialPoint() ); - } - } - else - { - //final join - //refer to half_outline for documentation - Geom::Path p_almost = path_in[lmnop]; - p_almost.appendNew ( path_in[lmnop].initialPoint() ); - p_init = Outline::half_outline_extrp( p_almost, -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline_extrp( p_almost.reverse(), -line_width, butt, - miter_lim ); - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - - //this is a kludge, because I can't find how to make this work properly - bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), - path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == - (path_in[lmnop] [path_in[lmnop].size()].length())); - - p_almost = p_init; - if (lastIsLinear) - { - p_almost.erase_last(); p_almost.erase_last(); - } - - //outside test - Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); - Geom::Curve* cbc2 = p_almost[0].duplicate(); - - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //this is the outside path - - //reuse the old one - p_init = p_almost; - Outline::extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside, carry on :-) - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - - p_almost = p_rev; - if (lastIsLinear) - { - p_almost.erase(p_almost.begin() ); - p_almost.erase(p_almost.begin() ); - } - - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - - cbc1 = p_almost[p_almost.size() - 1].duplicate(); - cbc2 = p_almost[0].duplicate(); - - cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //outside path - - p_init = p_almost; - extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - //pb.closePath(); - pb.flush(); - Geom::PathVector pv_np = pb.peek(); - //hack - for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) - { - path_out.push_back( pv_np[abcd] ); - } - } - else - { - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - p.Outline(&outlinepath, line_width / 2, join_pointy, butt, miter_lim); - std::vector *pv_p = outlinepath.MakePathVector(); - //hack - path_out.push_back( (*pv_p)[0].reverse() ); - delete pv_p; - } - } - return path_out; - } - - -} // namespace Outline - -/* - 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:encoding=utf-8:textwidth=99 : -- cgit v1.2.3 From 95b10e0707ee0e16055d5e514e1d05c929d49b5a Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 18 Mar 2014 17:34:31 -0600 Subject: Added in new toy effect "Taper Strokes," readded a missing header file, bugfixes (bzr r13090.1.25) --- src/live_effects/Makefile_insert | 6 +- src/live_effects/effect-enum.h | 3 +- src/live_effects/effect.cpp | 13 +- src/live_effects/lpe-jointype.h | 43 ++ src/live_effects/lpe-taperstroke.cpp | 536 +++++++++++++++++++++++ src/live_effects/lpe-taperstroke.h | 73 ++++ src/live_effects/pathoutlineprovider.h | 766 +++++++++++++++++++++++++++++++++ 7 files changed, 1434 insertions(+), 6 deletions(-) create mode 100755 src/live_effects/lpe-jointype.h create mode 100644 src/live_effects/lpe-taperstroke.cpp create mode 100644 src/live_effects/lpe-taperstroke.h create mode 100755 src/live_effects/pathoutlineprovider.h (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 35a85b4aa..b19f417ae 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -92,4 +92,8 @@ ink_common_sources += \ live_effects/lpe-fill-between-many.cpp \ live_effects/lpe-fill-between-many.h \ live_effects/lpe-ellipse_5pts.cpp \ - live_effects/lpe-ellipse_5pts.h + live_effects/lpe-ellipse_5pts.h \ + live_effects/lpe-jointype.cpp \ + live_effects/lpe-jointype.h \ + live_effects/lpe-taperstroke.cpp \ + live_effects/lpe-taperstroke.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 9c76875e9..c53d64699 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -55,7 +55,8 @@ enum EffectType { FILL_BETWEEN_MANY, ELLIPSE_5PTS, BOUNDING_BOX, -// JOIN_TYPE, + JOIN_TYPE, + TAPER_STROKE, 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 eac0f79f4..d6840e5b8 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -52,7 +52,8 @@ #include "live_effects/lpe-fill-between-many.h" #include "live_effects/lpe-ellipse_5pts.h" #include "live_effects/lpe-bounding-box.h" -//#include "live_effects/lpe-jointype.h" +#include "live_effects/lpe-jointype.h" +#include "live_effects/lpe-taperstroke.h" #include "xml/node-event-vector.h" #include "sp-object.h" @@ -109,7 +110,8 @@ const Util::EnumData LPETypeData[] = { {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, -// {JOIN_TYPE, N_("Join type"), "join_type"}, + {JOIN_TYPE, N_("Join type"), "join_type"}, + {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, #endif /* 0.46 */ {BEND_PATH, N_("Bend"), "bend_path"}, @@ -273,9 +275,12 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case BOUNDING_BOX: neweffect = static_cast ( new LPEBoundingBox(lpeobj) ); break; - /*case JOIN_TYPE: + case JOIN_TYPE: neweffect = static_cast ( new LPEJoinType(lpeobj) ); - break;*/ + break; + case TAPER_STROKE: + neweffect = static_cast ( new LPETaperStroke(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h new file mode 100755 index 000000000..db113c66a --- /dev/null +++ b/src/live_effects/lpe-jointype.h @@ -0,0 +1,43 @@ +/* Authors: + * Liam P White + * + * Copyright (C) 2014 Authors + * + * Released under GNU GPL v2, read the file COPYING for more information + */ +#ifndef INKSCAPE_LPE_JOINTYPE_H +#define INKSCAPE_LPE_JOINTYPE_H + +#include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/point.h" +#include "live_effects/parameter/enum.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEJoinType : public Effect { +public: + LPEJoinType(LivePathEffectObject *lpeobject); + virtual ~LPEJoinType(); + + virtual void doOnApply(SPLPEItem const* lpeitem); + virtual void doOnRemove(SPLPEItem const* lpeitem); + virtual std::vector doEffect_path (std::vector const & path_in); + +private: + LPEJoinType(const LPEJoinType&); + LPEJoinType& operator=(const LPEJoinType&); + + ScalarParam line_width; + EnumParam linecap_type; + EnumParam linejoin_type; + ScalarParam miter_limit; + BoolParam attempt_force_join; + bool was_initialized; +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp new file mode 100644 index 000000000..e6eed3abe --- /dev/null +++ b/src/live_effects/lpe-taperstroke.cpp @@ -0,0 +1,536 @@ +/** + * @file + * Taper Stroke path effect, provided as an alternative to Power Strokes + * for otherwise constant-width paths. + * + * Authors: + * Liam P White + * + * Copyright (C) 2014 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-taperstroke.h" + +// You might need to include other 2geom files. You can add them here: +#include <2geom/path.h> +#include <2geom/shape.h> +#include "pathoutlineprovider.h" +#include "display/curve.h" +#include "svg/svg.h" + +//#include + +#include "knot-holder-entity.h" +#include "knotholder.h" + +namespace Inkscape { +namespace LivePathEffect { + +namespace TpS { + class KnotHolderEntityAttachBegin : public LPEKnotHolderEntity { + public: + KnotHolderEntityAttachBegin(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + }; + class KnotHolderEntityAttachEnd : public LPEKnotHolderEntity { + public: + KnotHolderEntityAttachEnd(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + }; +} // TpS + +static const Util::EnumData JoinType[] = { + {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, + {LINEJOIN_ROUND, N_("Rounded"), "round"}, + {LINEJOIN_REFLECTED, N_("Reflected"), "reflected"}, + {LINEJOIN_POINTY, N_("Miter"), "miter"}, + {LINEJOIN_EXTRAPOLATED, N_("Extrapolated"), "extrapolated"} +}; + +static const Util::EnumDataConverter JoinTypeConverter(JoinType, sizeof (JoinType)/sizeof(*JoinType)); + +LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), + attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), + smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.2), + join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), + miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 30.) +{ + /* uncomment the following line to have the original path displayed while the item is selected */ + show_orig_path = true; + _provides_knotholder_entities = true; + + attach_start.param_set_digits(3); + attach_end.param_set_digits(3); + + registerParameter( dynamic_cast(&attach_start) ); + registerParameter( dynamic_cast(&attach_end) ); + registerParameter( dynamic_cast(&smoothing) ); + registerParameter( dynamic_cast(&join_type) ); + registerParameter( dynamic_cast(&miter_limit) ); +} + +LPETaperStroke::~LPETaperStroke() +{ + +} + +unsigned curveOrder (const Geom::Curve* curve_in) +{ + using namespace Geom; + //cast it + const CubicBezier *cbc = dynamic_cast(curve_in); + if (cbc) return 3; + const QuadraticBezier * qbc = dynamic_cast(curve_in); + if (qbc) return 2; + const BezierCurveN<1U> * lbc = dynamic_cast *>(curve_in); + if (lbc) return 1; + //BezierCurveN<0> * dbc = dynamic_cast *> (curve_in); + return 0; +} + +Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_tolerance = 0.01) +{ + Geom::Path path_out = Geom::Path(); + + for (unsigned i = 0; i < path_in.size(); i++) + { + path_out.append(path_in[i]); + if (path_in.size() == 1) + break; + + //determine order of curve + int order = curveOrder(&path_in[i]); + + Geom::Point start_point; + Geom::Point cross_point = path_in[i].finalPoint(); + Geom::Point end_point; + + g_assert(path_in[i].finalPoint() == path_in[i+1].initialPoint()); + + //can you tell that the following expressions have been shaped by + //repeated compiler errors? ;) + switch (order) + { + case 3: + start_point = (dynamic_cast(&path_in[i]))->operator[] (2); + break; + case 2: + start_point = (dynamic_cast(&path_in[i]))->operator[] (1); + break; + case 1: + default: + start_point = path_in[i].initialPoint(); + } + + order = curveOrder(&path_in[i+1]); + + switch (order) + { + case 3: + end_point = (dynamic_cast(&path_in[i+1]))->operator[] (1); + break; + case 2: + end_point = (dynamic_cast(&path_in[i+1]))->operator[] (1); + break; + case 1: + default: + end_point = path_in[i+1].finalPoint(); + } + if (!are_collinear(start_point, cross_point, end_point, smooth_tolerance)) + break; + } + return path_out; +} + +Geom::Curve * subdivide_at(const Geom::Curve* curve_in, Geom::Coord time, bool first) +{ + //the only reason for this function is the lack of a subdivide function in the Curve class. + //you have to cast to Beziers to be able to use subdivide(t) + unsigned order = curveOrder(curve_in); + Geom::Curve* curve_out = curve_in->duplicate(); + switch (order) + { + //these need to be scoped because of the variable 'c' + case 3: + { + Geom::CubicBezier c = first ? (dynamic_cast (curve_out))->subdivide(time).first : + (dynamic_cast (curve_out))->subdivide(time).second; + if (curve_out) delete curve_out; + curve_out = c.duplicate(); + break; + } + case 2: + { + Geom::QuadraticBezier c = first ? (dynamic_cast(curve_out))->subdivide(time).first : + (dynamic_cast(curve_out))->subdivide(time).second; + if (curve_out) delete curve_out; + curve_out = c.duplicate(); + break; + } + case 1: + { + Geom::BezierCurveN<1> c = first ? (dynamic_cast* >(curve_out))->subdivide(time).first : + (dynamic_cast* >(curve_out))->subdivide(time).second; + if (curve_out) delete curve_out; + curve_out = c.duplicate(); + break; + } + } + return curve_out; +} + +Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double width); + +Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) +{ + //there is a pretty good chance that people will try to drag the knots + //on top of each other, so block it + + unsigned size = path_in[0].size(); + if (size == return_at_first_cusp(path_in[0]).size()) { + //check to see if the knots were dragged over each other + //if so, reset the end offset + if ( attach_start >= (size - attach_end) ) { + attach_end.param_set_value( size - attach_start ); + } + } + + //don't ever let it be zero + if (attach_start <= 0) { + attach_start.param_set_value( 0.0001 ); + } + if (attach_end <= 0) { + attach_end.param_set_value( 0.0001 ); + } + + /*if (size != return_at_first_cusp(path_in[0]).size()) { //will get to this in a bit + //check to see if either knot was dragged past their allowed amount + volatile unsigned size_p_start = (unsigned)attach_start; + volatile unsigned size_p_end = (unsigned)attach_end; + + //maximum allowed value in either direction is return_at_first_cusp(path_in[0]).size + volatile unsigned allowed_p_start = return_at_first_cusp(path_in[0]).size(); + volatile unsigned allowed_p_end = return_at_first_cusp(path_in[0].reverse()).size(); + + if (size_p_start > allowed_p_start) { + attach_start.param_set_value(allowed_p_start - 0.0001); + } else if (size_p_end > allowed_p_end) { + attach_end.param_set_value(allowed_p_end - 0.0001); + } + }*/ + + //Path::operator () means get point at time t + start_attach_point = return_at_first_cusp(path_in[0])(attach_start); + end_attach_point = return_at_first_cusp(path_in[0].reverse())(attach_end); + Geom::PathVector pathv_out; + + pathv_out = doEffect_simplePath(path_in); + + + //now for the fun stuff. Right? RIGHT? + + //decide on case + + //first case: taper on both sides + if (true/*pathv_out[0].length() != 0.001 && pathv_out[2].length() != 0.001*/) { + Geom::PathVector real_pathv; + + //Construct the pattern + + Geom::PathVector pat_vec = sp_svg_read_pathv("M 1,0 1,1 C 0.5,1 0,0.5 0,0.5 0,0.5 0.5,0 1,0 Z"); + + Geom::Piecewise > pwd2; + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], 40)); + + real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0]); + + Geom::PathVector sht_path; + sht_path.push_back(pathv_out[1]); + sht_path = Outline::outlinePath_extr(sht_path, 40, LINEJOIN_STRAIGHT, butt_straight, 30); + + real_pathv.push_back(sht_path[0]); + + pat_vec = sp_svg_read_pathv("M 0,0 0,1 C 0.5,1 1,0.5 1,0.5 1,0.5 0.5,0 0,0 Z"); + + pwd2 = Geom::Piecewise > (); + pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], 40)); + real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0].reverse()); + + //clever union + //Geom::Shape shape1 = Geom::sanitize(Geom::PathVector(1, real_pathv[0])); + //Geom::Shape shape2 = Geom::sanitize(Geom::PathVector(1, real_pathv[1])); + //Geom::Shape shape3 = Geom::boolop(shape1, shape2, Geom::BOOLOP_UNION); + + //shape2 = Geom::sanitize(Geom::PathVector(1, real_pathv[2])); + //shape1 = Geom::boolop(shape3, shape2, Geom::BOOLOP_UNION); + + //real_pathv = Geom::desanitize(shape1); + return real_pathv; + } + + return pathv_out; +} + +//in all cases, this should return a PathVector with three elements. +Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & path_in) +{ + unsigned size = path_in[0].size(); + + //do subdivision and get out + unsigned loc = (unsigned)attach_start; + Geom::Curve * curve_start = path_in[0] [loc].duplicate(); + + std::vector pathv_out; + Geom::Path path_out = Geom::Path(); + + Geom::Path trimmed_start = Geom::Path(); + Geom::Path trimmed_end = Geom::Path(); + + for (unsigned i = 0; i < loc; i++) { + trimmed_start.append(path_in[0] [i]); + } + + #define OVERLAP 0.001 + + trimmed_start.append(*subdivide_at(curve_start, (attach_start - loc) + OVERLAP, true)); + curve_start = subdivide_at(curve_start, attach_start - loc, false); + + //special case: path is one segment long + //special case: what if the two knots occupy the same segment? + if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) + { + Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); + //it is just a dumb segment + //we have to do some shifting here because the value changed when we reduced the length + //of the previous segment. + trimmed_end.append(*subdivide_at(curve_start, t - OVERLAP, false)); + for (unsigned j = (size - attach_end) + 1; j < size; j++) { + trimmed_end.append(path_in[0] [j]); + } + + curve_start = subdivide_at(curve_start, t, true); + path_out.append(*curve_start); + pathv_out.push_back(trimmed_start); + pathv_out.push_back(path_out); + pathv_out.push_back(trimmed_end); + return pathv_out; + } + + pathv_out.push_back(trimmed_start); + + //append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) + path_out.append(*curve_start); + + for (unsigned k = loc + 1; k < (size - unsigned(attach_end)) - 1; k++) { + path_out.append(path_in[0] [k]); + } + + //deal with the last segment in a very similar fashion to the first + loc = size - attach_end; + + Geom::Curve * curve_end = path_in[0] [loc].duplicate(); + + Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); + + trimmed_end.append(*subdivide_at(curve_end, t - OVERLAP, false)); + curve_end = subdivide_at(curve_end, t, true); + + for (unsigned j = (size - attach_end) + 1; j < size; j++) { + trimmed_end.append(path_in[0] [j]); + } + + path_out.append(*curve_end); + pathv_out.push_back(path_out); + + pathv_out.push_back(trimmed_end); + + if (curve_end) delete curve_end; + if (curve_start) delete curve_start; + return pathv_out; +} + + +//most of the below code is verbatim from Pattern Along Path. However, it needed a little +//tweaking to get it to work right in this case. +Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double prop_scale) +{ + using namespace Geom; + + // Don't allow empty path parameter: + if ( pattern.empty() ) { + return pwd2_in; + } + +/* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */ + Piecewise > output; + std::vector > > pre_output; + + D2 > patternd2 = make_cuts_independent(pattern.toPwSb()); + Piecewise x0 = Piecewise(patternd2[0]); + Piecewise y0 = Piecewise(patternd2[1]); + OptInterval pattBndsX = bounds_exact(x0); + OptInterval pattBndsY = bounds_exact(y0); + if (pattBndsX && pattBndsY) { + x0 -= pattBndsX->min(); + y0 -= pattBndsY->middle(); + + double xspace = 0; + double noffset = 0; + double toffset = 0; + /*if (prop_units.get_value() && pattBndsY){ + xspace *= pattBndsX->extent(); + noffset *= pattBndsY->extent(); + toffset *= pattBndsX->extent(); + }*/ + + //Prevent more than 90% overlap... + if (xspace < -pattBndsX->extent()*.9) { + xspace = -pattBndsX->extent()*.9; + } + + y0+=noffset; + + std::vector > > paths_in; + paths_in = split_at_discontinuities(pwd2_in); + + for (unsigned idx = 0; idx < paths_in.size(); idx++){ + Geom::Piecewise > path_i = paths_in[idx]; + Piecewise x = x0; + Piecewise y = y0; + Piecewise > uskeleton = arc_length_parametrization(path_i,2,.1); + uskeleton = remove_short_cuts(uskeleton,.01); + Piecewise > n = rot90(derivative(uskeleton)); + n = force_continuity(remove_short_cuts(n,.1)); + + int nbCopies = 0; + double scaling = 1; + nbCopies = 1; + scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); + + double pattWidth = pattBndsX->extent() * scaling; + + if (scaling != 1.0) { + x*=scaling; + } + if ( false ) { + y*=(scaling*prop_scale); + } else { + if (prop_scale != 1.0) y *= prop_scale; + } + x += toffset; + + double offs = 0; + for (int i=0; i > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs); + std::vector > > splited_output_piece = split_at_discontinuities(output_piece); + pre_output.insert(pre_output.end(), splited_output_piece.begin(), splited_output_piece.end() ); + }else{ + output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs)); + } + offs+=pattWidth; + } + } + /*if (false){ + pre_output = fuse_nearby_ends(pre_output, fuse_tolerance); + for (unsigned i=0; icreate( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); + knotholder->add(e); + } + { + KnotHolderEntity *e = new TpS::KnotHolderEntityAttachEnd(this); + e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); + knotholder->add(e); + } +} + +namespace TpS { + void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) + { + using namespace Geom; + + LPETaperStroke* lpe = dynamic_cast(_effect); + + Geom::Point const s = snap_knot_position(p, state); + + SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); + Geom::PathVector pathv = curve->get_pathvector(); + Piecewise > pwd2; + Geom::Path p_in = return_at_first_cusp(pathv[0]); + pwd2.concat(p_in.toPwSb()); + + double t0 = nearest_point(s, pwd2); + lpe->attach_start.param_set_value(t0); + + // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); + } + void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state) + { + using namespace Geom; + + LPETaperStroke* lpe = dynamic_cast(_effect); + + Geom::Point const s = snap_knot_position(p, state); + + SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); + Geom::PathVector pathv = curve->get_pathvector(); + Piecewise > pwd2; + Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); + pwd2.concat(p_in.toPwSb()); + + double t0 = nearest_point(s, pwd2); + lpe->attach_end.param_set_value(t0); + + // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); + } + Geom::Point KnotHolderEntityAttachBegin::knot_get() const + { + LPETaperStroke const * lpe = dynamic_cast (_effect); + return lpe->start_attach_point; + } + Geom::Point KnotHolderEntityAttachEnd::knot_get() const + { + LPETaperStroke const * lpe = dynamic_cast (_effect); + return lpe->end_attach_point; + } +} + + +/* ######################## */ + +} //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:fileencoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h new file mode 100644 index 000000000..f2fe03533 --- /dev/null +++ b/src/live_effects/lpe-taperstroke.h @@ -0,0 +1,73 @@ +/** @file + * @brief Taper Stroke path effect (meant as a replacement for using Power Strokes for tapering) + */ +/* Authors: + * Liam P White + * Copyright (C) 2014 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_LPE_SKELETON_H +#define INKSCAPE_LPE_SKELETON_H + +#include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/vector.h" + +namespace Inkscape { +namespace LivePathEffect { + +namespace TpS { + // we need a separate namespace to avoid clashes with other LPEs + class KnotHolderEntityAttachBegin; + class KnotHolderEntityAttachEnd; +} + +class LPETaperStroke : public Effect { +public: + LPETaperStroke(LivePathEffectObject *lpeobject); + virtual ~LPETaperStroke(); + + virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in); + Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in); + + virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); + + friend class TpS::KnotHolderEntityAttachBegin; + friend class TpS::KnotHolderEntityAttachEnd; +private: + ScalarParam attach_start; + ScalarParam attach_end; + ScalarParam smoothing; + EnumParam join_type; + ScalarParam miter_limit; + + Geom::Point start_attach_point; + Geom::Point end_attach_point; + + LPETaperStroke(const LPETaperStroke&); + LPETaperStroke& operator=(const LPETaperStroke&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +//because Windoze is stupid +# ifdef WIN32 +# include "lpe-taperstroke.cpp" +# endif + +#endif + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h new file mode 100755 index 000000000..8aa2e38ad --- /dev/null +++ b/src/live_effects/pathoutlineprovider.h @@ -0,0 +1,766 @@ +#pragma once + +#include <2geom/path.h> +#include <2geom/circle.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/shape.h> +#include <2geom/transforms.h> +#include <2geom/path-sink.h> + +#include +#include + +enum LineJoinType { + LINEJOIN_STRAIGHT, + LINEJOIN_ROUND, + LINEJOIN_POINTY, + LINEJOIN_REFLECTED, + LINEJOIN_EXTRAPOLATED +}; + +namespace Geom +{ + /** + * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/Circle-CircleIntersection.html + * + * @return 0 if no intersection + * @return 1 if one circle is contained in the other + * @return 2 if intersections are found (they are written to p0 and p1) + */ + static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, + Point & p0, Point & p1) + { + Point X0 = circle0.center(); + double r0 = circle0.ray(); + Point X1 = circle1.center(); + double r1 = circle1.ray(); + + /* dx and dy are the vertical and horizontal distances between + * the circle centers. + */ + Point D = X1 - X0; + + /* Determine the straight-line distance between the centers. */ + double d = L2(D); + + /* Check for solvability. */ + if (d > (r0 + r1)) + { + /* no solution. circles do not intersect. */ + return 0; + } + if (d <= fabs(r0 - r1)) + { + /* no solution. one circle is contained in the other */ + return 1; + } + + /* 'point 2' is the point where the line through the circle + * intersection points crosses the line between the circle + * centers. + */ + + /* Determine the distance from point 0 to point 2. */ + double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; + + /* Determine the coordinates of point 2. */ + Point p2 = X0 + D * (a/d); + + /* Determine the distance from point 2 to either of the + * intersection points. + */ + double h = std::sqrt((r0*r0) - (a*a)); + + /* Now determine the offsets of the intersection points from + * point 2. + */ + Point r = (h/d)*rot90(D); + + /* Determine the absolute intersection points. */ + p0 = p2 + r; + p1 = p2 - r; + + return 2; + } + /** + * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. + * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). + */ + static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) + { + D2 dM=derivative(curve); + if ( are_near(L2sq(dM(t)),0.) ) { + dM=derivative(dM); + } + if ( are_near(L2sq(dM(t)),0.) ) { // try second time + dM=derivative(dM); + } + Piecewise > unitv = unitVector(dM,tol); + Piecewise dMlength = dot(Piecewise >(dM),unitv); + Piecewise k = cross(derivative(unitv),unitv); + k = divide(k,dMlength,tol,3); + double curv = k(t); // note that this value is signed + + Geom::Point normal = unitTangentAt(curve, t).cw(); + double radius = 1/curv; + Geom::Point center = curve(t) + radius*normal; + return Geom::Circle(center, fabs(radius)); + } + + static std::vector split_at_cusps(const Geom::Path& in) + { + Geom::PathVector out = Geom::PathVector(); + Geom::Path temp = Geom::Path(); + + for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) + { + temp = Geom::Path(); + temp.append(in[path_descr]); + out.push_back(temp); + } + + return out; + } + + static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) + { + std::vector temp; + sbasis_to_bezier(temp, sbasis_in, 4); + return Geom::CubicBezier( temp ); + } + + static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, + Geom::Point const & origin_b, Geom::Point const & vector_b) + { + Geom::Coord denom = cross(vector_b, vector_a); + if (!Geom::are_near(denom,0.)){ + Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + return origin_a + t * vector_a; + } + return boost::none; + } +} + +namespace Outline +{ + + typedef Geom::D2 D2SB; + typedef Geom::Piecewise PWD2; + + static void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve*cbc2, Geom::Point endPt, double miter_limit) +{ + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (cross.empty()) + { + Geom::Path pth; + pth.append(*cbc1); + + Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); + + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + + Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(cbc1->toSBasis()), 0.); + Geom::Circle circle2 = Geom::touching_circle(cbc2->toSBasis(), 0); + + Geom::Point points[2]; + int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); + if (solutions == 2) + { + Geom::Point sol(0,0); + if ( dot(tang2,points[0]-endPt) > 0 ) + { + // points[0] is bad, choose points[1] + sol = points[1]; + } + else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] + // points[1] is bad, choose points[0] + sol = points[0]; + } + else + { + // both points are good, choose nearest + sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? + points[0] : points[1]; + } + Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); + Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + + if (arc0) + { + path_builder.append (arc0->toSBasis()); + delete arc0; + arc0 = NULL; + } + + if (arc1) + { + path_builder.append (arc1->toSBasis()); + delete arc1; + arc1 = NULL; + } + } + else + { + path_builder.appendNew (endPt); + } + } + else + { + path_builder.appendNew (endPt); + } +} + static Geom::Path half_outline_extrp(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) + { + Geom::PathVector pv = split_at_cusps(path_in); + unsigned m; + Path path_outline = Path(); + Path path_tangent = Path(); + + Geom::Point initialPoint; + Geom::Point endPoint; + + Geom::Path path_builder = Geom::Path(); + Geom::PathVector * pathvec; + + //load the first portion in before the loop starts + { + path_outline = Path(); + path_outline.LoadPath(pv[0], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + //now half of first cusp has been loaded + + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + //instead of array accessing twice, dereferencing used for clarity + initialPoint = (*pathvec)[0].initialPoint(); + + path_builder.start(initialPoint); + path_builder.append( (*pathvec)[0] ); + + path_outline = Path(); + path_outline.LoadPath(pv[1], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + + path_builder.append( (*pathvec)[0] ); + + //always set pointers null after deleting + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + for (m = 2; m < pv.size(); m++) + { + path_outline = Path(); + path_outline.LoadPath(pv[m], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + path_builder.append( (*pathvec)[0] ); + + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + return path_builder; + } + + //Create a reflected outline join. + //Note: it is generally recommended to let half_outline do this for you! + //path_builder: the path to append the curves to + //cbc1: the curve before the join + //cbc2: the curve after the join + //endPt: the point to end at + //miter_limit: the miter parameter + static void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit) + { + //the most important work for the reflected join is done here + + //determine where we are in the path. If we're on the inside, ignore + //and just lineTo. On the outside, we'll do a little reflection magic :) + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (cross.empty()) + { + //probably on the outside of the corner + Geom::Path pth; + pth.append(*cbc1); + + Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); + + //reflect curves along the bevel + D2SB newcurve1 = pth.toPwSb()[0] * + Geom::reflection ( -Geom::rot90(tang1) , + cbc1->finalPoint() ); + + Geom::CubicBezier bzr1 = sbasis_to_cubicbezier(Geom::reverse(newcurve1)); + + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + D2SB newcurve2 = pth.toPwSb()[0] * + Geom::reflection ( -Geom::rot90(tang2) , + cbc2->initialPoint() ); + Geom::CubicBezier bzr2 = sbasis_to_cubicbezier(Geom::reverse(newcurve2)); + + cross = Geom::crossings(bzr1, bzr2); + if ( cross.empty() ) + { + //std::cout << "Oops, no crossings!" << std::endl; + //curves didn't cross; default to miter + /*boost::optional p = intersection_point (cbc1->finalPoint(), tang1, + cbc2->initialPoint(), tang2); + if (p) + { + path_builder.appendNew (*p); + }*/ + //bevel + path_builder.appendNew( endPt ); + } + else + { + //join + std::pair sub1 = bzr1.subdivide(cross[0].ta); + std::pair sub2 = bzr2.subdivide(cross[0].tb); + + //@TODO joins have a strange tendency to cross themselves twice. Check this. + + //sections commented out are for general stability + path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); + path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); + } + } + else // cross.empty() + { + //probably on the inside of the corner + path_builder.appendNew ( endPt ); + } + } + + /** @brief Converts a path to one half of an outline. + * path_in: The input path to use. (To create the other side use path_in.reverse() ) + * line_width: the line width to use (usually you want to divide this by 2) + * linecap_type: (not used here) the cap to apply. Passed to libvarot. + * miter_limit: the miter parameter + */ + static Geom::Path half_outline(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) + { + Geom::PathVector pv = split_at_cusps(path_in); + unsigned m; + Path path_outline = Path(); + Path path_tangent = Path(); + //needed for closing the path + Geom::Point initialPoint; + Geom::Point endPoint; + + //some issues prevented me from using a PathBuilder here + //it seems like PathBuilder::peek() gave me a null reference exception + //and I was unable to get a stack trace on Windows, so had to switch to Linux + //to see what the hell was wrong. :( + //I wasted five hours opening it in IDAPro, VS2012, and GDB Windows + + /*Program received signal SIGSEGV, Segmentation fault. + 0x00000000006539ac in get_curves (this=0x0) + at /usr/include/c++/4.6/bits/locale_facets.h:1077 + 1077 { return __c; } + */ + + Geom::Path path_builder = Geom::Path(); + Geom::PathVector * pathvec; + + //load the first portion in before the loop starts + { + path_outline = Path(); + path_outline.LoadPath(pv[0], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + //now half of first cusp has been loaded + + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + //instead of array accessing twice, dereferencing used for clarity + initialPoint = (*pathvec)[0].initialPoint(); + + path_builder.start(initialPoint); + path_builder.append( (*pathvec)[0] ); + + path_outline = Path(); + path_outline.LoadPath(pv[1], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + + path_builder.append( (*pathvec)[0] ); + + //always set pointers null after deleting + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + for (m = 2; m < pv.size(); m++) + { + path_outline = Path(); + path_outline.LoadPath(pv[m], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + path_builder.append( (*pathvec)[0] ); + + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + return path_builder; + } + + static Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim) + { + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + Geom::PathVector path_out; + for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) + { + if (path_in[lmnop].size() > 1) + { + Geom::Path p_init; + Geom::Path p_rev; + Geom::PathBuilder pb = Geom::PathBuilder(); + + if ( !path_in[lmnop].closed() ) + { + p_init = Outline::half_outline( path_in[lmnop], -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline( path_in[lmnop].reverse(), -line_width, butt, + miter_lim ); + + pb.moveTo(p_init.initialPoint() ); + pb.append(p_init); + + //cap + if (butt == butt_straight) { + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } + + pb.append(p_rev); + + if (butt == butt_straight) { + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); + //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); + + pb.lineTo(p_init.initialPoint() ); + } + } + else + { + //final join + //refer to half_outline for documentation + Geom::Path p_almost = path_in[lmnop]; + p_almost.appendNew ( path_in[lmnop].initialPoint() ); + p_init = Outline::half_outline( p_almost, -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline( p_almost.reverse(), -line_width, butt, + miter_lim ); + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + + //this is a kludge, because I can't find how to make this work properly + bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), + path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == + (path_in[lmnop] [path_in[lmnop].size()].length())); + + p_almost = p_init; + if (lastIsLinear) + { + p_almost.erase_last(); p_almost.erase_last(); + } + + //outside test + Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); + Geom::Curve* cbc2 = p_almost[0].duplicate(); + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //this is the outside path + + //reuse the old one + p_init = p_almost; + Outline::reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside, carry on :-) + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + + p_almost = p_rev; + if (lastIsLinear) + { + p_almost.erase(p_almost.begin() ); + p_almost.erase(p_almost.begin() ); + } + + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + + cbc1 = p_almost[p_almost.size() - 1].duplicate(); + cbc2 = p_almost[0].duplicate(); + + cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //outside path + + p_init = p_almost; + reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + //pb.closePath(); + pb.flush(); + Geom::PathVector pv_np = pb.peek(); + //hack + for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) + { + path_out.push_back( pv_np[abcd] ); + } + } + else + { + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + p.Outline(&outlinepath, line_width / 2, join, butt, miter_lim); + std::vector *pv_p = outlinepath.MakePathVector(); + //hack + path_out.push_back( (*pv_p)[0].reverse() ); + delete pv_p; + } + } + return path_out; + } + static Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim) + { + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + Geom::PathVector path_out; + for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) + { + if (path_in[lmnop].size() > 1) + { + Geom::Path p_init; + Geom::Path p_rev; + Geom::PathBuilder pb = Geom::PathBuilder(); + + if ( !path_in[lmnop].closed() ) + { + p_init = Outline::half_outline_extrp( path_in[lmnop], -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline_extrp( path_in[lmnop].reverse(), -line_width, butt, + miter_lim ); + + pb.moveTo(p_init.initialPoint() ); + pb.append(p_init); + + //cap + if (butt == butt_straight) { + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } + + pb.append(p_rev); + + if (butt == butt_straight) { + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); + //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); + + pb.lineTo(p_init.initialPoint() ); + } + } + else + { + //final join + //refer to half_outline for documentation + Geom::Path p_almost = path_in[lmnop]; + p_almost.appendNew ( path_in[lmnop].initialPoint() ); + p_init = Outline::half_outline_extrp( p_almost, -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline_extrp( p_almost.reverse(), -line_width, butt, + miter_lim ); + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + + //this is a kludge, because I can't find how to make this work properly + bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), + path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == + (path_in[lmnop] [path_in[lmnop].size()].length())); + + p_almost = p_init; + if (lastIsLinear) + { + p_almost.erase_last(); p_almost.erase_last(); + } + + //outside test + Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); + Geom::Curve* cbc2 = p_almost[0].duplicate(); + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //this is the outside path + + //reuse the old one + p_init = p_almost; + Outline::extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside, carry on :-) + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + + p_almost = p_rev; + if (lastIsLinear) + { + p_almost.erase(p_almost.begin() ); + p_almost.erase(p_almost.begin() ); + } + + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + + cbc1 = p_almost[p_almost.size() - 1].duplicate(); + cbc2 = p_almost[0].duplicate(); + + cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //outside path + + p_init = p_almost; + extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + //pb.closePath(); + pb.flush(); + Geom::PathVector pv_np = pb.peek(); + //hack + for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) + { + path_out.push_back( pv_np[abcd] ); + } + } + else + { + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + p.Outline(&outlinepath, line_width / 2, join_pointy, butt, miter_lim); + std::vector *pv_p = outlinepath.MakePathVector(); + //hack + path_out.push_back( (*pv_p)[0].reverse() ); + delete pv_p; + } + } + return path_out; + } + + +} // namespace Outline + +/* + 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:encoding=utf-8:textwidth=99 : -- cgit v1.2.3 From ba99347e1308e6d183aaaf6e8d5f65cce4f4b74b Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 18 Mar 2014 21:00:36 -0600 Subject: Fix a compiler error on Windows (bzr r13090.1.27) --- src/live_effects/effect.cpp | 2 +- src/live_effects/lpe-taperstroke.cpp | 26 ++++++++++++++------------ src/live_effects/lpe-taperstroke.h | 6 +----- 3 files changed, 16 insertions(+), 18 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index d6840e5b8..337fe631f 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,7 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -//#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects +#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects #ifdef HAVE_CONFIG_H # include "config.h" diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index e6eed3abe..2cdc09376 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -55,6 +55,7 @@ static const Util::EnumDataConverter JoinTypeConverter(JoinType, sizeo LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), + line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 3), attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.2), @@ -67,7 +68,9 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : attach_start.param_set_digits(3); attach_end.param_set_digits(3); - + + + registerParameter( dynamic_cast(&line_width) ); registerParameter( dynamic_cast(&attach_start) ); registerParameter( dynamic_cast(&attach_end) ); registerParameter( dynamic_cast(&smoothing) ); @@ -235,31 +238,30 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //now for the fun stuff. Right? RIGHT? - //decide on case - - //first case: taper on both sides - if (true/*pathv_out[0].length() != 0.001 && pathv_out[2].length() != 0.001*/) { + if (true) { Geom::PathVector real_pathv; - //Construct the pattern - - Geom::PathVector pat_vec = sp_svg_read_pathv("M 1,0 1,1 C 0.5,1 0,0.5 0,0.5 0,0.5 0.5,0 1,0 Z"); + //Construct the pattern (pat_str stands for pattern string) + char* pat_str = new char[200]; + sprintf(pat_str, "M 1,0 1,1 C %5.5f,1 0,0.5 0,0.5 0,0.5 %5.5f,0 1,0 Z", (double)smoothing, (double)smoothing); + Geom::PathVector pat_vec = sp_svg_read_pathv(pat_str); Geom::Piecewise > pwd2; - pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], 40)); + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], line_width)); real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0]); Geom::PathVector sht_path; sht_path.push_back(pathv_out[1]); - sht_path = Outline::outlinePath_extr(sht_path, 40, LINEJOIN_STRAIGHT, butt_straight, 30); + sht_path = Outline::outlinePath_extr(sht_path, line_width, LINEJOIN_STRAIGHT, butt_straight, miter_limit); real_pathv.push_back(sht_path[0]); - pat_vec = sp_svg_read_pathv("M 0,0 0,1 C 0.5,1 1,0.5 1,0.5 1,0.5 0.5,0 0,0 Z"); + sprintf(pat_str, "M 0,0 0,1 C %5.5f,1 1,0.5 1,0.5 1,0.5 %5.5f,0 0,0 Z", (double)smoothing, (double)smoothing); + pat_vec = sp_svg_read_pathv(pat_str); pwd2 = Geom::Piecewise > (); - pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], 40)); + pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], line_width)); real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0].reverse()); //clever union diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h index f2fe03533..7cb8bc85e 100644 --- a/src/live_effects/lpe-taperstroke.h +++ b/src/live_effects/lpe-taperstroke.h @@ -38,6 +38,7 @@ public: friend class TpS::KnotHolderEntityAttachBegin; friend class TpS::KnotHolderEntityAttachEnd; private: + ScalarParam line_width; ScalarParam attach_start; ScalarParam attach_end; ScalarParam smoothing; @@ -54,11 +55,6 @@ private: } //namespace LivePathEffect } //namespace Inkscape -//because Windoze is stupid -# ifdef WIN32 -# include "lpe-taperstroke.cpp" -# endif - #endif /* -- cgit v1.2.3 From 9a04c985ec628dc749a8a82d94bcf47d482a4f63 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 20 Mar 2014 17:09:57 -0400 Subject: Fix a linker error ("static") (hopefully) Resolve compiler errors with GTK3+ (bzr r13090.1.28) --- src/live_effects/Makefile_insert | 1 + src/live_effects/effect.cpp | 2 +- src/live_effects/lpe-taperstroke.cpp | 162 ++++-- src/live_effects/lpe-taperstroke.h | 9 +- src/live_effects/pathoutlineprovider.cpp | 840 +++++++++++++++++++++++++++++++ src/live_effects/pathoutlineprovider.h | 791 +---------------------------- 6 files changed, 997 insertions(+), 808 deletions(-) create mode 100755 src/live_effects/pathoutlineprovider.cpp mode change 100755 => 100644 src/live_effects/pathoutlineprovider.h (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index b19f417ae..ac7c33e2f 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -93,6 +93,7 @@ ink_common_sources += \ live_effects/lpe-fill-between-many.h \ live_effects/lpe-ellipse_5pts.cpp \ live_effects/lpe-ellipse_5pts.h \ + live_effects/pathoutlineprovider.cpp \ live_effects/lpe-jointype.cpp \ live_effects/lpe-jointype.h \ live_effects/lpe-taperstroke.cpp \ diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 337fe631f..d6840e5b8 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,7 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects +//#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects #ifdef HAVE_CONFIG_H # include "config.h" diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 2cdc09376..a862417d7 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -13,11 +13,20 @@ #include "live_effects/lpe-taperstroke.h" -// You might need to include other 2geom files. You can add them here: #include <2geom/path.h> #include <2geom/shape.h> +#include <2geom/path.h> +#include <2geom/circle.h> +#include <2geom/sbasis-to-bezier.h> #include "pathoutlineprovider.h" #include "display/curve.h" +#include "sp-shape.h" +#include "style.h" +#include "xml/repr.h" +#include "sp-paint-server.h" +#include "svg/svg-color.h" +#include "desktop-style.h" +#include "svg/css-ostringstream.h" #include "svg/svg.h" //#include @@ -58,7 +67,7 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 3), attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), - smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.2), + smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5), join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 30.) { @@ -83,21 +92,93 @@ LPETaperStroke::~LPETaperStroke() } -unsigned curveOrder (const Geom::Curve* curve_in) +//from LPEPowerStroke -- sets fill if stroke color because we will +//be converting to a fill to make the new join. + +void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) { - using namespace Geom; - //cast it - const CubicBezier *cbc = dynamic_cast(curve_in); - if (cbc) return 3; - const QuadraticBezier * qbc = dynamic_cast(curve_in); - if (qbc) return 2; - const BezierCurveN<1U> * lbc = dynamic_cast *>(curve_in); - if (lbc) return 1; - //BezierCurveN<0> * dbc = dynamic_cast *> (curve_in); - return 0; + if (SP_IS_SHAPE(lpeitem)) { + SPLPEItem* item = const_cast(lpeitem); + double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; + + SPCSSAttr *css = sp_repr_css_attr_new (); + if (lpeitem->style->stroke.isSet()) { + if (lpeitem->style->stroke.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getStrokePaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "fill", str.c_str()); + } + } else if (lpeitem->style->stroke.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "fill", c); + } else { + sp_repr_css_set_property (css, "fill", "none"); + } + } else { + sp_repr_css_unset_property (css, "fill"); + } + + sp_repr_css_set_property(css, "stroke", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); + + line_width.param_set_value(width); + } else { + g_warning("LPE Join Type can only be applied to paths (not groups)."); + } } -Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_tolerance = 0.01) +//from LPEPowerStroke -- sets stroke color from existing fill color + +void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) +{ + + if (SP_IS_SHAPE(lpeitem)) { + SPLPEItem *item = const_cast(lpeitem); + + SPCSSAttr *css = sp_repr_css_attr_new (); + if (lpeitem->style->fill.isSet()) { + if (lpeitem->style->fill.isPaintserver()) { + SPPaintServer * server = lpeitem->style->getFillPaintServer(); + if (server) { + Glib::ustring str; + str += "url(#"; + str += server->getId(); + str += ")"; + sp_repr_css_set_property (css, "stroke", str.c_str()); + } + } else if (lpeitem->style->fill.isColor()) { + gchar c[64]; + sp_svg_write_color (c, sizeof(c), lpeitem->style->stroke.value.color.toRGBA32(SP_SCALE24_TO_FLOAT(lpeitem->style->stroke_opacity.value))); + sp_repr_css_set_property (css, "stroke", c); + } else { + sp_repr_css_set_property (css, "stroke", "none"); + } + } else { + sp_repr_css_unset_property (css, "stroke"); + } + + Inkscape::CSSOStringStream os; + os << fabs(line_width); + sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); + + sp_repr_css_set_property(css, "fill", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); + item->updateRepr(); + } +} + +//actual effect impl here + +Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_tolerance = 0.05) { Geom::Path path_out = Geom::Path(); @@ -108,7 +189,7 @@ Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_toler break; //determine order of curve - int order = curveOrder(&path_in[i]); + int order = Outline::bezierOrder(&path_in[i]); Geom::Point start_point; Geom::Point cross_point = path_in[i].finalPoint(); @@ -131,7 +212,7 @@ Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_toler start_point = path_in[i].initialPoint(); } - order = curveOrder(&path_in[i+1]); + order = Outline::bezierOrder(&path_in[i+1]); switch (order) { @@ -155,7 +236,7 @@ Geom::Curve * subdivide_at(const Geom::Curve* curve_in, Geom::Coord time, bool f { //the only reason for this function is the lack of a subdivide function in the Curve class. //you have to cast to Beziers to be able to use subdivide(t) - unsigned order = curveOrder(curve_in); + unsigned order = Outline::bezierOrder(curve_in); Geom::Curve* curve_out = curve_in->duplicate(); switch (order) { @@ -211,22 +292,25 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) if (attach_end <= 0) { attach_end.param_set_value( 0.0001 ); } + + //don't let it be integer + if (double(unsigned(attach_start)) == attach_start) { + attach_start.param_set_value(attach_start - 0.0001); + } + if (double(unsigned(attach_end)) == attach_end) { + attach_end.param_set_value(attach_end - 0.0001); + } - /*if (size != return_at_first_cusp(path_in[0]).size()) { //will get to this in a bit - //check to see if either knot was dragged past their allowed amount - volatile unsigned size_p_start = (unsigned)attach_start; - volatile unsigned size_p_end = (unsigned)attach_end; - - //maximum allowed value in either direction is return_at_first_cusp(path_in[0]).size - volatile unsigned allowed_p_start = return_at_first_cusp(path_in[0]).size(); - volatile unsigned allowed_p_end = return_at_first_cusp(path_in[0].reverse()).size(); - - if (size_p_start > allowed_p_start) { - attach_start.param_set_value(allowed_p_start - 0.0001); - } else if (size_p_end > allowed_p_end) { - attach_end.param_set_value(allowed_p_end - 0.0001); - } - }*/ + unsigned allowed_start = return_at_first_cusp(path_in[0]).size(); + + unsigned allowed_end = return_at_first_cusp(path_in[0].reverse()).size(); + + if ((unsigned)attach_start >= allowed_start) { + attach_start.param_set_value((double)allowed_start - 0.0001); + } + if ((unsigned)attach_end >= allowed_end) { + attach_end.param_set_value((double)allowed_end - 0.0001); + } //Path::operator () means get point at time t start_attach_point = return_at_first_cusp(path_in[0])(attach_start); @@ -242,8 +326,8 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) Geom::PathVector real_pathv; //Construct the pattern (pat_str stands for pattern string) - char* pat_str = new char[200]; - sprintf(pat_str, "M 1,0 1,1 C %5.5f,1 0,0.5 0,0.5 0,0.5 %5.5f,0 1,0 Z", (double)smoothing, (double)smoothing); + char pat_str[200]; + sprintf(pat_str, "M 1,0 1,1 C %5.5f,1 0,0.5 0,0.5 0,0.5 %5.5f,0 1,0 Z", 1 - (double)smoothing, 1 - (double)smoothing); Geom::PathVector pat_vec = sp_svg_read_pathv(pat_str); Geom::Piecewise > pwd2; @@ -253,12 +337,13 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) Geom::PathVector sht_path; sht_path.push_back(pathv_out[1]); - sht_path = Outline::outlinePath_extr(sht_path, line_width, LINEJOIN_STRAIGHT, butt_straight, miter_limit); + sht_path = Outline::PathVectorOutline(sht_path, line_width, butt_straight, static_cast(join_type.get_value()) , miter_limit); real_pathv.push_back(sht_path[0]); - sprintf(pat_str, "M 0,0 0,1 C %5.5f,1 1,0.5 1,0.5 1,0.5 %5.5f,0 0,0 Z", (double)smoothing, (double)smoothing); - pat_vec = sp_svg_read_pathv(pat_str); + char pat_str_1[200]; + sprintf(pat_str_1, "M 0,0 0,1 C %5.5f,1 1,0.5 1,0.5 1,0.5 %5.5f,0 0,0 Z", (double)smoothing, (double)smoothing); + pat_vec = sp_svg_read_pathv(pat_str_1); pwd2 = Geom::Piecewise > (); pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], line_width)); @@ -298,7 +383,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa trimmed_start.append(path_in[0] [i]); } - #define OVERLAP 0.001 + #define OVERLAP (0.001 / (line_width < 1 ? 1 : line_width)) trimmed_start.append(*subdivide_at(curve_start, (attach_start - loc) + OVERLAP, true)); curve_start = subdivide_at(curve_start, attach_start - loc, false); @@ -451,6 +536,7 @@ Geom::Piecewise > stretch_along(Geom::Piecewise +#include <2geom/path.h> +#include <2geom/circle.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/shape.h> +#include <2geom/transforms.h> +#include <2geom/path-sink.h> + +namespace Geom +{ + /** + * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/Circle-CircleIntersection.html + * + * @return 0 if no intersection + * @return 1 if one circle is contained in the other + * @return 2 if intersections are found (they are written to p0 and p1) + */ + static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, + Point & p0, Point & p1) + { + Point X0 = circle0.center(); + double r0 = circle0.ray(); + Point X1 = circle1.center(); + double r1 = circle1.ray(); + + /* dx and dy are the vertical and horizontal distances between + * the circle centers. + */ + Point D = X1 - X0; + + /* Determine the straight-line distance between the centers. */ + double d = L2(D); + + /* Check for solvability. */ + if (d > (r0 + r1)) + { + /* no solution. circles do not intersect. */ + return 0; + } + if (d <= fabs(r0 - r1)) + { + /* no solution. one circle is contained in the other */ + return 1; + } + + /* 'point 2' is the point where the line through the circle + * intersection points crosses the line between the circle + * centers. + */ + + /* Determine the distance from point 0 to point 2. */ + double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; + + /* Determine the coordinates of point 2. */ + Point p2 = X0 + D * (a/d); + + /* Determine the distance from point 2 to either of the + * intersection points. + */ + double h = std::sqrt((r0*r0) - (a*a)); + + /* Now determine the offsets of the intersection points from + * point 2. + */ + Point r = (h/d)*rot90(D); + + /* Determine the absolute intersection points. */ + p0 = p2 + r; + p1 = p2 - r; + + return 2; + } + /** + * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. + * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). + */ + static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) + { + D2 dM=derivative(curve); + if ( are_near(L2sq(dM(t)),0.) ) { + dM=derivative(dM); + } + if ( are_near(L2sq(dM(t)),0.) ) { // try second time + dM=derivative(dM); + } + Piecewise > unitv = unitVector(dM,tol); + Piecewise dMlength = dot(Piecewise >(dM),unitv); + Piecewise k = cross(derivative(unitv),unitv); + k = divide(k,dMlength,tol,3); + double curv = k(t); // note that this value is signed + + Geom::Point normal = unitTangentAt(curve, t).cw(); + double radius = 1/curv; + Geom::Point center = curve(t) + radius*normal; + return Geom::Circle(center, fabs(radius)); + } + + static std::vector split_at_cusps(const Geom::Path& in) + { + Geom::PathVector out = Geom::PathVector(); + Geom::Path temp = Geom::Path(); + + for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) + { + temp = Geom::Path(); + temp.append(in[path_descr]); + out.push_back(temp); + } + + return out; + } + + static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) + { + std::vector temp; + sbasis_to_bezier(temp, sbasis_in, 4); + return Geom::CubicBezier( temp ); + } + + static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, + Geom::Point const & origin_b, Geom::Point const & vector_b) + { + Geom::Coord denom = cross(vector_b, vector_a); + if (!Geom::are_near(denom,0.)){ + Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + return origin_a + t * vector_a; + } + return boost::none; + } +} + +namespace Outline +{ + +typedef Geom::D2 D2SB; +typedef Geom::Piecewise PWD2; + +unsigned bezierOrder (const Geom::Curve* curve_in) +{ + using namespace Geom; + //cast it + const CubicBezier *cbc = dynamic_cast(curve_in); + if (cbc) return 3; + const QuadraticBezier * qbc = dynamic_cast(curve_in); + if (qbc) return 2; + const BezierCurveN<1U> * lbc = dynamic_cast *>(curve_in); + if (lbc) return 1; + return 0; +} + +//returns true if the angle formed by the curves and their handles +//is >180 clockwise, otherwise false. +bool outside_angle (const Geom::Curve* cbc1, const Geom::Curve* cbc2) +{ + Geom::Point start_point = cbc1->initialPoint(); + Geom::Point end_point = cbc2->finalPoint(); + unsigned order = bezierOrder(cbc1); + switch (order) + { + case 3: + start_point = ( dynamic_cast(cbc1) )->operator [] (2); + break; + case 2: + start_point = ( dynamic_cast(cbc1) )->operator [] (1); + break; + } + order = bezierOrder(cbc2); + switch (order) + { + case 3: + end_point = ( dynamic_cast(cbc2) )->operator [] (1); + break; + case 2: + end_point = ( dynamic_cast(cbc2) )->operator[] (1); + break; + } + return false; +} + +void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve*cbc2, Geom::Point endPt, double miter_limit) +{ + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (cross.empty()) + { + Geom::Path pth; + pth.append(*cbc1); + + //Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); + + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + + Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(cbc1->toSBasis()), 0.); + Geom::Circle circle2 = Geom::touching_circle(cbc2->toSBasis(), 0); + + Geom::Point points[2]; + int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); + if (solutions == 2) + { + Geom::Point sol(0,0); + if ( dot(tang2,points[0]-endPt) > 0 ) + { + // points[0] is bad, choose points[1] + sol = points[1]; + } + else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] + // points[1] is bad, choose points[0] + sol = points[0]; + } + else + { + // both points are good, choose nearest + sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? + points[0] : points[1]; + } + Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); + Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + + if (arc0) + { + path_builder.append (arc0->toSBasis()); + delete arc0; + arc0 = NULL; + } + + if (arc1) + { + path_builder.append (arc1->toSBasis()); + delete arc1; + arc1 = NULL; + } + } + else + { + path_builder.appendNew (endPt); + } + } + else + { + path_builder.appendNew (endPt); + } +} + Geom::Path half_outline_extrp(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) + { + Geom::PathVector pv = split_at_cusps(path_in); + unsigned m; + Path path_outline = Path(); + Path path_tangent = Path(); + + Geom::Point initialPoint; + Geom::Point endPoint; + + Geom::Path path_builder = Geom::Path(); + Geom::PathVector * pathvec; + + //load the first portion in before the loop starts + { + path_outline = Path(); + path_outline.LoadPath(pv[0], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + //now half of first cusp has been loaded + + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + //instead of array accessing twice, dereferencing used for clarity + initialPoint = (*pathvec)[0].initialPoint(); + + path_builder.start(initialPoint); + path_builder.append( (*pathvec)[0] ); + + path_outline = Path(); + path_outline.LoadPath(pv[1], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + + path_builder.append( (*pathvec)[0] ); + + //always set pointers null after deleting + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + for (m = 2; m < pv.size(); m++) + { + path_outline = Path(); + path_outline.LoadPath(pv[m], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + path_builder.append( (*pathvec)[0] ); + + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + return path_builder; + } + + //Create a reflected outline join. + //Note: it is generally recommended to let half_outline do this for you! + //path_builder: the path to append the curves to + //cbc1: the curve before the join + //cbc2: the curve after the join + //endPt: the point to end at + //miter_limit: the miter parameter + void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit) + { + //the most important work for the reflected join is done here + + //determine where we are in the path. If we're on the inside, ignore + //and just lineTo. On the outside, we'll do a little reflection magic :) + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (cross.empty()) + { + //probably on the outside of the corner + Geom::Path pth; + pth.append(*cbc1); + + Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); + + //reflect curves along the bevel + D2SB newcurve1 = pth.toPwSb()[0] * + Geom::reflection ( -Geom::rot90(tang1) , + cbc1->finalPoint() ); + + Geom::CubicBezier bzr1 = sbasis_to_cubicbezier(Geom::reverse(newcurve1)); + + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + D2SB newcurve2 = pth.toPwSb()[0] * + Geom::reflection ( -Geom::rot90(tang2) , + cbc2->initialPoint() ); + Geom::CubicBezier bzr2 = sbasis_to_cubicbezier(Geom::reverse(newcurve2)); + + cross = Geom::crossings(bzr1, bzr2); + if ( cross.empty() ) + { + //std::cout << "Oops, no crossings!" << std::endl; + //curves didn't cross; default to miter + /*boost::optional p = intersection_point (cbc1->finalPoint(), tang1, + cbc2->initialPoint(), tang2); + if (p) + { + path_builder.appendNew (*p); + }*/ + //bevel + path_builder.appendNew( endPt ); + } + else + { + //join + std::pair sub1 = bzr1.subdivide(cross[0].ta); + std::pair sub2 = bzr2.subdivide(cross[0].tb); + + //@TODO joins have a strange tendency to cross themselves twice. Check this. + + //sections commented out are for general stability + path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); + path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); + } + } + else // cross.empty() + { + //probably on the inside of the corner + path_builder.appendNew ( endPt ); + } + } + + /** @brief Converts a path to one half of an outline. + * path_in: The input path to use. (To create the other side use path_in.reverse() ) + * line_width: the line width to use (usually you want to divide this by 2) + * linecap_type: (not used here) the cap to apply. Passed to libvarot. + * miter_limit: the miter parameter + */ + Geom::Path half_outline(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) + { + Geom::PathVector pv = split_at_cusps(path_in); + unsigned m; + Path path_outline = Path(); + Path path_tangent = Path(); + //needed for closing the path + Geom::Point initialPoint; + Geom::Point endPoint; + + //some issues prevented me from using a PathBuilder here + //it seems like PathBuilder::peek() gave me a null reference exception + //and I was unable to get a stack trace on Windows, so had to switch to Linux + //to see what the hell was wrong. :( + //I wasted five hours opening it in IDAPro, VS2012, and GDB Windows + + /*Program received signal SIGSEGV, Segmentation fault. + 0x00000000006539ac in get_curves (this=0x0) + at /usr/include/c++/4.6/bits/locale_facets.h:1077 + 1077 { return __c; } + */ + + Geom::Path path_builder = Geom::Path(); + Geom::PathVector * pathvec; + + //load the first portion in before the loop starts + { + path_outline = Path(); + path_outline.LoadPath(pv[0], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + //now half of first cusp has been loaded + + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + //instead of array accessing twice, dereferencing used for clarity + initialPoint = (*pathvec)[0].initialPoint(); + + path_builder.start(initialPoint); + path_builder.append( (*pathvec)[0] ); + + path_outline = Path(); + path_outline.LoadPath(pv[1], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + path_tangent = Path(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + + path_builder.append( (*pathvec)[0] ); + + //always set pointers null after deleting + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + for (m = 2; m < pv.size(); m++) + { + path_outline = Path(); + path_outline.LoadPath(pv[m], Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); + + delete pathvec; pathvec = NULL; + pathvec = path_tangent.MakePathVector(); + + Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); + Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); + + reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); + path_builder.append( (*pathvec)[0] ); + + delete pathvec; pathvec = NULL; + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + + return path_builder; + } + + Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim) + { + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + Geom::PathVector path_out; + for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) + { + if (path_in[lmnop].size() > 1) + { + Geom::Path p_init; + Geom::Path p_rev; + Geom::PathBuilder pb = Geom::PathBuilder(); + + if ( !path_in[lmnop].closed() ) + { + p_init = Outline::half_outline( path_in[lmnop], -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline( path_in[lmnop].reverse(), -line_width, butt, + miter_lim ); + + pb.moveTo(p_init.initialPoint() ); + pb.append(p_init); + + //cap + if (butt == butt_straight) { + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } + + pb.append(p_rev); + + if (butt == butt_straight) { + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); + //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); + + pb.lineTo(p_init.initialPoint() ); + } + } + else + { + //final join + //refer to half_outline for documentation + Geom::Path p_almost = path_in[lmnop]; + p_almost.appendNew ( path_in[lmnop].initialPoint() ); + p_init = Outline::half_outline( p_almost, -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline( p_almost.reverse(), -line_width, butt, + miter_lim ); + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + + //this is a kludge, because I can't find how to make this work properly + bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), + path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == + (path_in[lmnop] [path_in[lmnop].size()].length())); + + p_almost = p_init; + if (lastIsLinear) + { + p_almost.erase_last(); p_almost.erase_last(); + } + + //outside test + Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); + Geom::Curve* cbc2 = p_almost[0].duplicate(); + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //this is the outside path + + //reuse the old one + p_init = p_almost; + Outline::reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside, carry on :-) + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + + p_almost = p_rev; + if (lastIsLinear) + { + p_almost.erase(p_almost.begin() ); + p_almost.erase(p_almost.begin() ); + } + + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + + cbc1 = p_almost[p_almost.size() - 1].duplicate(); + cbc2 = p_almost[0].duplicate(); + + cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //outside path + + p_init = p_almost; + reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + //pb.closePath(); + pb.flush(); + Geom::PathVector pv_np = pb.peek(); + //hack + for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) + { + path_out.push_back( pv_np[abcd] ); + } + } + else + { + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + p.Outline(&outlinepath, line_width / 2, join, butt, miter_lim); + std::vector *pv_p = outlinepath.MakePathVector(); + //hack + path_out.push_back( (*pv_p)[0].reverse() ); + delete pv_p; + } + } + return path_out; + } + Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim) + { + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + Geom::PathVector path_out; + for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) + { + if (path_in[lmnop].size() > 1) + { + Geom::Path p_init; + Geom::Path p_rev; + Geom::PathBuilder pb = Geom::PathBuilder(); + + if ( !path_in[lmnop].closed() ) + { + p_init = Outline::half_outline_extrp( path_in[lmnop], -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline_extrp( path_in[lmnop].reverse(), -line_width, butt, + miter_lim ); + + pb.moveTo(p_init.initialPoint() ); + pb.append(p_init); + + //cap + if (butt == butt_straight) { + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + pb.lineTo(p_rev.initialPoint() ); + } + + pb.append(p_rev); + + if (butt == butt_straight) { + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_round) { + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); + } else if (butt == butt_square) { + //don't know what to do + pb.lineTo(p_init.initialPoint() ); + } else if (butt == butt_pointy) { + //don't know what to do + //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); + //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); + + pb.lineTo(p_init.initialPoint() ); + } + } + else + { + //final join + //refer to half_outline for documentation + Geom::Path p_almost = path_in[lmnop]; + p_almost.appendNew ( path_in[lmnop].initialPoint() ); + p_init = Outline::half_outline_extrp( p_almost, -line_width, butt, + miter_lim ); + p_rev = Outline::half_outline_extrp( p_almost.reverse(), -line_width, butt, + miter_lim ); + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + + //this is a kludge, because I can't find how to make this work properly + bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), + path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == + (path_in[lmnop] [path_in[lmnop].size()].length())); + + p_almost = p_init; + if (lastIsLinear) + { + p_almost.erase_last(); p_almost.erase_last(); + } + + //outside test + Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); + Geom::Curve* cbc2 = p_almost[0].duplicate(); + + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //this is the outside path + + //reuse the old one + p_init = p_almost; + Outline::extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside, carry on :-) + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + + p_almost = p_rev; + if (lastIsLinear) + { + p_almost.erase(p_almost.begin() ); + p_almost.erase(p_almost.begin() ); + } + + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + + cbc1 = p_almost[p_almost.size() - 1].duplicate(); + cbc2 = p_almost[0].duplicate(); + + cross = Geom::crossings(*cbc1, *cbc2); + + if (cross.empty()) + { + //outside path + + p_init = p_almost; + extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); + pb.moveTo(p_init.initialPoint()); pb.append(p_init); + } + else + { + //inside + pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); + } + delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; + } + //pb.closePath(); + pb.flush(); + Geom::PathVector pv_np = pb.peek(); + //hack + for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) + { + path_out.push_back( pv_np[abcd] ); + } + } + else + { + p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); + p.Outline(&outlinepath, line_width / 2, join_pointy, butt, miter_lim); + std::vector *pv_p = outlinepath.MakePathVector(); + //hack + path_out.push_back( (*pv_p)[0].reverse() ); + delete pv_p; + } + } + return path_out; + } + +Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtType linecap_type, + join_typ linejoin_type, double miter_limit) +{ + std::vector path_out = std::vector(); + if (path_in.empty()) + { + return path_out; + } + Path p = Path(); + Path outlinepath = Path(); + for (unsigned i = 0; i < path_in.size(); i++) + { + p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); + } + + #define miter_lim fabs(line_width * miter_limit) + + //magic! + if (linejoin_type <= 2) + { + p.Outline(&outlinepath, line_width / 2, linejoin_type, + linecap_type, miter_lim); + //fix memory leak + std::vector *pv_p = outlinepath.MakePathVector(); + path_out = *pv_p; + delete pv_p; + + } else if (linejoin_type == 3) { + //reflected arc join + path_out = outlinePath(path_in, line_width, linejoin_type, + linecap_type , miter_lim); + + } else if (linejoin_type == 4) { + //extrapolated arc join + path_out = outlinePath_extr(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim); + + } + + #undef miter_lim + return path_out; +} + +} // namespace Outline + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h old mode 100755 new mode 100644 index 8aa2e38ad..1a363c35b --- a/src/live_effects/pathoutlineprovider.h +++ b/src/live_effects/pathoutlineprovider.h @@ -1,766 +1,25 @@ -#pragma once - -#include <2geom/path.h> -#include <2geom/circle.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/shape.h> -#include <2geom/transforms.h> -#include <2geom/path-sink.h> - -#include -#include - -enum LineJoinType { - LINEJOIN_STRAIGHT, - LINEJOIN_ROUND, - LINEJOIN_POINTY, - LINEJOIN_REFLECTED, - LINEJOIN_EXTRAPOLATED -}; - -namespace Geom -{ - /** - * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/Circle-CircleIntersection.html - * - * @return 0 if no intersection - * @return 1 if one circle is contained in the other - * @return 2 if intersections are found (they are written to p0 and p1) - */ - static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, - Point & p0, Point & p1) - { - Point X0 = circle0.center(); - double r0 = circle0.ray(); - Point X1 = circle1.center(); - double r1 = circle1.ray(); - - /* dx and dy are the vertical and horizontal distances between - * the circle centers. - */ - Point D = X1 - X0; - - /* Determine the straight-line distance between the centers. */ - double d = L2(D); - - /* Check for solvability. */ - if (d > (r0 + r1)) - { - /* no solution. circles do not intersect. */ - return 0; - } - if (d <= fabs(r0 - r1)) - { - /* no solution. one circle is contained in the other */ - return 1; - } - - /* 'point 2' is the point where the line through the circle - * intersection points crosses the line between the circle - * centers. - */ - - /* Determine the distance from point 0 to point 2. */ - double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; - - /* Determine the coordinates of point 2. */ - Point p2 = X0 + D * (a/d); - - /* Determine the distance from point 2 to either of the - * intersection points. - */ - double h = std::sqrt((r0*r0) - (a*a)); - - /* Now determine the offsets of the intersection points from - * point 2. - */ - Point r = (h/d)*rot90(D); - - /* Determine the absolute intersection points. */ - p0 = p2 + r; - p1 = p2 - r; - - return 2; - } - /** - * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. - * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). - */ - static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) - { - D2 dM=derivative(curve); - if ( are_near(L2sq(dM(t)),0.) ) { - dM=derivative(dM); - } - if ( are_near(L2sq(dM(t)),0.) ) { // try second time - dM=derivative(dM); - } - Piecewise > unitv = unitVector(dM,tol); - Piecewise dMlength = dot(Piecewise >(dM),unitv); - Piecewise k = cross(derivative(unitv),unitv); - k = divide(k,dMlength,tol,3); - double curv = k(t); // note that this value is signed - - Geom::Point normal = unitTangentAt(curve, t).cw(); - double radius = 1/curv; - Geom::Point center = curve(t) + radius*normal; - return Geom::Circle(center, fabs(radius)); - } - - static std::vector split_at_cusps(const Geom::Path& in) - { - Geom::PathVector out = Geom::PathVector(); - Geom::Path temp = Geom::Path(); - - for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) - { - temp = Geom::Path(); - temp.append(in[path_descr]); - out.push_back(temp); - } - - return out; - } - - static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) - { - std::vector temp; - sbasis_to_bezier(temp, sbasis_in, 4); - return Geom::CubicBezier( temp ); - } - - static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, - Geom::Point const & origin_b, Geom::Point const & vector_b) - { - Geom::Coord denom = cross(vector_b, vector_a); - if (!Geom::are_near(denom,0.)){ - Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; - return origin_a + t * vector_a; - } - return boost::none; - } -} - -namespace Outline -{ - - typedef Geom::D2 D2SB; - typedef Geom::Piecewise PWD2; - - static void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve*cbc2, Geom::Point endPt, double miter_limit) -{ - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - if (cross.empty()) - { - Geom::Path pth; - pth.append(*cbc1); - - Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); - - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - - Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(cbc1->toSBasis()), 0.); - Geom::Circle circle2 = Geom::touching_circle(cbc2->toSBasis(), 0); - - Geom::Point points[2]; - int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); - if (solutions == 2) - { - Geom::Point sol(0,0); - if ( dot(tang2,points[0]-endPt) > 0 ) - { - // points[0] is bad, choose points[1] - sol = points[1]; - } - else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] - // points[1] is bad, choose points[0] - sol = points[0]; - } - else - { - // both points are good, choose nearest - sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? - points[0] : points[1]; - } - Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); - Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); - - if (arc0) - { - path_builder.append (arc0->toSBasis()); - delete arc0; - arc0 = NULL; - } - - if (arc1) - { - path_builder.append (arc1->toSBasis()); - delete arc1; - arc1 = NULL; - } - } - else - { - path_builder.appendNew (endPt); - } - } - else - { - path_builder.appendNew (endPt); - } -} - static Geom::Path half_outline_extrp(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) - { - Geom::PathVector pv = split_at_cusps(path_in); - unsigned m; - Path path_outline = Path(); - Path path_tangent = Path(); - - Geom::Point initialPoint; - Geom::Point endPoint; - - Geom::Path path_builder = Geom::Path(); - Geom::PathVector * pathvec; - - //load the first portion in before the loop starts - { - path_outline = Path(); - path_outline.LoadPath(pv[0], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - //now half of first cusp has been loaded - - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - //instead of array accessing twice, dereferencing used for clarity - initialPoint = (*pathvec)[0].initialPoint(); - - path_builder.start(initialPoint); - path_builder.append( (*pathvec)[0] ); - - path_outline = Path(); - path_outline.LoadPath(pv[1], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - - path_builder.append( (*pathvec)[0] ); - - //always set pointers null after deleting - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - for (m = 2; m < pv.size(); m++) - { - path_outline = Path(); - path_outline.LoadPath(pv[m], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - extrapolate_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - path_builder.append( (*pathvec)[0] ); - - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - return path_builder; - } - - //Create a reflected outline join. - //Note: it is generally recommended to let half_outline do this for you! - //path_builder: the path to append the curves to - //cbc1: the curve before the join - //cbc2: the curve after the join - //endPt: the point to end at - //miter_limit: the miter parameter - static void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit) - { - //the most important work for the reflected join is done here - - //determine where we are in the path. If we're on the inside, ignore - //and just lineTo. On the outside, we'll do a little reflection magic :) - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - if (cross.empty()) - { - //probably on the outside of the corner - Geom::Path pth; - pth.append(*cbc1); - - Geom::Point tang1 = Geom::unitTangentAt(pth.toPwSb()[0], 1); - - //reflect curves along the bevel - D2SB newcurve1 = pth.toPwSb()[0] * - Geom::reflection ( -Geom::rot90(tang1) , - cbc1->finalPoint() ); - - Geom::CubicBezier bzr1 = sbasis_to_cubicbezier(Geom::reverse(newcurve1)); - - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - D2SB newcurve2 = pth.toPwSb()[0] * - Geom::reflection ( -Geom::rot90(tang2) , - cbc2->initialPoint() ); - Geom::CubicBezier bzr2 = sbasis_to_cubicbezier(Geom::reverse(newcurve2)); - - cross = Geom::crossings(bzr1, bzr2); - if ( cross.empty() ) - { - //std::cout << "Oops, no crossings!" << std::endl; - //curves didn't cross; default to miter - /*boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { - path_builder.appendNew (*p); - }*/ - //bevel - path_builder.appendNew( endPt ); - } - else - { - //join - std::pair sub1 = bzr1.subdivide(cross[0].ta); - std::pair sub2 = bzr2.subdivide(cross[0].tb); - - //@TODO joins have a strange tendency to cross themselves twice. Check this. - - //sections commented out are for general stability - path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); - path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); - } - } - else // cross.empty() - { - //probably on the inside of the corner - path_builder.appendNew ( endPt ); - } - } - - /** @brief Converts a path to one half of an outline. - * path_in: The input path to use. (To create the other side use path_in.reverse() ) - * line_width: the line width to use (usually you want to divide this by 2) - * linecap_type: (not used here) the cap to apply. Passed to libvarot. - * miter_limit: the miter parameter - */ - static Geom::Path half_outline(const Geom::Path& path_in, double line_width, ButtType linecap_type, double miter_limit) - { - Geom::PathVector pv = split_at_cusps(path_in); - unsigned m; - Path path_outline = Path(); - Path path_tangent = Path(); - //needed for closing the path - Geom::Point initialPoint; - Geom::Point endPoint; - - //some issues prevented me from using a PathBuilder here - //it seems like PathBuilder::peek() gave me a null reference exception - //and I was unable to get a stack trace on Windows, so had to switch to Linux - //to see what the hell was wrong. :( - //I wasted five hours opening it in IDAPro, VS2012, and GDB Windows - - /*Program received signal SIGSEGV, Segmentation fault. - 0x00000000006539ac in get_curves (this=0x0) - at /usr/include/c++/4.6/bits/locale_facets.h:1077 - 1077 { return __c; } - */ - - Geom::Path path_builder = Geom::Path(); - Geom::PathVector * pathvec; - - //load the first portion in before the loop starts - { - path_outline = Path(); - path_outline.LoadPath(pv[0], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - //now half of first cusp has been loaded - - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - //instead of array accessing twice, dereferencing used for clarity - initialPoint = (*pathvec)[0].initialPoint(); - - path_builder.start(initialPoint); - path_builder.append( (*pathvec)[0] ); - - path_outline = Path(); - path_outline.LoadPath(pv[1], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - path_tangent = Path(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - - path_builder.append( (*pathvec)[0] ); - - //always set pointers null after deleting - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - for (m = 2; m < pv.size(); m++) - { - path_outline = Path(); - path_outline.LoadPath(pv[m], Geom::Affine(), false, false); - path_outline.OutsideOutline(&path_tangent, line_width / 2, join_straight, linecap_type, 10); - - delete pathvec; pathvec = NULL; - pathvec = path_tangent.MakePathVector(); - - Geom::Curve *cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve *cbc2 = (*pathvec)[0][0].duplicate(); - - reflect_curves(path_builder, cbc1, cbc2, (*pathvec)[0].initialPoint(), miter_limit ); - path_builder.append( (*pathvec)[0] ); - - delete pathvec; pathvec = NULL; - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - - return path_builder; - } - - static Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim) - { - Path p = Path(); - Path outlinepath = Path(); - for (unsigned i = 0; i < path_in.size(); i++) - { - p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); - } - - Geom::PathVector path_out; - for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) - { - if (path_in[lmnop].size() > 1) - { - Geom::Path p_init; - Geom::Path p_rev; - Geom::PathBuilder pb = Geom::PathBuilder(); - - if ( !path_in[lmnop].closed() ) - { - p_init = Outline::half_outline( path_in[lmnop], -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline( path_in[lmnop].reverse(), -line_width, butt, - miter_lim ); - - pb.moveTo(p_init.initialPoint() ); - pb.append(p_init); - - //cap - if (butt == butt_straight) { - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } - - pb.append(p_rev); - - if (butt == butt_straight) { - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); - //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); - - pb.lineTo(p_init.initialPoint() ); - } - } - else - { - //final join - //refer to half_outline for documentation - Geom::Path p_almost = path_in[lmnop]; - p_almost.appendNew ( path_in[lmnop].initialPoint() ); - p_init = Outline::half_outline( p_almost, -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline( p_almost.reverse(), -line_width, butt, - miter_lim ); - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - - //this is a kludge, because I can't find how to make this work properly - bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), - path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == - (path_in[lmnop] [path_in[lmnop].size()].length())); - - p_almost = p_init; - if (lastIsLinear) - { - p_almost.erase_last(); p_almost.erase_last(); - } - - //outside test - Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); - Geom::Curve* cbc2 = p_almost[0].duplicate(); - - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //this is the outside path - - //reuse the old one - p_init = p_almost; - Outline::reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside, carry on :-) - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - - p_almost = p_rev; - if (lastIsLinear) - { - p_almost.erase(p_almost.begin() ); - p_almost.erase(p_almost.begin() ); - } - - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - - cbc1 = p_almost[p_almost.size() - 1].duplicate(); - cbc2 = p_almost[0].duplicate(); - - cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //outside path - - p_init = p_almost; - reflect_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - //pb.closePath(); - pb.flush(); - Geom::PathVector pv_np = pb.peek(); - //hack - for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) - { - path_out.push_back( pv_np[abcd] ); - } - } - else - { - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - p.Outline(&outlinepath, line_width / 2, join, butt, miter_lim); - std::vector *pv_p = outlinepath.MakePathVector(); - //hack - path_out.push_back( (*pv_p)[0].reverse() ); - delete pv_p; - } - } - return path_out; - } - static Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim) - { - Path p = Path(); - Path outlinepath = Path(); - for (unsigned i = 0; i < path_in.size(); i++) - { - p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); - } - - Geom::PathVector path_out; - for (unsigned lmnop = 0; lmnop < path_in.size(); lmnop++) - { - if (path_in[lmnop].size() > 1) - { - Geom::Path p_init; - Geom::Path p_rev; - Geom::PathBuilder pb = Geom::PathBuilder(); - - if ( !path_in[lmnop].closed() ) - { - p_init = Outline::half_outline_extrp( path_in[lmnop], -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline_extrp( path_in[lmnop].reverse(), -line_width, butt, - miter_lim ); - - pb.moveTo(p_init.initialPoint() ); - pb.append(p_init); - - //cap - if (butt == butt_straight) { - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_rev.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - pb.lineTo(p_rev.initialPoint() ); - } - - pb.append(p_rev); - - if (butt == butt_straight) { - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_round) { - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, p_init.initialPoint() ); - } else if (butt == butt_square) { - //don't know what to do - pb.lineTo(p_init.initialPoint() ); - } else if (butt == butt_pointy) { - //don't know what to do - //Geom::Point end_deriv = Geom::unitTangentAt( Geom::reverse(path_in[lmnop].toPwSb()[path_in[lmnop].size()]), 0); - //double radius = 0.5 * Geom::distance(path_in[lmnop].finalPoint(), p_rev.initialPoint()); - - pb.lineTo(p_init.initialPoint() ); - } - } - else - { - //final join - //refer to half_outline for documentation - Geom::Path p_almost = path_in[lmnop]; - p_almost.appendNew ( path_in[lmnop].initialPoint() ); - p_init = Outline::half_outline_extrp( p_almost, -line_width, butt, - miter_lim ); - p_rev = Outline::half_outline_extrp( p_almost.reverse(), -line_width, butt, - miter_lim ); - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - - //this is a kludge, because I can't find how to make this work properly - bool lastIsLinear = ( (Geom::distance(path_in[lmnop].finalPoint(), - path_in[lmnop] [path_in[lmnop].size() - 1].finalPoint())) == - (path_in[lmnop] [path_in[lmnop].size()].length())); - - p_almost = p_init; - if (lastIsLinear) - { - p_almost.erase_last(); p_almost.erase_last(); - } - - //outside test - Geom::Curve* cbc1 = p_almost[p_almost.size() - 1].duplicate(); - Geom::Curve* cbc2 = p_almost[0].duplicate(); - - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //this is the outside path - - //reuse the old one - p_init = p_almost; - Outline::extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside, carry on :-) - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - - p_almost = p_rev; - if (lastIsLinear) - { - p_almost.erase(p_almost.begin() ); - p_almost.erase(p_almost.begin() ); - } - - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - - cbc1 = p_almost[p_almost.size() - 1].duplicate(); - cbc2 = p_almost[0].duplicate(); - - cross = Geom::crossings(*cbc1, *cbc2); - - if (cross.empty()) - { - //outside path - - p_init = p_almost; - extrapolate_curves(p_init, cbc1, cbc2, p_almost.initialPoint(), miter_lim ); - pb.moveTo(p_init.initialPoint()); pb.append(p_init); - } - else - { - //inside - pb.moveTo(p_almost.initialPoint()); pb.append(p_almost); - } - delete cbc1; delete cbc2; cbc1 = cbc2 = NULL; - } - //pb.closePath(); - pb.flush(); - Geom::PathVector pv_np = pb.peek(); - //hack - for (unsigned abcd = 0; abcd < pv_np.size(); abcd++) - { - path_out.push_back( pv_np[abcd] ); - } - } - else - { - p.LoadPath(path_in[lmnop], Geom::Affine(), false, false); - p.Outline(&outlinepath, line_width / 2, join_pointy, butt, miter_lim); - std::vector *pv_p = outlinepath.MakePathVector(); - //hack - path_out.push_back( (*pv_p)[0].reverse() ); - delete pv_p; - } - } - return path_out; - } - - -} // namespace Outline - -/* - 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:encoding=utf-8:textwidth=99 : +#ifndef _SEEN_PATH_OUTLINE_H +#define _SEEN_PATH_OUTLINE_H + +#include +#include + +enum LineJoinType { + LINEJOIN_STRAIGHT, + LINEJOIN_ROUND, + LINEJOIN_POINTY, + LINEJOIN_REFLECTED, + LINEJOIN_EXTRAPOLATED +}; + +namespace Outline +{ + unsigned bezierOrder (const Geom::Curve* curve_in); + std::vector PathVectorOutline(std::vector const & path_in, double line_width, ButtType linecap_type, + join_typ linejoin_type, double miter_limit); + + Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim); + Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim); +} + +#endif // _SEEN_PATH_OUTLINE_H -- cgit v1.2.3 From 7d6a2eac770b159a51183add6917eaec36729d80 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 23 Mar 2014 17:25:49 -0400 Subject: tiny bugfix for Taper Strokes (bzr r13090.1.30) --- src/live_effects/lpe-taperstroke.cpp | 54 ++++++++++++++++++++------------ src/live_effects/pathoutlineprovider.cpp | 33 +++++++++++++++++++ src/live_effects/pathoutlineprovider.h | 1 + 3 files changed, 68 insertions(+), 20 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index a862417d7..0e709f3ac 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -324,40 +324,54 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) if (true) { Geom::PathVector real_pathv; + Geom::Path real_path; //Construct the pattern (pat_str stands for pattern string) - char pat_str[200]; - sprintf(pat_str, "M 1,0 1,1 C %5.5f,1 0,0.5 0,0.5 0,0.5 %5.5f,0 1,0 Z", 1 - (double)smoothing, 1 - (double)smoothing); - Geom::PathVector pat_vec = sp_svg_read_pathv(pat_str); + std::stringstream pat_str; + pat_str << "M 1,0 1,1 C " << 1 - (double)smoothing << ",1 0,0.5 0,0.5 0,0.5 " << 1 - double(smoothing) << ",0 1,0"; + + Geom::PathVector pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); Geom::Piecewise > pwd2; pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], line_width)); - real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0]); + Geom::Path throwaway_path = path_from_piecewise(pwd2, 0.001)[0].reverse(); + throwaway_path.erase_last(); - Geom::PathVector sht_path; - sht_path.push_back(pathv_out[1]); - sht_path = Outline::PathVectorOutline(sht_path, line_width, butt_straight, static_cast(join_type.get_value()) , miter_limit); + real_path.append(throwaway_path); //wtf - real_pathv.push_back(sht_path[0]); + throwaway_path = Outline::PathOutsideOutline(pathv_out[1], + line_width, static_cast(join_type.get_value()), miter_limit); + + throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path); - char pat_str_1[200]; - sprintf(pat_str_1, "M 0,0 0,1 C %5.5f,1 1,0.5 1,0.5 1,0.5 %5.5f,0 0,0 Z", (double)smoothing, (double)smoothing); - pat_vec = sp_svg_read_pathv(pat_str_1); + std::stringstream pat_str_1; + pat_str_1 << "M 0,0 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; + pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); pwd2 = Geom::Piecewise > (); pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], line_width)); - real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0].reverse()); - //clever union - //Geom::Shape shape1 = Geom::sanitize(Geom::PathVector(1, real_pathv[0])); - //Geom::Shape shape2 = Geom::sanitize(Geom::PathVector(1, real_pathv[1])); - //Geom::Shape shape3 = Geom::boolop(shape1, shape2, Geom::BOOLOP_UNION); + throwaway_path = Geom::Path(); + throwaway_path = path_from_piecewise(pwd2, 0.001)[0]; + throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path); + + throwaway_path = Geom::Path(); + throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), + line_width, static_cast(join_type.get_value()), miter_limit); + + //throwaway_path = throwaway_path.reverse(); + throwaway_path.setInitial(real_path.finalPoint()); + + real_path.append(throwaway_path); + //real_path.close(); + + real_pathv.push_back(real_path); - //shape2 = Geom::sanitize(Geom::PathVector(1, real_pathv[2])); - //shape1 = Geom::boolop(shape3, shape2, Geom::BOOLOP_UNION); + //real_pathv.push_back(path_from_piecewise(pwd2, 0.001)[0].reverse()); - //real_pathv = Geom::desanitize(shape1); return real_pathv; } @@ -383,7 +397,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa trimmed_start.append(path_in[0] [i]); } - #define OVERLAP (0.001 / (line_width < 1 ? 1 : line_width)) + #define OVERLAP 0 /*(0.001 / (line_width < 1 ? 1 : line_width))*/ trimmed_start.append(*subdivide_at(curve_start, (attach_start - loc) + OVERLAP, true)); curve_start = subdivide_at(curve_start, attach_start - loc, false); diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index e62f516c9..302756c7c 100755 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -825,6 +825,39 @@ Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line #undef miter_lim return path_out; } +Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit) +{ + + #define miter_lim fabs(line_width * miter_limit) + + Geom::Path path_out; + + if (linejoin_type <= LINEJOIN_POINTY || path_in.size() <= 1) { + + Geom::PathVector * pathvec; + + Path path_tangent = Path(); + Path path_outline = Path(); + path_outline.LoadPath(path_in, Geom::Affine(), false, false); + path_outline.OutsideOutline(&path_tangent, line_width / 2, static_cast(linejoin_type), butt_straight, miter_lim); + + pathvec = path_tangent.MakePathVector(); + path_out = pathvec[0]/* deref pointer */[0]/*actual object ref*/; + delete pathvec; + return path_out; + } + else if (linejoin_type == LINEJOIN_REFLECTED) { + //reflected half outline + Geom::PathVector pathvec; pathvec.push_back(path_in); + path_out = half_outline(path_in, line_width, butt_straight, miter_lim); + return path_out; + } + else if (linejoin_type == LINEJOIN_EXTRAPOLATED) { + path_out = half_outline_extrp(path_in, line_width, butt_straight, miter_lim); + return path_out; + } + return path_out; +} } // namespace Outline diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h index 1a363c35b..4133f47c2 100644 --- a/src/live_effects/pathoutlineprovider.h +++ b/src/live_effects/pathoutlineprovider.h @@ -20,6 +20,7 @@ namespace Outline Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, JoinType join, ButtType butt, double miter_lim); Geom::PathVector outlinePath_extr(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim); + Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); } #endif // _SEEN_PATH_OUTLINE_H -- cgit v1.2.3 From f7943d80067732ec4a0565077b26b32562a150d3 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 27 Mar 2014 01:31:58 +0100 Subject: Adding cout << output to check bug in Geom::are_near (bzr r11950.1.314) --- src/live_effects/lpe-bspline.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index c19eda8f0..df98f0897 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -39,6 +39,7 @@ #include "inkscape.h" #include "desktop.h" +#include using Inkscape::DocumentUndo; @@ -347,14 +348,24 @@ LPEBSpline::changeWeight(double weightValue) bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint){ + using Geom::X; + using Geom::Y; + std::cout << "\n"; + std::cout << ":: Executed -> nodeIsSelected(Geom::Point nodePoint) ::\n"; + std::cout << "Want to check the argument -nodePoint- is in points vector \n"; + std::cout << "nodePoint::X=" << nodePoint[X] << ";Y=" << nodePoint[Y] << "\n"; + std::cout << "Checking points std::vector\n"; if(points.size() > 0){ - for(std::vector::iterator i = points.begin(); i != points.end();){ - Geom::Point p = static_cast(*i); + for(std::vector::iterator i = points.begin(); i != points.end(); ++i){ + Geom::Point p = *i; + std::cout << "p::X=" << p[X] << ";Y=" << p[Y] << "\n"; + std::cout << "Are near? "; if(Geom::are_near(p, nodePoint)){ + std::cout << "YES\n"; return true; - points.erase(i); + }else{ + std::cout << "NO\n"; } - i++; } } return false; @@ -367,17 +378,21 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) using Geom::Y; SPDesktop *desktop = inkscape_active_desktop(); if(INK_IS_NODE_TOOL(desktop->event_context)){ + std::cout << ":: Start -> doBSplineFromWidget(SPCurve * curve, double weightValue) ::\n"; + std::cout << "Inserting nodes selected into std::vector 'points'\n"; Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); points.clear(); std::vector::iterator pbegin; for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i){ if ((*i)->selected()) { - Inkscape::UI::Node *n = static_cast(*i); + Inkscape::UI::Node *n = dynamic_cast(*i); pbegin = points.begin(); points.insert(pbegin,desktop->doc2dt(n->position())); + std::cout << "inserting point::X=" << desktop->doc2dt(n->position())[X] << ";Y=" << desktop->doc2dt(n->position())[Y] << "\n"; } } + std::cout << "End inserting selected nodes into vector\n"; } //bool hasNodesSelected = LPEBspline::hasNodesSelected(); if(curve->get_segment_count() < 2) @@ -629,6 +644,7 @@ LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) curve->append(nCurve,false); nCurve->reset(); delete nCurve; + std::cout << ":: End ::\n"; } } -- cgit v1.2.3 From f928fc556c8d7824dd920171b5de534cee4fe4ad Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 26 Mar 2014 21:32:07 -0400 Subject: Small performance and bug fixes (bzr r13090.1.33) --- src/live_effects/effect.cpp | 2 +- src/live_effects/lpe-taperstroke.cpp | 169 +++++++++++++++++++++-------------- 2 files changed, 101 insertions(+), 70 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index d6840e5b8..337fe631f 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,7 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -//#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects +#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects #ifdef HAVE_CONFIG_H # include "config.h" diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 91b8fd7bc..4ae1de923 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -232,9 +232,9 @@ Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_toler return path_out; } -Geom::Curve * subdivide_at(const Geom::Curve* curve_in, Geom::Coord time, bool first); Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double width); + Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) { Geom::Path first_cusp = return_at_first_cusp(path_in[0]); @@ -255,21 +255,21 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) } //don't ever let it be zero - if (attach_start <= 0) { + if (attach_start <= 0.00000001) { attach_start.param_set_value( 0.00000001 ); + zeroStart = true; } - if (attach_end <= 0) { + if (attach_end <= 0.00000001) { attach_end.param_set_value( 0.00000001 ); + zeroEnd = true; } //don't let it be integer if (double(unsigned(attach_start)) == attach_start) { attach_start.param_set_value(attach_start - 0.00000001); - zeroStart = true; } if (double(unsigned(attach_end)) == attach_end) { - attach_end.param_set_value(attach_end - 0.00000001); - zeroStart = true; + attach_end.param_set_value(attach_end - 0.00000001); } unsigned allowed_start = first_cusp.size(); @@ -302,14 +302,11 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) if (!zeroStart) { //Construct the pattern (pat_str stands for pattern string) (yes, this is easier, trust me) std::stringstream pat_str; - pat_str << "M 1,0 1,1 C " << 1 - (double)smoothing << ",1 0,0.5 0,0.5 0,0.5 " << 1 - double(smoothing) << ",0 1,0"; + pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; - pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); - - pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], line_width)); - - throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0].reverse(); - throwaway_path.erase_last(); //wtf + pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], line_width)); + throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; real_path.append(throwaway_path); } @@ -317,8 +314,12 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) throwaway_path = Outline::PathOutsideOutline(pathv_out[1], line_width, static_cast(join_type.get_value()), miter_limit); - throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path); + if (!zeroStart) { + throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path); + } else { + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + } if (!zeroEnd) { //append the ending taper @@ -336,10 +337,13 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //append the inside outline of the path (against direction) throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), line_width, static_cast(join_type.get_value()), miter_limit); - - throwaway_path.setInitial(real_path.finalPoint()); - - real_path.append(throwaway_path); + + if (!zeroEnd) { + throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path); + } else { + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + } real_path.close(); real_pathv.push_back(real_path); @@ -355,7 +359,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa //do subdivision and get out unsigned loc = (unsigned)attach_start; Geom::Curve * curve_start = path_in[0] [loc].duplicate(); - + std::vector pathv_out; Geom::Path path_out = Geom::Path(); @@ -365,25 +369,69 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa for (unsigned i = 0; i < loc; i++) { trimmed_start.append(path_in[0] [i]); } - - - trimmed_start.append(*subdivide_at(curve_start, (attach_start - loc), true)); - curve_start = subdivide_at(curve_start, attach_start - loc, false); + + + //this is pretty annoying + //previously I wrote a function for this but it wasted a lot of time + //so I optimized it back into here. + unsigned order = Outline::bezierOrder(curve_start); + switch (order) { + case 3: { + Geom::CubicBezier *cb = static_cast(curve_start); + std::pair cb_pair = cb->subdivide((attach_start - loc)); + trimmed_start.append(cb_pair.first); curve_start = cb_pair.second.duplicate(); //goes out of scope + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_start); + std::pair qb_pair = qb->subdivide((attach_start - loc)); + trimmed_start.append(qb_pair.first); curve_start = qb_pair.second.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide((attach_start - loc)); + trimmed_start.append(lb_pair.first); curve_start = lb_pair.second.duplicate(); + break; + } + } //special case: path is one segment long //special case: what if the two knots occupy the same segment? if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) { Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); + //it is just a dumb segment //we have to do some shifting here because the value changed when we reduced the length //of the previous segment. - trimmed_end.append(*subdivide_at(curve_start, t, false)); + + order = Outline::bezierOrder(curve_start); + switch (order) { + case 3: { + Geom::CubicBezier *cb = static_cast(curve_start); + std::pair cb_pair = cb->subdivide(t); + trimmed_end.append(cb_pair.second); curve_start = cb_pair.first.duplicate(); + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_start); + std::pair qb_pair = qb->subdivide(t); + trimmed_end.append(qb_pair.second); curve_start = qb_pair.first.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); + trimmed_end.append(lb_pair.second); curve_start = lb_pair.first.duplicate(); + break; + } + } + for (unsigned j = (size - attach_end) + 1; j < size; j++) { trimmed_end.append(path_in[0] [j]); } - curve_start = subdivide_at(curve_start, t, true); path_out.append(*curve_start); pathv_out.push_back(trimmed_start); pathv_out.push_back(path_out); @@ -406,9 +454,28 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa Geom::Curve * curve_end = path_in[0] [loc].duplicate(); Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); - - trimmed_end.append(*subdivide_at(curve_end, t, false)); - curve_end = subdivide_at(curve_end, t, true); + + order = Outline::bezierOrder(curve_end); + switch (order) { + case 3: { + Geom::CubicBezier *cb = static_cast(curve_end); + std::pair cb_pair = cb->subdivide(t); + trimmed_end.append(cb_pair.second); curve_end = cb_pair.first.duplicate(); + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_end); + std::pair qb_pair = qb->subdivide(t); + trimmed_end.append(qb_pair.second); curve_end = qb_pair.first.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_end); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); + trimmed_end.append(lb_pair.second); curve_end = lb_pair.first.duplicate(); + break; + } + } for (unsigned j = (size - attach_end) + 1; j < size; j++) { trimmed_end.append(path_in[0] [j]); @@ -424,44 +491,6 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa return pathv_out; } -Geom::Curve * subdivide_at(const Geom::Curve* curve_in, Geom::Coord time, bool first) -{ - //the only reason for this function is the lack of a subdivide function in the Curve class. - //you have to cast to Beziers to be able to use subdivide(t) - unsigned order = Outline::bezierOrder(curve_in); - Geom::Curve* curve_out = curve_in->duplicate(); - switch (order) - { - //these need to be scoped because of the variable 'c' - case 3: - { - Geom::CubicBezier c = first ? (dynamic_cast (curve_out))->subdivide(time).first : - (dynamic_cast (curve_out))->subdivide(time).second; - if (curve_out) delete curve_out; - curve_out = c.duplicate(); - break; - } - case 2: - { - Geom::QuadraticBezier c = first ? (dynamic_cast(curve_out))->subdivide(time).first : - (dynamic_cast(curve_out))->subdivide(time).second; - if (curve_out) delete curve_out; - curve_out = c.duplicate(); - break; - } - case 1: - { - Geom::BezierCurveN<1> c = first ? (dynamic_cast* >(curve_out))->subdivide(time).first : - (dynamic_cast* >(curve_out))->subdivide(time).second; - if (curve_out) delete curve_out; - curve_out = c.duplicate(); - break; - } - } - return curve_out; -} - - //most of the below code is verbatim from Pattern Along Path. However, it needed a little //tweaking to get it to work right in this case. @@ -587,8 +616,9 @@ namespace TpS { Piecewise > pwd2; Geom::Path p_in = return_at_first_cusp(pathv[0]); pwd2.concat(p_in.toPwSb()); + std::vector > > pwd_vec = split_at_discontinuities(pwd2); - double t0 = nearest_point(s, pwd2); + double t0 = nearest_point(s, pwd_vec[0]); lpe->attach_start.param_set_value(t0); // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. @@ -607,8 +637,9 @@ namespace TpS { Piecewise > pwd2; Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); pwd2.concat(p_in.toPwSb()); + std::vector > > pwd_vec = split_at_discontinuities(pwd2); - double t0 = nearest_point(s, pwd2); + double t0 = nearest_point(s, pwd_vec[0]); lpe->attach_end.param_set_value(t0); // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. -- cgit v1.2.3 From 8a082e274bc322596c217bbe7770904a3cb50cc2 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 29 Mar 2014 15:28:44 -0400 Subject: Fix build errors and a few small bugs (bzr r13090.1.36) --- src/live_effects/lpe-taperstroke.cpp | 4 ++-- .../parameter/powerstrokepointarray.cpp | 2 +- src/live_effects/pathoutlineprovider.cpp | 25 ++++++++++++++++++---- 3 files changed, 24 insertions(+), 7 deletions(-) mode change 100644 => 100755 src/live_effects/lpe-taperstroke.cpp (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp old mode 100644 new mode 100755 index 8e6edfa2f..0e9752d31 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -279,10 +279,10 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //don't let it be integer if (double(unsigned(attach_start)) == attach_start) { - attach_start.param_set_value(attach_start - 0.00000001); + attach_start.param_set_value(attach_start - 0.00001); } if (double(unsigned(attach_end)) == attach_end) { - attach_end.param_set_value(attach_end - 0.00000001); + attach_end.param_set_value(attach_end - 0.00001); } unsigned allowed_start = first_cusp.size(); diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 7fa837689..4ed8998fa 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -202,7 +202,7 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const void PowerStrokePointArrayParamKnotHolderEntity::knot_set_offset(Geom::Point offset) { _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y() / 2); - this->parent_holder->knot_ungrabbed_handler(this->knot); + this->parent_holder->knot_ungrabbed_handler(this->knot, 0); } void diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index a5a7a044f..2a0da05b4 100755 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -220,8 +220,8 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, bool outside = false) { - - if ( outside ) { + bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); + if ( outside && !lineProblem ) { Geom::Path pth; pth.append(*cbc1); @@ -273,9 +273,26 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } path_builder.appendNew (endPt); } - } else { + } + if ( outside && lineProblem ) { + Geom::Path pth; + pth.append(*cbc1); + Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); + pth = Geom::Path(); + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + boost::optional p = intersection_point (cbc1->finalPoint(), tang1, + cbc2->initialPoint(), tang2); + if (p) + { + path_builder.appendNew (*p); + } path_builder.appendNew (endPt); - } + } + if ( !outside ) { + path_builder.appendNew (endPt); + } } void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, bool outside = false) -- cgit v1.2.3 From e667170b1473faccbeabece0cef7d24ebf15bef9 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 29 Mar 2014 20:33:36 -0400 Subject: Minor fixes (bzr r13090.1.37) --- src/live_effects/lpe-taperstroke.cpp | 4 +- src/live_effects/pathoutlineprovider.cpp | 79 +++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 18 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 0e9752d31..b4e43209d 100755 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -352,8 +352,8 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) -fabs(line_width), static_cast(join_type.get_value()), miter_limit); if (!zeroEnd) { - throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path); + //throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); } else { real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); } diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index 2a0da05b4..6a47285a0 100755 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -1,5 +1,5 @@ #include "pathoutlineprovider.h" - +#include "livarot/path-description.h" #include <2geom/angle.h> #include <2geom/path.h> #include <2geom/circle.h> @@ -7,6 +7,7 @@ #include <2geom/shape.h> #include <2geom/transforms.h> #include <2geom/path-sink.h> +#include namespace Geom { @@ -163,7 +164,10 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) Geom::Point end_point; //assert(cbc1.finalPoint() == cbc2.initialPoint()); + //short circuiting? if (cbc1.finalPoint() != cbc2.initialPoint()) { + printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n" + "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); return false; } switch (order) @@ -218,7 +222,8 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) return false; } -void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, bool outside = false) +void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, + double miter_limit, double line_width, bool outside = false) { bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); if ( outside && !lineProblem ) { @@ -269,7 +274,13 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve cbc2->initialPoint(), tang2); if (p) { - path_builder.appendNew (*p); + //check size of miter + Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; + Geom::Coord len = distance(*p, point_on_path); + if (len <= miter_limit) { + // miter OK + path_builder.appendNew (*p); + } } path_builder.appendNew (endPt); } @@ -286,7 +297,13 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve cbc2->initialPoint(), tang2); if (p) { - path_builder.appendNew (*p); + //check size of miter + Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; + Geom::Coord len = distance(*p, point_on_path); + if (len <= miter_limit) { + // miter OK + path_builder.appendNew (*p); + } } path_builder.appendNew (endPt); } @@ -295,7 +312,8 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } -void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, bool outside = false) +void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, + double miter_limit, double line_width, bool outside = false) { //the most important work for the reflected join is done here @@ -332,7 +350,13 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb cbc2->initialPoint(), tang2); if (p) { - path_builder.appendNew (*p); + //check size of miter + Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; + Geom::Coord len = distance(*p, point_on_path); + if (len <= miter_limit) { + // miter OK + path_builder.appendNew (*p); + } } //bevel path_builder.appendNew( endPt ); @@ -395,10 +419,10 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); //do the reflection/extrapolation: - if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, - outside_angle ( pv[u - 1] [pv[u - 1].size()], pv[u] [0] )); } - else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, - outside_angle ( pv[u - 1] [pv[u - 1].size()], pv[u] [0] )); } + if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } + else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } } path_builder.append( (*path_vec)[0] ); @@ -420,9 +444,9 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); //do the reflection/extrapolation: - if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, + if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); } - else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, + else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); } //Now we can store it. @@ -449,10 +473,33 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, //since you've made it this far, hopefully all this is obvious :P Geom::Path with_direction; Geom::Path against_direction; - - with_direction = Outline::doAdvHalfOutline( path_in[i], -line_width, miter_lim, extrapolate ); - against_direction = Outline::doAdvHalfOutline( path_in[i].reverse(), -line_width, extrapolate ); - + if ( !path_in[i].closed() ) { + with_direction = Outline::doAdvHalfOutline( path_in[i], -line_width, miter_lim, extrapolate ); + against_direction = Outline::doAdvHalfOutline( path_in[i].reverse(), -line_width, miter_lim, extrapolate ); + } else { + //Geom::Path absolutely refuses to do what I want with these + Geom::Path newPath = path_in[i]; + newPath.close(false); + Geom::Piecewise > pwd2 = newPath.toPwSb(); + newPath = Geom::path_from_piecewise(pwd2, 0.01)[0]; + //fuk this + with_direction = Outline::doAdvHalfOutline( newPath, -line_width, miter_lim, extrapolate ); + against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); + + /*if (dynamic_cast *>(&newPath[newPath.size()])) { + //delete the 'Z' + newPath.erase_last(); + newPath.append(path_in[i][path_in[i].size() - 1]); + newPath.appendNew(newPath.initialPoint()); + newPath.erase_last(); + } else { + //delete the 'Z' + newPath.erase_last(); + newPath.append(path_in[i][path_in[i].size() - 1]); + newPath.appendNew(newPath.initialPoint()); + newPath.erase_last(); + }*/ + } Geom::PathBuilder pb; //add in the...do I really need to say this? -- cgit v1.2.3 From 9d5889926c9752867b244e9247843dd012cefdda Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 30 Mar 2014 23:53:17 +0200 Subject: clang-format bspline lpe files (bzr r11950.1.316) --- src/live_effects/lpe-bspline.cpp | 1182 ++++++++++++++++++++------------------ src/live_effects/lpe-bspline.h | 39 +- 2 files changed, 636 insertions(+), 585 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index df98f0897..09e71d833 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -2,7 +2,7 @@ /* * Released under GNU GPL, read the file 'COPYING' for more information */ - + #include #include #include @@ -46,606 +46,658 @@ using Inkscape::DocumentUndo; namespace Inkscape { namespace LivePathEffect { - - -LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - // initialise your parameters here: - //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, Geom::Point(100,100)), - steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), - ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), - onlySelected(_("Change only selected nodes:"), _("Change only selected nodes"), "onlySelected", &wr, this, false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 0.3334) -{ - registerParameter( dynamic_cast(&ignoreCusp) ); - registerParameter( dynamic_cast(&onlySelected) ); - registerParameter( dynamic_cast(&weight) ); - registerParameter( dynamic_cast(&steps) ); - weight.param_set_range(0.0000, 1); - weight.param_set_increments(0.1, 0.1); - weight.param_set_digits(4); - steps.param_set_range(1, 10); - steps.param_set_increments(1, 1); - steps.param_set_digits(0); +LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + // initialise your parameters here: + //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, + //Geom::Point(100,100)), + steps(_("Steps whith CTRL:"), + _("Change number of steps whith CTRL pressed"), "steps", &wr, this, + 2), + ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), + "ignoreCusp", &wr, this, true), + onlySelected(_("Change only selected nodes:"), + _("Change only selected nodes"), "onlySelected", &wr, this, + false), + weight(_("Change weight:"), _("Change weight of the effect"), "weight", + &wr, this, 0.3334) { + registerParameter(dynamic_cast(&ignoreCusp)); + registerParameter(dynamic_cast(&onlySelected)); + registerParameter(dynamic_cast(&weight)); + registerParameter(dynamic_cast(&steps)); + weight.param_set_range(0.0000, 1); + weight.param_set_increments(0.1, 0.1); + weight.param_set_digits(4); + steps.param_set_range(1, 10); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); } -LPEBSpline::~LPEBSpline() -{ -} +LPEBSpline::~LPEBSpline() {} -void -LPEBSpline::createAndApply(const char* name, SPDocument *doc, SPItem *item) -{ - if (!SP_IS_SHAPE(item)) { - g_warning("LPE BSpline can only be applied to shapes (not groups)."); - }else{ - // Path effect definition - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); - repr->setAttribute("effect", name); +void LPEBSpline::createAndApply(const char *name, SPDocument *doc, + SPItem *item) { + if (!SP_IS_SHAPE(item)) { + g_warning("LPE BSpline can only be applied to shapes (not groups)."); + } else { + // Path effect definition + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); + repr->setAttribute("effect", name); - doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to and assigns the 'id' attribute - const gchar * repr_id = repr->attribute("id"); - Inkscape::GC::release(repr); + doc->getDefs()->getRepr() + ->addChild(repr, NULL); // adds to and assigns the 'id' attribute + const gchar *repr_id = repr->attribute("id"); + Inkscape::GC::release(repr); - gchar *href = g_strdup_printf("#%s", repr_id); - SP_LPE_ITEM(item)->addPathEffect( href, true); - g_free(href); - } + gchar *href = g_strdup_printf("#%s", repr_id); + SP_LPE_ITEM(item)->addPathEffect(href, true); + g_free(href); + } } -void -LPEBSpline::doEffect(SPCurve * curve) -{ - if(curve->get_segment_count() < 2) - return; - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - curve->reset(); +void LPEBSpline::doEffect(SPCurve *curve) { + if (curve->get_segment_count() < 2) + return; + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo - 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 - - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point previousNode(0,0); - Geom::Point node(0,0); - Geom::Point pointAt1(0,0); - Geom::Point pointAt2(0,0); - Geom::Point nextPointAt1(0,0); - Geom::Point nextPointAt2(0,0); - Geom::Point nextPointAt3(0,0); - Geom::D2< Geom::SBasis > SBasisIn; - Geom::D2< Geom::SBasis > SBasisOut; - Geom::D2< Geom::SBasis > SBasisHelper; - Geom::CubicBezier const *cubic = NULL; - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo BSPline - nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while ( curve_it2 != curve_endit ) - { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - SPCurve * in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - if(cubic){ - SBasisIn = in->first_segment()->toSBasis(); - pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1],*in->first_segment())); - pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2],*in->first_segment())); - }else{ - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - in->reset(); - delete in; - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - SPCurve * out = new SPCurve(); - out->moveto(curve_it2->initialPoint()); - out->lineto(curve_it2->finalPoint()); - cubic = dynamic_cast(&*curve_it2); - if(cubic){ - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1],*out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2],*out->first_segment()));; - nextPointAt3 = out->first_segment()->finalPoint(); - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente de - //los manejadores de la curva - SPCurve *lineHelper = new SPCurve(); - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de principio de curva - previousNode = node; - //Y este hará de final de curva - node = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, node); - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - //Si está cerrada la curva, la cerramos sobre el valor guardado previamente - //Si no finalizamos en el punto final - Geom::Point startNode(0,0); - if (path_it->closed()) { - SPCurve * start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - Geom::D2< Geom::SBasis > SBasisStart = start->first_segment()->toSBasis(); - SPCurve *lineHelper = new SPCurve(); - cubic = dynamic_cast(&*path_it->begin()); - if(cubic){ - lineHelper->moveto(SBasisStart.valueAt(Geom::nearest_point((*cubic)[1],*start->first_segment()))); - }else{ - lineHelper->moveto(start->first_segment()->initialPoint()); - } - start->reset(); - delete start; + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + 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 * end = new SPCurve(); - end->moveto(curve_it1->initialPoint()); - end->lineto(curve_it1->finalPoint()); - Geom::D2< Geom::SBasis > SBasisEnd = end->first_segment()->toSBasis(); - //Geom::BezierCurve const *bezier = dynamic_cast(&*curve_endit); - cubic = dynamic_cast(&*curve_it1); - if(cubic){ - lineHelper->lineto(SBasisEnd.valueAt(Geom::nearest_point((*cubic)[2],*end->first_segment()))); - }else{ - lineHelper->lineto(end->first_segment()->finalPoint()); - } - end->reset(); - delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - startNode = SBasisHelper.valueAt(0.5); - nCurve->curveto(nextPointAt1, nextPointAt2, startNode); - nCurve->move_endpoints(startNode,startNode); - }else{ - SPCurve * start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - startNode = start->first_segment()->initialPoint(); - start->reset(); - delete start; - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(startNode,nextPointAt3); - } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); - } - curve->append(nCurve,false); - nCurve->reset(); - delete nCurve; + 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 + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point previousNode(0, 0); + Geom::Point node(0, 0); + Geom::Point pointAt1(0, 0); + Geom::Point pointAt2(0, 0); + Geom::Point nextPointAt1(0, 0); + Geom::Point nextPointAt2(0, 0); + Geom::Point nextPointAt3(0, 0); + Geom::D2 SBasisIn; + Geom::D2 SBasisOut; + Geom::D2 SBasisHelper; + Geom::CubicBezier const *cubic = NULL; + 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(); + } + } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último + while (curve_it2 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path + //recto de entrada y de salida + SPCurve *in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + SBasisIn = in->first_segment()->toSBasis(); + pointAt1 = SBasisIn.valueAt( + Geom::nearest_point((*cubic)[1], *in->first_segment())); + pointAt2 = SBasisIn.valueAt( + Geom::nearest_point((*cubic)[2], *in->first_segment())); + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + in->reset(); + delete in; + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + SPCurve *out = new SPCurve(); + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + cubic = dynamic_cast(&*curve_it2); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt( + Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt( + Geom::nearest_point((*cubic)[2], *out->first_segment())); + ; + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de + //los manejadores de la curva + SPCurve *lineHelper = new SPCurve(); + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de + //principio de curva + previousNode = node; + //Y este hará de final de curva + node = SBasisHelper.valueAt(0.5); + nCurve->curveto(pointAt1, pointAt2, node); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + //Si está cerrada la curva, la cerramos sobre el valor guardado + //previamente + //Si no finalizamos en el punto final + Geom::Point startNode(0, 0); + if (path_it->closed()) { + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + Geom::D2 SBasisStart = start->first_segment()->toSBasis(); + SPCurve *lineHelper = new SPCurve(); + cubic = dynamic_cast(&*path_it->begin()); + if (cubic) { + lineHelper->moveto(SBasisStart.valueAt( + Geom::nearest_point((*cubic)[1], *start->first_segment()))); + } else { + lineHelper->moveto(start->first_segment()->initialPoint()); + } + start->reset(); + delete start; + + SPCurve *end = new SPCurve(); + end->moveto(curve_it1->initialPoint()); + end->lineto(curve_it1->finalPoint()); + Geom::D2 SBasisEnd = end->first_segment()->toSBasis(); + //Geom::BezierCurve const *bezier = dynamic_cast(&*curve_endit); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + lineHelper->lineto(SBasisEnd.valueAt( + Geom::nearest_point((*cubic)[2], *end->first_segment()))); + } else { + lineHelper->lineto(end->first_segment()->finalPoint()); + } + end->reset(); + delete end; + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + startNode = SBasisHelper.valueAt(0.5); + nCurve->curveto(nextPointAt1, nextPointAt2, startNode); + nCurve->move_endpoints(startNode, startNode); + } else { + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + startNode = start->first_segment()->initialPoint(); + start->reset(); + delete start; + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->move_endpoints(startNode, nextPointAt3); } + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); + } + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; + } } -Gtk::Widget * -LPEBSpline::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()) ); +Gtk::Widget *LPEBSpline::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); - std::vector::iterator it = param_vector.begin(); - 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 == "weight"||param->param_key == "steps"){ - Inkscape::UI::Widget::Scalar * widgRegistered = Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun (*this,&LPEBSpline::toWeight)); - widg = dynamic_cast(widgRegistered); - } - if(param->param_key == "onlySelected"){ - Gtk::CheckButton * widgRegistered = Gtk::manage(dynamic_cast(widg)); - widg = dynamic_cast(widgRegistered); - } - if(param->param_key == "ignoreCusp"){ - Gtk::CheckButton * widgRegistered = Gtk::manage(dynamic_cast(widg)); - widg = dynamic_cast(widgRegistered); - } - 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); - } - } + vbox->set_border_width(5); + std::vector::iterator it = param_vector.begin(); + 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 == "weight" || param->param_key == "steps") { + Inkscape::UI::Widget::Scalar *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed() + .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); + widg = dynamic_cast(widgRegistered); + } + if (param->param_key == "onlySelected") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } + if (param->param_key == "ignoreCusp") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } + 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; + } } - Gtk::Button* defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight 0.3334")))); - defaultWeight->set_alignment(0.0, 0.5); - defaultWeight->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::toDefaultWeight)); - Gtk::Widget* defaultWeightWidget = dynamic_cast(defaultWeight); - vbox->pack_start(*defaultWeightWidget, true, true,2); - Gtk::Button* makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->set_alignment(0.0, 0.5); - makeCusp->signal_clicked().connect(sigc::mem_fun (*this,&LPEBSpline::toMakeCusp)); - Gtk::Widget* makeCuspWidget = dynamic_cast(makeCusp); - vbox->pack_start(*makeCuspWidget, true, true,2); - return dynamic_cast(vbox); -} -void -LPEBSpline::toDefaultWeight(){ - changeWeight(0.3334); + ++it; + } + Gtk::Button *defaultWeight = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight 0.3334")))); + defaultWeight->set_alignment(0.0, 0.5); + defaultWeight->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight)); + Gtk::Widget *defaultWeightWidget = dynamic_cast(defaultWeight); + vbox->pack_start(*defaultWeightWidget, true, true, 2); + Gtk::Button *makeCusp = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); + makeCusp->set_alignment(0.0, 0.5); + makeCusp->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp)); + Gtk::Widget *makeCuspWidget = dynamic_cast(makeCusp); + vbox->pack_start(*makeCuspWidget, true, true, 2); + return dynamic_cast(vbox); } -void -LPEBSpline::toMakeCusp(){ - changeWeight(0.0000); -} +void LPEBSpline::toDefaultWeight() { changeWeight(0.3334); } -void -LPEBSpline::toWeight(){ - changeWeight(weight); -} +void LPEBSpline::toMakeCusp() { changeWeight(0.0000); } -void -LPEBSpline::changeWeight(double weightValue) -{ - SPDesktop *desktop = inkscape_active_desktop(); - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList *items = (GSList *) selection->itemList(); - SPItem *item = (SPItem *)g_slist_nth(items,0)->data; - SPPath *path = SP_PATH(item); - SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve,weightValue); - gchar *str = sp_svg_write_path(curve->get_pathvector()); - path->getRepr()->setAttribute("inkscape:original-d", str); - if(INK_IS_NODE_TOOL(desktop->event_context)){ - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - nt->desktop->updateNow(); - } - g_free(str); - curve->unref(); - desktop->clearWaitingCursor(); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, - _("Modified the weight of the BSpline")); +void LPEBSpline::toWeight() { changeWeight(weight); } + +void LPEBSpline::changeWeight(double weightValue) { + SPDesktop *desktop = inkscape_active_desktop(); + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList *items = (GSList *)selection->itemList(); + SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; + SPPath *path = SP_PATH(item); + SPCurve *curve = path->get_curve_for_edit(); + LPEBSpline::doBSplineFromWidget(curve, weightValue); + gchar *str = sp_svg_write_path(curve->get_pathvector()); + path->getRepr()->setAttribute("inkscape:original-d", str); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); + nt->desktop->updateNow(); + } + g_free(str); + curve->unref(); + desktop->clearWaitingCursor(); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, + _("Modified the weight of the BSpline")); } -bool -LPEBSpline::nodeIsSelected(Geom::Point nodePoint){ - using Geom::X; - using Geom::Y; - std::cout << "\n"; - std::cout << ":: Executed -> nodeIsSelected(Geom::Point nodePoint) ::\n"; - std::cout << "Want to check the argument -nodePoint- is in points vector \n"; - std::cout << "nodePoint::X=" << nodePoint[X] << ";Y=" << nodePoint[Y] << "\n"; - std::cout << "Checking points std::vector\n"; - if(points.size() > 0){ - for(std::vector::iterator i = points.begin(); i != points.end(); ++i){ - Geom::Point p = *i; - std::cout << "p::X=" << p[X] << ";Y=" << p[Y] << "\n"; - std::cout << "Are near? "; - if(Geom::are_near(p, nodePoint)){ - std::cout << "YES\n"; - return true; - }else{ - std::cout << "NO\n"; - } - } +bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) { + using Geom::X; + using Geom::Y; + std::cout << "\n"; + std::cout << ":: Executed -> nodeIsSelected(Geom::Point nodePoint) ::\n"; + std::cout << "Want to check the argument -nodePoint- is in points vector \n"; + std::cout << "nodePoint::X=" << nodePoint[X] << ";Y=" << nodePoint[Y] << "\n"; + std::cout << "Checking points std::vector\n"; + if (points.size() > 0) { + for (std::vector::iterator i = points.begin(); + i != points.end(); ++i) { + Geom::Point p = *i; + std::cout << "p::X=" << p[X] << ";Y=" << p[Y] << "\n"; + std::cout << "Are near? "; + if (Geom::are_near(p, nodePoint)) { + std::cout << "YES\n"; + return true; + } else { + std::cout << "NO\n"; + } } - return false; + } + return false; } -void -LPEBSpline::doBSplineFromWidget(SPCurve * curve, double weightValue) -{ - using Geom::X; - using Geom::Y; - SPDesktop *desktop = inkscape_active_desktop(); - if(INK_IS_NODE_TOOL(desktop->event_context)){ - std::cout << ":: Start -> doBSplineFromWidget(SPCurve * curve, double weightValue) ::\n"; - std::cout << "Inserting nodes selected into std::vector 'points'\n"; - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); - points.clear(); - std::vector::iterator pbegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i){ - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast(*i); - pbegin = points.begin(); - points.insert(pbegin,desktop->doc2dt(n->position())); - std::cout << "inserting point::X=" << desktop->doc2dt(n->position())[X] << ";Y=" << desktop->doc2dt(n->position())[Y] << "\n"; - } - } - std::cout << "End inserting selected nodes into vector\n"; +void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { + using Geom::X; + using Geom::Y; + SPDesktop *desktop = inkscape_active_desktop(); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + std::cout << ":: Start -> doBSplineFromWidget(SPCurve * curve, double " + "weightValue) ::\n"; + std::cout << "Inserting nodes selected into std::vector 'points'\n"; + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = + nt->_selected_nodes->allPoints(); + points.clear(); + std::vector::iterator pbegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = + selection.begin(); + i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast(*i); + pbegin = points.begin(); + points.insert(pbegin, desktop->doc2dt(n->position())); + std::cout << "inserting point::X=" << desktop->doc2dt(n->position())[X] + << ";Y=" << desktop->doc2dt(n->position())[Y] << "\n"; + } } - //bool hasNodesSelected = LPEBspline::hasNodesSelected(); - if(curve->get_segment_count() < 2) - return; - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - curve->reset(); + std::cout << "End inserting selected nodes into vector\n"; + } + //bool hasNodesSelected = LPEBspline::hasNodesSelected(); + if (curve->get_segment_count() < 2) + return; + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + 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 - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el penúltimo - 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 - - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point pointAt0(0,0); - Geom::Point pointAt1(0,0); - Geom::Point pointAt2(0,0); - Geom::Point pointAt3(0,0); - Geom::Point nextPointAt0(0,0); - Geom::Point nextPointAt1(0,0); - Geom::Point nextPointAt2(0,0); - Geom::Point nextPointAt3(0,0); - Geom::D2< Geom::SBasis > SBasisIn; - Geom::D2< Geom::SBasis > SBasisOut; - Geom::CubicBezier const *cubic = NULL; - 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(); + 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 + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point pointAt0(0, 0); + Geom::Point pointAt1(0, 0); + Geom::Point pointAt2(0, 0); + Geom::Point pointAt3(0, 0); + Geom::Point nextPointAt0(0, 0); + Geom::Point nextPointAt1(0, 0); + Geom::Point nextPointAt2(0, 0); + Geom::Point nextPointAt3(0, 0); + Geom::D2 SBasisIn; + Geom::D2 SBasisOut; + Geom::CubicBezier const *cubic = NULL; + 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(); + } + } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último + while (curve_it2 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path + //recto de entrada y de salida + SPCurve *in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + pointAt0 = in->first_segment()->initialPoint(); + pointAt3 = in->first_segment()->finalPoint(); + SBasisIn = in->first_segment()->toSBasis(); + if (!onlySelected) { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.0000) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); } + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo BSPline - nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while ( curve_it2 != curve_endit ) - { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path recto de entrada y de salida - SPCurve * in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - pointAt0 = in->first_segment()->initialPoint(); - pointAt3 = in->first_segment()->finalPoint(); - SBasisIn = in->first_segment()->toSBasis(); - if(!onlySelected){ - if(cubic){ - if(!ignoreCusp || !Geom::are_near((*cubic)[1],pointAt0)){ - pointAt1 = SBasisIn.valueAt(weightValue); - if(weightValue !=0.0000){ - pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); - } - }else{ - pointAt1 = in->first_segment()->initialPoint(); - } - if(!ignoreCusp || !Geom::are_near((*cubic)[2],pointAt3)){ - pointAt2 = SBasisIn.valueAt(1-weightValue); - if(weightValue !=0.0000){ - pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); - } - }else{ - pointAt2 = in->first_segment()->finalPoint(); - } - }else{ - if(!ignoreCusp && weightValue !=0.0000){ - pointAt1 = SBasisIn.valueAt(weightValue); - if(weightValue !=0.0000){ - pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); - } - pointAt2 = SBasisIn.valueAt(1-weightValue); - if(weightValue !=0.0000){ - pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); - } - }else{ - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - } - }else{ - if(cubic){ - if(!ignoreCusp || !Geom::are_near((*cubic)[1],pointAt0)){ - if(nodeIsSelected(pointAt0)){ - pointAt1 = SBasisIn.valueAt(weightValue); - if(weightValue !=0.0000){ - pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); - } - }else{ - pointAt1 = (*cubic)[1]; - } - }else{ - pointAt1 = in->first_segment()->initialPoint(); - } - if(!ignoreCusp || !Geom::are_near((*cubic)[2],pointAt3)){ - if(nodeIsSelected(pointAt3)){ - pointAt2 = SBasisIn.valueAt(1-weightValue); - if(weightValue !=0.0000){ - pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); - } - }else{ - pointAt2 = (*cubic)[2]; - } - }else{ - pointAt2 = in->first_segment()->finalPoint(); - } - }else{ - if(!ignoreCusp && weightValue !=0.000){ - if(nodeIsSelected(pointAt0)){ - pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = Geom::Point(pointAt1[X] + 0.0001,pointAt1[Y] + 0.0001); - }else{ - pointAt1 = in->first_segment()->initialPoint(); - } - if(nodeIsSelected(pointAt3)){ - pointAt2 = SBasisIn.valueAt(weightValue); - pointAt2 = Geom::Point(pointAt2[X] + 0.0001,pointAt2[Y] + 0.0001); - }else{ - pointAt2 = in->first_segment()->finalPoint(); - } - }else{ - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - } + } else { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { + if (nodeIsSelected(pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } else { + pointAt1 = (*cubic)[1]; } - in->reset(); - delete in; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente de - //los manejadores de la curva - nCurve->curveto(pointAt1, pointAt2, pointAt3); - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { + if (nodeIsSelected(pointAt3)) { + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt2 = (*cubic)[2]; + } + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.000) { + if (nodeIsSelected(pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (nodeIsSelected(pointAt3)) { + pointAt2 = SBasisIn.valueAt(weightValue); + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } } - SPCurve * out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt0 = out->first_segment()->initialPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - cubic = dynamic_cast(&*curve_it1); - if(!onlySelected){ - if(cubic){ - if(!ignoreCusp || !Geom::are_near((*cubic)[1],nextPointAt0)){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - if(weightValue !=0.0000){ - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); - } - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - } - if(!ignoreCusp || !Geom::are_near((*cubic)[2],nextPointAt3)){ - nextPointAt2 = SBasisOut.valueAt(1-weightValue); - if(weightValue !=0.0000){ - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); - } - }else{ - nextPointAt2 = out->first_segment()->finalPoint(); - } - }else{ - if(!ignoreCusp && weightValue !=0.0000){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); - nextPointAt2 = SBasisOut.valueAt(1-weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - } - } - }else{ - if(cubic){ - if(!ignoreCusp || !Geom::are_near((*cubic)[1],nextPointAt0)){ - if(nodeIsSelected(nextPointAt0)){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - if(weightValue !=0.0000){ - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); - } - }else{ - nextPointAt1 = (*cubic)[1]; - } - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - } - if(!ignoreCusp || !Geom::are_near((*cubic)[2],nextPointAt3)){ - if(nodeIsSelected(nextPointAt3)){ - nextPointAt2 = SBasisOut.valueAt(1-weightValue); - if(weightValue !=0.0000){ - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); - } - }else{ - nextPointAt2 = (*cubic)[2]; - } - }else{ - nextPointAt2 = out->first_segment()->finalPoint(); - } - }else{ - if(!ignoreCusp && weightValue !=0.0000){ - if(nodeIsSelected(nextPointAt0)){ - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001,nextPointAt1[Y] + 0.0001); - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - } - if(nodeIsSelected(nextPointAt3)){ - nextPointAt2 = SBasisOut.valueAt(weightValue); - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001,nextPointAt2[Y] + 0.0001); - }else{ - nextPointAt2 = out->first_segment()->finalPoint(); - } - }else{ - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - } + } + in->reset(); + delete in; + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de + //los manejadores de la curva + nCurve->curveto(pointAt1, pointAt2, pointAt3); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt0 = out->first_segment()->initialPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + cubic = dynamic_cast(&*curve_it1); + if (!onlySelected) { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + if (weightValue != 0.0000) { + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.0000) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } + } + } else { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { + if (nodeIsSelected(nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + if (weightValue != 0.0000) { + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001, + nextPointAt1[Y] + 0.0001); } + } else { + nextPointAt1 = (*cubic)[1]; + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); } - out->reset(); - delete out; - //Aberiguamos la ultima parte de la curva correspondiente al último segmento - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - if (path_it->closed()) { - nCurve->curveto(nextPointAt1, nextPointAt2, path_it->begin()->initialPoint()); - nCurve->move_endpoints(path_it->begin()->initialPoint(),path_it->begin()->initialPoint()); - }else{ - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(path_it->begin()->initialPoint(),nextPointAt3); + if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { + if (nodeIsSelected(nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001, + nextPointAt2[Y] + 0.0001); + } + } else { + nextPointAt2 = (*cubic)[2]; + } + } else { + nextPointAt2 = out->first_segment()->finalPoint(); } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); + } else { + if (!ignoreCusp && weightValue != 0.0000) { + if (nodeIsSelected(nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (nodeIsSelected(nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(weightValue); + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); } - curve->append(nCurve,false); - nCurve->reset(); - delete nCurve; - std::cout << ":: End ::\n"; + } + } + out->reset(); + delete out; + //Aberiguamos la ultima parte de la curva correspondiente al último + //segmento + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + if (path_it->closed()) { + nCurve->curveto(nextPointAt1, nextPointAt2, + path_it->begin()->initialPoint()); + nCurve->move_endpoints(path_it->begin()->initialPoint(), + path_it->begin()->initialPoint()); + } else { + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->move_endpoints(path_it->begin()->initialPoint(), nextPointAt3); + } + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); } + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; + std::cout << ":: End ::\n"; + } } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 510f9c989..167810c49 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -11,46 +11,45 @@ #include "live_effects/parameter/bool.h" #include - namespace Inkscape { namespace LivePathEffect { class LPEBSpline : public Effect { public: - LPEBSpline(LivePathEffectObject *lpeobject); - virtual ~LPEBSpline(); + LPEBSpline(LivePathEffectObject *lpeobject); + virtual ~LPEBSpline(); - virtual void createAndApply(const char* name, SPDocument *doc, SPItem *item); + virtual void createAndApply(const char *name, SPDocument *doc, SPItem *item); - virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } + virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } - virtual void doEffect(SPCurve * curve); + virtual void doEffect(SPCurve *curve); - virtual void doBSplineFromWidget(SPCurve * curve, double value); + virtual void doBSplineFromWidget(SPCurve *curve, double value); - virtual bool nodeIsSelected(Geom::Point nodePoint); + virtual bool nodeIsSelected(Geom::Point nodePoint); - virtual Gtk::Widget * newWidget(); + virtual Gtk::Widget *newWidget(); - virtual void changeWeight(double weightValue); + virtual void changeWeight(double weightValue); - virtual void toDefaultWeight(); + virtual void toDefaultWeight(); - virtual void toMakeCusp(); + virtual void toMakeCusp(); - virtual void toWeight(); + virtual void toWeight(); - ScalarParam steps; + ScalarParam steps; private: - std::vector points; - BoolParam ignoreCusp; - BoolParam onlySelected; - ScalarParam weight; + std::vector points; + BoolParam ignoreCusp; + BoolParam onlySelected; + ScalarParam weight; - LPEBSpline(const LPEBSpline&); - LPEBSpline& operator=(const LPEBSpline&); + LPEBSpline(const LPEBSpline &); + LPEBSpline &operator=(const LPEBSpline &); }; -- cgit v1.2.3 From 10fcc833d8d5d02bc8b77b87c812fd9e723193a0 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 31 Mar 2014 14:10:57 +0200 Subject: Fixed bug in LPE Bspline widget, on apply selected nodes, because a rounding problem. Thanks very much to Johan Engelen for point me to the correct direction. maybe is better round it previously to the are_near function, not sure (bzr r11950.1.318) --- src/live_effects/lpe-bspline.cpp | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 09e71d833..8254a13b6 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -39,8 +39,6 @@ #include "inkscape.h" #include "desktop.h" -#include - using Inkscape::DocumentUndo; namespace Inkscape { @@ -367,22 +365,14 @@ void LPEBSpline::changeWeight(double weightValue) { bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) { using Geom::X; using Geom::Y; - std::cout << "\n"; - std::cout << ":: Executed -> nodeIsSelected(Geom::Point nodePoint) ::\n"; - std::cout << "Want to check the argument -nodePoint- is in points vector \n"; - std::cout << "nodePoint::X=" << nodePoint[X] << ";Y=" << nodePoint[Y] << "\n"; - std::cout << "Checking points std::vector\n"; + if (points.size() > 0) { for (std::vector::iterator i = points.begin(); i != points.end(); ++i) { Geom::Point p = *i; - std::cout << "p::X=" << p[X] << ";Y=" << p[Y] << "\n"; - std::cout << "Are near? "; - if (Geom::are_near(p, nodePoint)) { - std::cout << "YES\n"; + if (Geom::are_near(p, nodePoint, 0.0001)) { return true; } else { - std::cout << "NO\n"; } } } @@ -394,9 +384,6 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { using Geom::Y; SPDesktop *desktop = inkscape_active_desktop(); if (INK_IS_NODE_TOOL(desktop->event_context)) { - std::cout << ":: Start -> doBSplineFromWidget(SPCurve * curve, double " - "weightValue) ::\n"; - std::cout << "Inserting nodes selected into std::vector 'points'\n"; Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); @@ -409,11 +396,8 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { Inkscape::UI::Node *n = dynamic_cast(*i); pbegin = points.begin(); points.insert(pbegin, desktop->doc2dt(n->position())); - std::cout << "inserting point::X=" << desktop->doc2dt(n->position())[X] - << ";Y=" << desktop->doc2dt(n->position())[Y] << "\n"; } } - std::cout << "End inserting selected nodes into vector\n"; } //bool hasNodesSelected = LPEBspline::hasNodesSelected(); if (curve->get_segment_count() < 2) @@ -696,7 +680,6 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { curve->append(nCurve, false); nCurve->reset(); delete nCurve; - std::cout << ":: End ::\n"; } } -- cgit v1.2.3 From f3e0966f95dc4284b1fd191fb4c187c92c24aeed Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 1 Apr 2014 20:40:15 -0400 Subject: Fix some stuff (bzr r13090.1.41) --- src/live_effects/effect.cpp | 10 +++++++++- src/live_effects/effect.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 337fe631f..8bf210270 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,7 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects +//#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects #ifdef HAVE_CONFIG_H # include "config.h" @@ -365,6 +365,14 @@ Effect::doBeforeEffect (SPLPEItem const*/*lpeitem*/) //Do nothing for simple effects } +void Effect::doAfterEffect (SPLPEItem const* lpeitem) +{ +} + +void Effect::doOnRemove (SPLPEItem const* lpeitem) +{ +} + /** * Effects can have a parameter path set before they are applied by accepting a nonzero number of * mouse clicks. This method activates the pen context, which waits for the specified number of diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 1da9b4cc9..85c930def 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -55,6 +55,9 @@ public: virtual void doOnApply (SPLPEItem const* lpeitem); virtual void doBeforeEffect (SPLPEItem const* lpeitem); + + virtual void doAfterEffect (SPLPEItem const* lpeitem); + virtual void doOnRemove (SPLPEItem const* lpeitem); void writeParamsToSVG(); -- cgit v1.2.3 From d20b73d611b6de99e0e0697ee47a760de437ee97 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 2 Apr 2014 17:18:40 -0400 Subject: Clean up code (bzr r13090.1.42) --- src/live_effects/lpe-taperstroke.cpp | 905 ++++++++++++++++--------------- src/live_effects/lpe-taperstroke.h | 48 +- src/live_effects/pathoutlineprovider.cpp | 521 +++++++++--------- src/live_effects/pathoutlineprovider.h | 16 +- 4 files changed, 765 insertions(+), 725 deletions(-) mode change 100755 => 100644 src/live_effects/lpe-taperstroke.cpp mode change 100755 => 100644 src/live_effects/pathoutlineprovider.cpp (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp old mode 100755 new mode 100644 index b4e43209d..97ae02e3b --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -38,26 +38,27 @@ namespace Inkscape { namespace LivePathEffect { namespace TpS { - class KnotHolderEntityAttachBegin : public LPEKnotHolderEntity { - public: - KnotHolderEntityAttachBegin(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; - }; - class KnotHolderEntityAttachEnd : public LPEKnotHolderEntity { - public: - KnotHolderEntityAttachEnd(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; - }; + class KnotHolderEntityAttachBegin : public LPEKnotHolderEntity { + public: + KnotHolderEntityAttachBegin(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + }; + + class KnotHolderEntityAttachEnd : public LPEKnotHolderEntity { + public: + KnotHolderEntityAttachEnd(LPETaperStroke * effect) : LPEKnotHolderEntity(effect) {} + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + }; } // TpS static const Util::EnumData JoinType[] = { - {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, - {LINEJOIN_ROUND, N_("Rounded"), "round"}, - {LINEJOIN_REFLECTED, N_("Reflected"), "reflected"}, - {LINEJOIN_POINTY, N_("Miter"), "miter"}, - {LINEJOIN_EXTRAPOLATED, N_("Extrapolated"), "extrapolated"} + {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, + {LINEJOIN_ROUND, N_("Rounded"), "round"}, + {LINEJOIN_REFLECTED, N_("Reflected"), "reflected"}, + {LINEJOIN_POINTY, N_("Miter"), "miter"}, + {LINEJOIN_EXTRAPOLATED, N_("Extrapolated"), "extrapolated"} }; static const Util::EnumDataConverter JoinTypeConverter(JoinType, sizeof (JoinType)/sizeof(*JoinType)); @@ -65,31 +66,30 @@ static const Util::EnumDataConverter JoinTypeConverter(JoinType, sizeo LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 3), - attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), - attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), - smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5), - join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), - miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 30.) + attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), + attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), + smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5), + join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), + miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 30.) { - /* uncomment the following line to have the original path displayed while the item is selected */ show_orig_path = true; - _provides_knotholder_entities = true; - - attach_start.param_set_digits(3); - attach_end.param_set_digits(3); - - - registerParameter( dynamic_cast(&line_width) ); - registerParameter( dynamic_cast(&attach_start) ); - registerParameter( dynamic_cast(&attach_end) ); - registerParameter( dynamic_cast(&smoothing) ); - registerParameter( dynamic_cast(&join_type) ); - registerParameter( dynamic_cast(&miter_limit) ); + _provides_knotholder_entities = true; + + attach_start.param_set_digits(3); + attach_end.param_set_digits(3); + + + registerParameter( dynamic_cast(&line_width) ); + registerParameter( dynamic_cast(&attach_start) ); + registerParameter( dynamic_cast(&attach_end) ); + registerParameter( dynamic_cast(&smoothing) ); + registerParameter( dynamic_cast(&join_type) ); + registerParameter( dynamic_cast(&miter_limit) ); } LPETaperStroke::~LPETaperStroke() { - + } //from LPEPowerStroke -- sets fill if stroke color because we will @@ -97,10 +97,10 @@ LPETaperStroke::~LPETaperStroke() void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) { - if (SP_IS_SHAPE(lpeitem)) { + if (SP_IS_SHAPE(lpeitem)) { SPLPEItem* item = const_cast(lpeitem); double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; - + SPCSSAttr *css = sp_repr_css_attr_new (); if (lpeitem->style->stroke.isSet()) { if (lpeitem->style->stroke.isPaintserver()) { @@ -122,13 +122,13 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) } else { sp_repr_css_unset_property (css, "fill"); } - + sp_repr_css_set_property(css, "stroke", "none"); - + sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); - line_width.param_set_value(width); + line_width.param_set_value(width); } else { g_warning("LPE Join Type can only be applied to paths (not groups)."); } @@ -138,8 +138,10 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) { - - if (SP_IS_SHAPE(lpeitem)) { + + if (SP_IS_SHAPE(lpeitem)) { + //TODO: make it getobjbyrepr instead of const_cast because this can cause + //undefined behavior SPLPEItem *item = const_cast(lpeitem); SPCSSAttr *css = sp_repr_css_attr_new (); @@ -164,7 +166,7 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) sp_repr_css_unset_property (css, "stroke"); } - Inkscape::CSSOStringStream os; + Inkscape::CSSOStringStream os; os << fabs(line_width); sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); @@ -173,335 +175,347 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); item->updateRepr(); - } + } } //actual effect impl here Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_tolerance = 0.05) { - Geom::Path path_out = Geom::Path(); - - for (unsigned i = 0; i < path_in.size(); i++) - { - path_out.append(path_in[i]); - if (path_in.size() == 1) - break; - - //determine order of curve - int order = Outline::bezierOrder(&path_in[i]); - - Geom::Point start_point; - Geom::Point cross_point = path_in[i].finalPoint(); - Geom::Point end_point; - - g_assert(path_in[i].finalPoint() == path_in[i+1].initialPoint()); - - //can you tell that the following expressions have been shaped by - //repeated compiler errors? ;) - switch (order) - { - case 3: - start_point = (static_cast(&path_in[i]))->operator[] (2); - //major league b***f***ing - if (are_near(start_point, cross_point, 0.0000001)) { - start_point = (static_cast(&path_in[i]))->operator[] (1); - } - break; - case 2: - //this never happens - start_point = (static_cast(&path_in[i]))->operator[] (1); - break; - case 1: - default: - start_point = path_in[i].initialPoint(); - } - - order = Outline::bezierOrder(&path_in[i+1]); - - switch (order) - { - case 3: - end_point = (static_cast(&path_in[i+1]))->operator[] (1); - if (are_near(end_point, cross_point, 0.0000001)) { - end_point = (static_cast(&path_in[i+1]))->operator[] (2); - } - break; - case 2: - end_point = (static_cast(&path_in[i+1]))->operator[] (1); - break; - case 1: - default: - end_point = path_in[i+1].finalPoint(); - } - - g_assert(!are_near(start_point, cross_point, 0.0000001)); //take that motherf*ckers - g_assert(!are_near(cross_point, end_point, 0.0000001)); - g_assert(!are_near(start_point, end_point, 0.0000001)); - - if (!are_collinear(start_point, cross_point, end_point, smooth_tolerance)) - break; - } - return path_out; + Geom::Path path_out = Geom::Path(); + + for (unsigned i = 0; i < path_in.size(); i++) { + path_out.append(path_in[i]); + if (path_in.size() == 1) + break; + + //determine order of curve + int order = Outline::bezierOrder(&path_in[i]); + + Geom::Point start_point; + Geom::Point cross_point = path_in[i].finalPoint(); + Geom::Point end_point; + + g_assert(path_in[i].finalPoint() == path_in[i+1].initialPoint()); + + //can you tell that the following expressions have been shaped by + //repeated compiler errors? ;) + switch (order) { + case 3: + start_point = (static_cast(&path_in[i]))->operator[] (2); + //major league b***f***ing + if (are_near(start_point, cross_point, 0.0000001)) { + start_point = (static_cast(&path_in[i]))->operator[] (1); + } + break; + case 2: + //this never happens + start_point = (static_cast(&path_in[i]))->operator[] (1); + break; + case 1: + default: + start_point = path_in[i].initialPoint(); + } + + order = Outline::bezierOrder(&path_in[i+1]); + + switch (order) { + case 3: + end_point = (static_cast(&path_in[i+1]))->operator[] (1); + if (are_near(end_point, cross_point, 0.0000001)) { + end_point = (static_cast(&path_in[i+1]))->operator[] (2); + } + break; + case 2: + end_point = (static_cast(&path_in[i+1]))->operator[] (1); + break; + case 1: + default: + end_point = path_in[i+1].finalPoint(); + } + + //clearly it's collinear if two occupy the same point + g_assert(!are_near(start_point, cross_point, 0.0000001)); + g_assert(!are_near(cross_point, end_point, 0.0000001)); + g_assert(!are_near(start_point, end_point, 0.0000001)); + + if (!are_collinear(start_point, cross_point, end_point, smooth_tolerance)) + break; + } + return path_out; } Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double width); +//references to pointers, because magic +void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) { - Geom::Path first_cusp = return_at_first_cusp(path_in[0]); - Geom::Path last_cusp = return_at_first_cusp(path_in[0].reverse()); - - bool zeroStart = false; - bool zeroEnd = false; - //there is a pretty good chance that people will try to drag the knots - //on top of each other, so block it - - unsigned size = path_in[0].size(); - if (size == first_cusp.size()) { - //check to see if the knots were dragged over each other - //if so, reset the end offset - if ( attach_start >= (size - attach_end) ) { - attach_end.param_set_value( size - attach_start ); - } - } - - //don't ever let it be zero - if (attach_start <= 0.00000001) { - attach_start.param_set_value( 0.00000001 ); - zeroStart = true; - } - if (attach_end <= 0.00000001) { - attach_end.param_set_value( 0.00000001 ); - zeroEnd = true; - } - - //don't let it be integer - if (double(unsigned(attach_start)) == attach_start) { - attach_start.param_set_value(attach_start - 0.00001); - } - if (double(unsigned(attach_end)) == attach_end) { - attach_end.param_set_value(attach_end - 0.00001); - } - - unsigned allowed_start = first_cusp.size(); - unsigned allowed_end = last_cusp.size(); - - //don't let the knots be farther than they are allowed to be - if ((unsigned)attach_start >= allowed_start) { - attach_start.param_set_value((double)allowed_start - 0.00000001); - } - if ((unsigned)attach_end >= allowed_end) { - attach_end.param_set_value((double)allowed_end - 0.00000001); - } - - //remember, Path::operator () means get point at time t - start_attach_point = first_cusp(attach_start); - end_attach_point = last_cusp(attach_end); - Geom::PathVector pathv_out; - - //the following function just splits it up into three pieces. - pathv_out = doEffect_simplePath(path_in); - - //now for the actual tapering. We use a Pattern Along Path method to get this done. - - Geom::PathVector real_pathv; - Geom::Path real_path; - Geom::PathVector pat_vec; - Geom::Piecewise > pwd2; - Geom::Path throwaway_path; - - if (!zeroStart) { - //Construct the pattern (pat_str stands for pattern string) (yes, this is easier, trust me) - std::stringstream pat_str; - pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; - - pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); - pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); - throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; - - real_path.append(throwaway_path); - } - //append the outside outline of the path (with direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1], - -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - - if (!zeroStart) { - throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path); - } else { - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - } - - if (!zeroEnd) { - //append the ending taper - std::stringstream pat_str_1; - pat_str_1 << "M 0,0 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; - pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); - - pwd2 = Geom::Piecewise > (); - pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); - - throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; - throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path); - } - //append the inside outline of the path (against direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), - -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - - if (!zeroEnd) { - //throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - } else { - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - } - real_path.close(); - - real_pathv.push_back(real_path); - - return real_pathv; + Geom::Path first_cusp = return_at_first_cusp(path_in[0]); + Geom::Path last_cusp = return_at_first_cusp(path_in[0].reverse()); + + bool zeroStart = false; + bool zeroEnd = false; + //there is a pretty good chance that people will try to drag the knots + //on top of each other, so block it + + unsigned size = path_in[0].size(); + if (size == first_cusp.size()) { + //check to see if the knots were dragged over each other + //if so, reset the end offset + if ( attach_start >= (size - attach_end) ) { + attach_end.param_set_value( size - attach_start ); + } + } + + //don't ever let it be zero + if (attach_start <= 0.00000001) { + attach_start.param_set_value( 0.00000001 ); + zeroStart = true; + } + if (attach_end <= 0.00000001) { + attach_end.param_set_value( 0.00000001 ); + zeroEnd = true; + } + + //don't let it be integer + if (double(unsigned(attach_start)) == attach_start) { + attach_start.param_set_value(attach_start - 0.00001); + } + if (double(unsigned(attach_end)) == attach_end) { + attach_end.param_set_value(attach_end - 0.00001); + } + + unsigned allowed_start = first_cusp.size(); + unsigned allowed_end = last_cusp.size(); + + //don't let the knots be farther than they are allowed to be + if ((unsigned)attach_start >= allowed_start) { + attach_start.param_set_value((double)allowed_start - 0.00000001); + } + if ((unsigned)attach_end >= allowed_end) { + attach_end.param_set_value((double)allowed_end - 0.00000001); + } + + //remember, Path::operator () means get point at time t + start_attach_point = first_cusp(attach_start); + end_attach_point = last_cusp(attach_end); + Geom::PathVector pathv_out; + + //the following function just splits it up into three pieces. + pathv_out = doEffect_simplePath(path_in); + + //now for the actual tapering. We use a Pattern Along Path method to get this done. + + Geom::PathVector real_pathv; + Geom::Path real_path; + Geom::PathVector pat_vec; + Geom::Piecewise > pwd2; + Geom::Path throwaway_path; + + if (!zeroStart) { + //Construct the pattern (pat_str stands for pattern string) (yes, this is easier, trust me) + std::stringstream pat_str; + pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; + + pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); + throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; + + real_path.append(throwaway_path); + } + //append the outside outline of the path (with direction) + throwaway_path = Outline::PathOutsideOutline(pathv_out[1], + -fabs(line_width), static_cast(join_type.get_value()), miter_limit); + + if (!zeroStart) { + throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path); + } else { + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + } + + if (!zeroEnd) { + //append the ending taper + std::stringstream pat_str_1; + pat_str_1 << "M 0,0 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; + pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); + + pwd2 = Geom::Piecewise > (); + pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); + + throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; + throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path); + } + //append the inside outline of the path (against direction) + throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), + -fabs(line_width), static_cast(join_type.get_value()), miter_limit); + + if (!zeroEnd) { + //throwaway_path.setInitial(real_path.finalPoint()); + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + } else { + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + } + + //hmm + real_path.setFinal(real_path.initialPoint()); + + real_path.close(); + + real_pathv.push_back(real_path); + + return real_pathv; } //in all cases, this should return a PathVector with three elements. Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & path_in) { - unsigned size = path_in[0].size(); - - //do subdivision and get out - unsigned loc = (unsigned)attach_start; - Geom::Curve * curve_start = path_in[0] [loc].duplicate(); - - std::vector pathv_out; - Geom::Path path_out = Geom::Path(); - - Geom::Path trimmed_start = Geom::Path(); - Geom::Path trimmed_end = Geom::Path(); - - for (unsigned i = 0; i < loc; i++) { - trimmed_start.append(path_in[0] [i]); - } - - - //this is pretty annoying - //previously I wrote a function for this but it wasted a lot of time - //so I optimized it back into here. - unsigned order = Outline::bezierOrder(curve_start); - switch (order) { - case 3: { - Geom::CubicBezier *cb = static_cast(curve_start); - std::pair cb_pair = cb->subdivide((attach_start - loc)); - trimmed_start.append(cb_pair.first); curve_start = cb_pair.second.duplicate(); //goes out of scope - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_start); - std::pair qb_pair = qb->subdivide((attach_start - loc)); - trimmed_start.append(qb_pair.first); curve_start = qb_pair.second.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide((attach_start - loc)); - trimmed_start.append(lb_pair.first); curve_start = lb_pair.second.duplicate(); - break; - } - } - - //special case: path is one segment long - //special case: what if the two knots occupy the same segment? - if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) - { - Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); - - //it is just a dumb segment - //we have to do some shifting here because the value changed when we reduced the length - //of the previous segment. - - order = Outline::bezierOrder(curve_start); - switch (order) { - case 3: { - Geom::CubicBezier *cb = static_cast(curve_start); - std::pair cb_pair = cb->subdivide(t); - trimmed_end.append(cb_pair.second); curve_start = cb_pair.first.duplicate(); - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_start); - std::pair qb_pair = qb->subdivide(t); - trimmed_end.append(qb_pair.second); curve_start = qb_pair.first.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); - trimmed_end.append(lb_pair.second); curve_start = lb_pair.first.duplicate(); - break; - } - } - - for (unsigned j = (size - attach_end) + 1; j < size; j++) { - trimmed_end.append(path_in[0] [j]); - } - - path_out.append(*curve_start); - pathv_out.push_back(trimmed_start); - pathv_out.push_back(path_out); - pathv_out.push_back(trimmed_end); - return pathv_out; - } - - pathv_out.push_back(trimmed_start); - - //append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) - path_out.append(*curve_start); - - for (unsigned k = loc + 1; k < (size - unsigned(attach_end)) - 1; k++) { - path_out.append(path_in[0] [k]); - } - - //deal with the last segment in a very similar fashion to the first - loc = size - attach_end; - - Geom::Curve * curve_end = path_in[0] [loc].duplicate(); - - Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); - - order = Outline::bezierOrder(curve_end); - switch (order) { - case 3: { - Geom::CubicBezier *cb = static_cast(curve_end); - std::pair cb_pair = cb->subdivide(t); - trimmed_end.append(cb_pair.second); curve_end = cb_pair.first.duplicate(); - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_end); - std::pair qb_pair = qb->subdivide(t); - trimmed_end.append(qb_pair.second); curve_end = qb_pair.first.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_end); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); - trimmed_end.append(lb_pair.second); curve_end = lb_pair.first.duplicate(); - break; - } - } - - for (unsigned j = (size - attach_end) + 1; j < size; j++) { - trimmed_end.append(path_in[0] [j]); - } - - path_out.append(*curve_end); - pathv_out.push_back(path_out); - - pathv_out.push_back(trimmed_end); - - if (curve_end) delete curve_end; - if (curve_start) delete curve_start; - return pathv_out; + unsigned size = path_in[0].size(); + + //do subdivision and get out + unsigned loc = (unsigned)attach_start; + Geom::Curve * curve_start = path_in[0] [loc].duplicate(); + + std::vector pathv_out; + Geom::Path path_out = Geom::Path(); + + Geom::Path trimmed_start = Geom::Path(); + Geom::Path trimmed_end = Geom::Path(); + + for (unsigned i = 0; i < loc; i++) { + trimmed_start.append(path_in[0] [i]); + } + + + //this is pretty annoying + //previously I wrote a function for this but it wasted a lot of time + //so I optimized it back into here. + unsigned order = Outline::bezierOrder(curve_start); + switch (order) { + case 3: { + Geom::CubicBezier *cb = static_cast(curve_start); + std::pair cb_pair = cb->subdivide((attach_start - loc)); + trimmed_start.append(cb_pair.first); + curve_start = cb_pair.second.duplicate(); //goes out of scope + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_start); + std::pair qb_pair = qb->subdivide((attach_start - loc)); + trimmed_start.append(qb_pair.first); + curve_start = qb_pair.second.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide((attach_start - loc)); + trimmed_start.append(lb_pair.first); + curve_start = lb_pair.second.duplicate(); + break; + } + } + + //special case: path is one segment long + //special case: what if the two knots occupy the same segment? + if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) { + Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); + + //it is just a dumb segment + //we have to do some shifting here because the value changed when we reduced the length + //of the previous segment. + + order = Outline::bezierOrder(curve_start); + switch (order) { + case 3: { + Geom::CubicBezier *cb = static_cast(curve_start); + std::pair cb_pair = cb->subdivide(t); + trimmed_end.append(cb_pair.second); + curve_start = cb_pair.first.duplicate(); + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_start); + std::pair qb_pair = qb->subdivide(t); + trimmed_end.append(qb_pair.second); + curve_start = qb_pair.first.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); + trimmed_end.append(lb_pair.second); + curve_start = lb_pair.first.duplicate(); + break; + } + } + + for (unsigned j = (size - attach_end) + 1; j < size; j++) { + trimmed_end.append(path_in[0] [j]); + } + + path_out.append(*curve_start); + pathv_out.push_back(trimmed_start); + pathv_out.push_back(path_out); + pathv_out.push_back(trimmed_end); + return pathv_out; + } + + pathv_out.push_back(trimmed_start); + + //append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) + path_out.append(*curve_start); + + for (unsigned k = loc + 1; k < (size - unsigned(attach_end)) - 1; k++) { + path_out.append(path_in[0] [k]); + } + + //deal with the last segment in a very similar fashion to the first + loc = size - attach_end; + + Geom::Curve * curve_end = path_in[0] [loc].duplicate(); + + Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); + + order = Outline::bezierOrder(curve_end); + switch (order) { + case 3: { + Geom::CubicBezier *cb = static_cast(curve_end); + std::pair cb_pair = cb->subdivide(t); + trimmed_end.append(cb_pair.second); + curve_end = cb_pair.first.duplicate(); + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_end); + std::pair qb_pair = qb->subdivide(t); + trimmed_end.append(qb_pair.second); + curve_end = qb_pair.first.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_end); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); + trimmed_end.append(lb_pair.second); + curve_end = lb_pair.first.duplicate(); + break; + } + } + + for (unsigned j = (size - attach_end) + 1; j < size; j++) { + trimmed_end.append(path_in[0] [j]); + } + + path_out.append(*curve_end); + pathv_out.push_back(path_out); + + pathv_out.push_back(trimmed_end); + + if (curve_end) delete curve_end; + if (curve_start) delete curve_start; + return pathv_out; } @@ -509,14 +523,14 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa //tweaking to get it to work right in this case. Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double prop_scale) { - using namespace Geom; + using namespace Geom; // Don't allow empty path parameter: if ( pattern.empty() ) { return pwd2_in; } -/* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */ + /* Much credit should go to jfb and mgsloan of lib2geom development for the code below! */ Piecewise > output; std::vector > > pre_output; @@ -548,7 +562,7 @@ Geom::Piecewise > stretch_along(Geom::Piecewise > > paths_in; paths_in = split_at_discontinuities(pwd2_in); - for (unsigned idx = 0; idx < paths_in.size(); idx++){ + for (unsigned idx = 0; idx < paths_in.size(); idx++) { Geom::Piecewise > path_i = paths_in[idx]; Piecewise x = x0; Piecewise y = y0; @@ -556,14 +570,14 @@ Geom::Piecewise > stretch_along(Geom::Piecewise > n = rot90(derivative(uskeleton)); n = force_continuity(remove_short_cuts(n,.1)); - + int nbCopies = 0; double scaling = 1; nbCopies = 1; scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); double pattWidth = pattBndsX->extent() * scaling; - + if (scaling != 1.0) { x*=scaling; } @@ -573,20 +587,20 @@ Geom::Piecewise > stretch_along(Geom::Piecewise > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs); std::vector > > splited_output_piece = split_at_discontinuities(output_piece); pre_output.insert(pre_output.end(), splited_output_piece.begin(), splited_output_piece.end() ); - }else{ + } else { output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs)); } offs+=pattWidth; } } - /*if (false){ + /*if (false){ pre_output = fuse_nearby_ends(pre_output, fuse_tolerance); for (unsigned i=0; i > stretch_along(Geom::Piecewise(curve_in); + std::pair cb_pair = cb->subdivide(t); + //trimmed_start.append(cb_pair.first); + val_first = cb_pair.first.duplicate(); + val_second = cb_pair.second.duplicate(); + break; + } + case 2: { + Geom::QuadraticBezier *qb = static_cast(curve_in); + std::pair qb_pair = qb->subdivide(t); + //trimmed_start.append(qb_pair.first); + val_first = qb_pair.first.duplicate(); + val_second = qb_pair.second.duplicate(); + break; + } + case 1: { + Geom::BezierCurveN<1> *lb = static_cast * >(curve_in); + std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); + //trimmed_start.append(lb_pair.first); + val_first = lb_pair.first.duplicate(); + val_second = lb_pair.second.duplicate(); + break; + } + } +} -void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) + +void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { - { - KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); - knotholder->add(e); - } - { - KnotHolderEntity *e = new TpS::KnotHolderEntityAttachEnd(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); - knotholder->add(e); - } + { + KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); + e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); + knotholder->add(e); + } + { + KnotHolderEntity *e = new TpS::KnotHolderEntityAttachEnd(this); + e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); + knotholder->add(e); + } } namespace TpS { - void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) - { - using namespace Geom; - - LPETaperStroke* lpe = dynamic_cast(_effect); - - Geom::Point const s = snap_knot_position(p, state); - - SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); - Geom::PathVector pathv = curve->get_pathvector(); - Piecewise > pwd2; - Geom::Path p_in = return_at_first_cusp(pathv[0]); - pwd2.concat(p_in.toPwSb()); - std::vector > > pwd_vec = split_at_discontinuities(pwd2); - - double t0 = nearest_point(s, pwd_vec[0]); - lpe->attach_start.param_set_value(t0); - - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); - } - void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state) - { - using namespace Geom; - - LPETaperStroke* lpe = dynamic_cast(_effect); - - Geom::Point const s = snap_knot_position(p, state); - - SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); - Geom::PathVector pathv = curve->get_pathvector(); - Piecewise > pwd2; - Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); - pwd2.concat(p_in.toPwSb()); - std::vector > > pwd_vec = split_at_discontinuities(pwd2); - - double t0 = nearest_point(s, pwd_vec[0]); - lpe->attach_end.param_set_value(t0); - - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); - } - Geom::Point KnotHolderEntityAttachBegin::knot_get() const - { - LPETaperStroke const * lpe = dynamic_cast (_effect); - return lpe->start_attach_point; - } - Geom::Point KnotHolderEntityAttachEnd::knot_get() const - { - LPETaperStroke const * lpe = dynamic_cast (_effect); - return lpe->end_attach_point; - } +void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) +{ + using namespace Geom; + + LPETaperStroke* lpe = dynamic_cast(_effect); + + Geom::Point const s = snap_knot_position(p, state); + + SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); + Geom::PathVector pathv = curve->get_pathvector(); + Piecewise > pwd2; + Geom::Path p_in = return_at_first_cusp(pathv[0]); + pwd2.concat(p_in.toPwSb()); + std::vector > > pwd_vec = split_at_discontinuities(pwd2); + + double t0 = nearest_point(s, pwd_vec[0]); + lpe->attach_start.param_set_value(t0); + + // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); +} +void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state) +{ + using namespace Geom; + + LPETaperStroke* lpe = dynamic_cast(_effect); + + Geom::Point const s = snap_knot_position(p, state); + + SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); + Geom::PathVector pathv = curve->get_pathvector(); + Piecewise > pwd2; + Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); + pwd2.concat(p_in.toPwSb()); + std::vector > > pwd_vec = split_at_discontinuities(pwd2); + + double t0 = nearest_point(s, pwd_vec[0]); + lpe->attach_end.param_set_value(t0); + + // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); +} +Geom::Point KnotHolderEntityAttachBegin::knot_get() const +{ + LPETaperStroke const * lpe = dynamic_cast (_effect); + return lpe->start_attach_point; +} +Geom::Point KnotHolderEntityAttachEnd::knot_get() const +{ + LPETaperStroke const * lpe = dynamic_cast (_effect); + return lpe->end_attach_point; +} } diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h index 29a56f77c..997209543 100644 --- a/src/live_effects/lpe-taperstroke.h +++ b/src/live_effects/lpe-taperstroke.h @@ -20,39 +20,39 @@ namespace Inkscape { namespace LivePathEffect { namespace TpS { - // we need a separate namespace to avoid clashes with other LPEs - class KnotHolderEntityAttachBegin; - class KnotHolderEntityAttachEnd; +// we need a separate namespace to avoid clashes with other LPEs +class KnotHolderEntityAttachBegin; +class KnotHolderEntityAttachEnd; } class LPETaperStroke : public Effect { public: - LPETaperStroke(LivePathEffectObject *lpeobject); - virtual ~LPETaperStroke(); - - virtual void doOnApply(SPLPEItem const* lpeitem); - virtual void doOnRemove(SPLPEItem const* lpeitem); + LPETaperStroke(LivePathEffectObject *lpeobject); + virtual ~LPETaperStroke(); - virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in); - Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in); - - virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); + virtual void doOnApply(SPLPEItem const* lpeitem); + virtual void doOnRemove(SPLPEItem const* lpeitem); - friend class TpS::KnotHolderEntityAttachBegin; - friend class TpS::KnotHolderEntityAttachEnd; + virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in); + Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in); + + virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); + + friend class TpS::KnotHolderEntityAttachBegin; + friend class TpS::KnotHolderEntityAttachEnd; private: - ScalarParam line_width; - ScalarParam attach_start; - ScalarParam attach_end; - ScalarParam smoothing; - EnumParam join_type; - ScalarParam miter_limit; + ScalarParam line_width; + ScalarParam attach_start; + ScalarParam attach_end; + ScalarParam smoothing; + EnumParam join_type; + ScalarParam miter_limit; - Geom::Point start_attach_point; - Geom::Point end_attach_point; + Geom::Point start_attach_point; + Geom::Point end_attach_point; - LPETaperStroke(const LPETaperStroke&); - LPETaperStroke& operator=(const LPETaperStroke&); + LPETaperStroke(const LPETaperStroke&); + LPETaperStroke& operator=(const LPETaperStroke&); }; } //namespace LivePathEffect diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp old mode 100755 new mode 100644 index 6a47285a0..ad39a7416 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -9,133 +9,128 @@ #include <2geom/path-sink.h> #include -namespace Geom +namespace Geom { +/** +* Refer to: Weisstein, Eric W. "Circle-Circle Intersection." + From MathWorld--A Wolfram Web Resource. + http://mathworld.wolfram.com/Circle-CircleIntersection.html +* +* @return 0 if no intersection +* @return 1 if one circle is contained in the other +* @return 2 if intersections are found (they are written to p0 and p1) +*/ +static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, + Point & p0, Point & p1) +{ + Point X0 = circle0.center(); + double r0 = circle0.ray(); + Point X1 = circle1.center(); + double r1 = circle1.ray(); + + /* dx and dy are the vertical and horizontal distances between + * the circle centers. + */ + Point D = X1 - X0; + + /* Determine the straight-line distance between the centers. */ + double d = L2(D); + + /* Check for solvability. */ + if (d > (r0 + r1)) { + /* no solution. circles do not intersect. */ + return 0; + } + if (d <= fabs(r0 - r1)) { + /* no solution. one circle is contained in the other */ + return 1; + } + + /* 'point 2' is the point where the line through the circle + * intersection points crosses the line between the circle + * centers. + */ + + /* Determine the distance from point 0 to point 2. */ + double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; + + /* Determine the coordinates of point 2. */ + Point p2 = X0 + D * (a/d); + + /* Determine the distance from point 2 to either of the + * intersection points. + */ + double h = std::sqrt((r0*r0) - (a*a)); + + /* Now determine the offsets of the intersection points from + * point 2. + */ + Point r = (h/d)*rot90(D); + + /* Determine the absolute intersection points. */ + p0 = p2 + r; + p1 = p2 - r; + + return 2; +} +/** +* Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. +* Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). +*/ +static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) { - /** - * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/Circle-CircleIntersection.html - * - * @return 0 if no intersection - * @return 1 if one circle is contained in the other - * @return 2 if intersections are found (they are written to p0 and p1) - */ - static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, - Point & p0, Point & p1) - { - Point X0 = circle0.center(); - double r0 = circle0.ray(); - Point X1 = circle1.center(); - double r1 = circle1.ray(); - - /* dx and dy are the vertical and horizontal distances between - * the circle centers. - */ - Point D = X1 - X0; - - /* Determine the straight-line distance between the centers. */ - double d = L2(D); - - /* Check for solvability. */ - if (d > (r0 + r1)) - { - /* no solution. circles do not intersect. */ - return 0; - } - if (d <= fabs(r0 - r1)) - { - /* no solution. one circle is contained in the other */ - return 1; - } - - /* 'point 2' is the point where the line through the circle - * intersection points crosses the line between the circle - * centers. - */ - - /* Determine the distance from point 0 to point 2. */ - double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; - - /* Determine the coordinates of point 2. */ - Point p2 = X0 + D * (a/d); - - /* Determine the distance from point 2 to either of the - * intersection points. - */ - double h = std::sqrt((r0*r0) - (a*a)); - - /* Now determine the offsets of the intersection points from - * point 2. - */ - Point r = (h/d)*rot90(D); - - /* Determine the absolute intersection points. */ - p0 = p2 + r; - p1 = p2 - r; - - return 2; - } - /** - * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. - * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). - */ - static Circle touching_circle( D2 const &curve, double t, double tol=0.01 ) - { - D2 dM=derivative(curve); - if ( are_near(L2sq(dM(t)),0.) ) { - dM=derivative(dM); - } - if ( are_near(L2sq(dM(t)),0.) ) { // try second time - dM=derivative(dM); - } - Piecewise > unitv = unitVector(dM,tol); - Piecewise dMlength = dot(Piecewise >(dM),unitv); - Piecewise k = cross(derivative(unitv),unitv); - k = divide(k,dMlength,tol,3); - double curv = k(t); // note that this value is signed - - Geom::Point normal = unitTangentAt(curve, t).cw(); - double radius = 1/curv; - Geom::Point center = curve(t) + radius*normal; - return Geom::Circle(center, fabs(radius)); - } - - static std::vector split_at_cusps(const Geom::Path& in) - { - Geom::PathVector out = Geom::PathVector(); - Geom::Path temp = Geom::Path(); - - for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) - { - temp = Geom::Path(); - temp.append(in[path_descr]); - out.push_back(temp); - } - - return out; - } - - static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) - { - std::vector temp; - sbasis_to_bezier(temp, sbasis_in, 4); - return Geom::CubicBezier( temp ); - } - - static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, - Geom::Point const & origin_b, Geom::Point const & vector_b) - { - Geom::Coord denom = cross(vector_b, vector_a); - if (!Geom::are_near(denom,0.)){ - Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; - return origin_a + t * vector_a; - } - return boost::none; - } + D2 dM=derivative(curve); + if ( are_near(L2sq(dM(t)),0.) ) { + dM=derivative(dM); + } + if ( are_near(L2sq(dM(t)),0.) ) { // try second time + dM=derivative(dM); + } + Piecewise > unitv = unitVector(dM,tol); + Piecewise dMlength = dot(Piecewise >(dM),unitv); + Piecewise k = cross(derivative(unitv),unitv); + k = divide(k,dMlength,tol,3); + double curv = k(t); // note that this value is signed + + Geom::Point normal = unitTangentAt(curve, t).cw(); + double radius = 1/curv; + Geom::Point center = curve(t) + radius*normal; + return Geom::Circle(center, fabs(radius)); } -namespace Outline +static std::vector split_at_cusps(const Geom::Path& in) { + Geom::PathVector out = Geom::PathVector(); + Geom::Path temp = Geom::Path(); + + for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) { + temp = Geom::Path(); + temp.append(in[path_descr]); + out.push_back(temp); + } + + return out; +} + +static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) +{ + std::vector temp; + sbasis_to_bezier(temp, sbasis_in, 4); + return Geom::CubicBezier( temp ); +} + +static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, + Geom::Point const & origin_b, Geom::Point const & vector_b) +{ + Geom::Coord denom = cross(vector_b, vector_a); + if (!Geom::are_near(denom,0.)) { + Geom::Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + return origin_a + t * vector_a; + } + return boost::none; +} +} + +namespace Outline { typedef Geom::D2 D2SB; typedef Geom::Piecewise PWD2; @@ -160,72 +155,70 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) unsigned order = bezierOrder(&cbc1); Geom::Point start_point; - Geom::Point cross_point = cbc1.finalPoint(); - Geom::Point end_point; - - //assert(cbc1.finalPoint() == cbc2.initialPoint()); - //short circuiting? - if (cbc1.finalPoint() != cbc2.initialPoint()) { - printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n" - "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); - return false; + Geom::Point cross_point = cbc1.finalPoint(); + Geom::Point end_point; + + //assert(cbc1.finalPoint() == cbc2.initialPoint()); + //short circuiting? + if (cbc1.finalPoint() != cbc2.initialPoint()) { + printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n" + "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); + return false; + } + switch (order) { + case 3: + start_point = (static_cast(&cbc1))->operator[] (2); + //major league b***f***ing + if (are_near(start_point, cross_point, 0.0000001)) { + start_point = (static_cast(&cbc1))->operator[] (1); } - switch (order) - { - case 3: - start_point = (static_cast(&cbc1))->operator[] (2); - //major league b***f***ing - if (are_near(start_point, cross_point, 0.0000001)) { - start_point = (static_cast(&cbc1))->operator[] (1); - } - break; - case 2: - //this never happens - start_point = (static_cast(&cbc1))->operator[] (1); - break; - case 1: - default: - start_point = cbc1.initialPoint(); - } - - order = Outline::bezierOrder(&cbc2); - - switch (order) - { - case 3: - end_point = (static_cast(&cbc2))->operator[] (1); - if (are_near(end_point, cross_point, 0.0000001)) { - end_point = (static_cast(&cbc2))->operator[] (2); - } - break; - case 2: - end_point = (static_cast(&cbc2))->operator[] (1); - break; - case 1: - default: - end_point = cbc2.finalPoint(); - } - //got our three points, now let's see what their clockwise angle is - - //Much credit to Wikipedia for the following ( http://en.wikipedia.org/wiki/Graham_scan ) - /******************************************************************** + break; + case 2: + //this never happens + start_point = (static_cast(&cbc1))->operator[] (1); + break; + case 1: + default: + start_point = cbc1.initialPoint(); + } + + order = Outline::bezierOrder(&cbc2); + + switch (order) { + case 3: + end_point = (static_cast(&cbc2))->operator[] (1); + if (are_near(end_point, cross_point, 0.0000001)) { + end_point = (static_cast(&cbc2))->operator[] (2); + } + break; + case 2: + end_point = (static_cast(&cbc2))->operator[] (1); + break; + case 1: + default: + end_point = cbc2.finalPoint(); + } + //got our three points, now let's see what their clockwise angle is + + //Much credit to Wikipedia for the following ( http://en.wikipedia.org/wiki/Graham_scan ) + /******************************************************************** # Three points are a counter-clockwise turn if ccw > 0, clockwise if # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that # gives the signed area of the triangle formed by p1, p2 and p3. function ccw(p1, p2, p3): - return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) + return (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) *********************************************************************/ - + double ccw = ( (cross_point.x() - start_point.x()) * (end_point.y() - start_point.y()) ) - ( (cross_point.y() - start_point.y()) * (end_point.x() - start_point.x()) ); if (ccw > 0) return true; return false; } -void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, +void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, double line_width, bool outside = false) { - bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); + bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); if ( outside && !lineProblem ) { Geom::Path pth; pth.append(*cbc1); @@ -271,9 +264,8 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } else { boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { + cbc2->initialPoint(), tang2); + if (p) { //check size of miter Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; Geom::Coord len = distance(*p, point_on_path); @@ -284,19 +276,18 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } path_builder.appendNew (endPt); } - } - if ( outside && lineProblem ) { - Geom::Path pth; + } + if ( outside && lineProblem ) { + Geom::Path pth; pth.append(*cbc1); - Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); + Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { + pth.append( *cbc2 ); + Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); + + boost::optional p = intersection_point (cbc1->finalPoint(), tang1, + cbc2->initialPoint(), tang2); + if (p) { //check size of miter Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; Geom::Coord len = distance(*p, point_on_path); @@ -306,13 +297,13 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } path_builder.appendNew (endPt); - } - if ( !outside ) { - path_builder.appendNew (endPt); - } + } + if ( !outside ) { + path_builder.appendNew (endPt); + } } -void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, +void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, double miter_limit, double line_width, bool outside = false) { //the most important work for the reflected join is done here @@ -320,7 +311,7 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb //determine where we are in the path. If we're on the inside, ignore //and just lineTo. On the outside, we'll do a little reflection magic :) Geom::Crossings cross; - + if (outside) { Geom::Path pth; pth.append(*cbc1); @@ -347,9 +338,8 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb if ( cross.empty() ) { //curves didn't cross; default to miter boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) - { + cbc2->initialPoint(), tang2); + if (p) { //check size of miter Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; Geom::Coord len = distance(*p, point_on_path); @@ -388,27 +378,26 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double // NOTE: it is important to notice the distinction between a Geom::Path and a livarot Path here! // if you do not see "Geom::" there is a different function set! Geom::PathVector pv = split_at_cusps(path_in); - + Path to_outline; Path outlined_result; - + Geom::Path path_builder = Geom::Path(); //the path to store the result in Geom::PathVector * path_vec; //needed because livarot returns a goddamn pointer - + const unsigned k = path_in.size(); - - for (unsigned u = 0; u < k; u+=2) - { + + for (unsigned u = 0; u < k; u+=2) { to_outline = Path(); outlined_result = Path(); - + to_outline.LoadPath(pv[u], Geom::Affine(), false, false); to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); //now a curve has been outside outlined and loaded into outlined_result - + //get the Geom::Path path_vec = outlined_result.MakePathVector(); - + //thing to do on the first run through if (u == 0) { //I could use the pv->operator[] (0) notation but that looks terrible @@ -417,58 +406,64 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double //get the curves ready for the operation Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); - + //do the reflection/extrapolation: - if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } - else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } + if (extrapolate) { + extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); + } else { + reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); + } } - + path_builder.append( (*path_vec)[0] ); - + //outline the next segment, but don't store it yet if (path_vec) delete path_vec; - + if (u < k - 1) { outlined_result = Path(); to_outline = Path(); - + to_outline.LoadPath(pv[u+1], Geom::Affine(), false, false); to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); - + path_vec = outlined_result.MakePathVector(); - + //get the curves ready for the operation Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); - + //do the reflection/extrapolation: - if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); } - else { reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); } - + if (extrapolate) { + extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); + } else { + reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, + outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); + } + //Now we can store it. path_builder.append( (*path_vec)[0] ); - + if (cbc1) delete cbc1; if (cbc2) delete cbc2; if (path_vec) delete path_vec; } } - + return path_builder; } -Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, +Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtType butt, double miter_lim, bool extrapolate) { Geom::PathVector path_out; - + unsigned pv_size = path_in.size(); for (unsigned i = 0; i < pv_size; i++) { - + if (path_in[i].size() > 1) { //since you've made it this far, hopefully all this is obvious :P Geom::Path with_direction; @@ -484,8 +479,8 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, newPath = Geom::path_from_piecewise(pwd2, 0.01)[0]; //fuk this with_direction = Outline::doAdvHalfOutline( newPath, -line_width, miter_lim, extrapolate ); - against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); - + against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); + /*if (dynamic_cast *>(&newPath[newPath.size()])) { //delete the 'Z' newPath.erase_last(); @@ -497,54 +492,54 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, newPath.erase_last(); newPath.append(path_in[i][path_in[i].size() - 1]); newPath.appendNew(newPath.initialPoint()); - newPath.erase_last(); + newPath.erase_last(); }*/ } Geom::PathBuilder pb; - + //add in the...do I really need to say this? pb.moveTo(with_direction.initialPoint()); pb.append(with_direction); - + //add in our line caps if (!path_in[i].closed()) { switch (butt) { - case butt_straight: - pb.lineTo(against_direction.initialPoint()); - break; - case butt_round: - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); - break; - case butt_pointy: - //I have ZERO idea what to do here. - pb.lineTo(against_direction.initialPoint()); - break; - case butt_square: - pb.lineTo(against_direction.initialPoint()); - break; + case butt_straight: + pb.lineTo(against_direction.initialPoint()); + break; + case butt_round: + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); + break; + case butt_pointy: + //I have ZERO idea what to do here. + pb.lineTo(against_direction.initialPoint()); + break; + case butt_square: + pb.lineTo(against_direction.initialPoint()); + break; } } else { pb.moveTo(against_direction.initialPoint()); } - + pb.append(against_direction); - + //cap (if necessary) if (!path_in[i].closed()) { switch (butt) { - case butt_straight: - pb.lineTo(with_direction.initialPoint()); - break; - case butt_round: - pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); - break; - case butt_pointy: - //I have ZERO idea what to do here. - pb.lineTo(with_direction.initialPoint()); - break; - case butt_square: - pb.lineTo(with_direction.initialPoint()); - break; + case butt_straight: + pb.lineTo(with_direction.initialPoint()); + break; + case butt_round: + pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); + break; + case butt_pointy: + //I have ZERO idea what to do here. + pb.lineTo(with_direction.initialPoint()); + break; + case butt_square: + pb.lineTo(with_direction.initialPoint()); + break; } } pb.flush(); @@ -554,7 +549,7 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, } else { Path p = Path(); Path outlinepath = Path(); - + p.LoadPath(path_in[i], Geom::Affine(), false, false); p.Outline(&outlinepath, line_width / 2, static_cast(join), butt, miter_lim); Geom::PathVector *pv_p = outlinepath.MakePathVector(); diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h index 23cc7e2c4..27bc62d45 100644 --- a/src/live_effects/pathoutlineprovider.h +++ b/src/live_effects/pathoutlineprovider.h @@ -12,15 +12,15 @@ enum LineJoinType { LINEJOIN_EXTRAPOLATED }; -namespace Outline +namespace Outline { - unsigned bezierOrder (const Geom::Curve* curve_in); - std::vector PathVectorOutline(std::vector const & path_in, double line_width, ButtType linecap_type, - LineJoinType linejoin_type, double miter_limit); - - Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, - ButtType butt, double miter_lim, bool extrapolate = false); - Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); + unsigned bezierOrder (const Geom::Curve* curve_in); + std::vector PathVectorOutline(std::vector const & path_in, double line_width, ButtType linecap_type, + LineJoinType linejoin_type, double miter_limit); + + /*Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, + ButtType butt, double miter_lim, bool extrapolate = false);*/ + Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); } #endif // _SEEN_PATH_OUTLINE_H -- cgit v1.2.3 From b7c026006efcc5461dcef0f3c9a5e1b87d162d3d Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 2 Apr 2014 17:33:37 -0400 Subject: Hopefully remove the last of the exception throwing with certain path effects (bzr r13090.1.43) --- src/live_effects/pathoutlineprovider.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index ad39a7416..56f741417 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -250,17 +250,21 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + try { + if (arc0) { + path_builder.append (arc0->toSBasis()); + delete arc0; + arc0 = NULL; + } - if (arc0) { - path_builder.append (arc0->toSBasis()); - delete arc0; - arc0 = NULL; - } - - if (arc1) { - path_builder.append (arc1->toSBasis()); - delete arc1; - arc1 = NULL; + if (arc1) { + path_builder.append (arc1->toSBasis()); + delete arc1; + arc1 = NULL; + } + } catch (std::exception ex) { + printf("Exception occured, probably NaN or infinite valued points: %s\n", ex.what()); + path_builder.appendNew(endPt); } } else { boost::optional p = intersection_point (cbc1->finalPoint(), tang1, -- cgit v1.2.3 From b2f138290a5dedf907fe3e67d12ab93adfd5fd50 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 2 Apr 2014 21:49:11 -0400 Subject: Fix some minor issues (bzr r13090.1.44) --- src/live_effects/lpe-taperstroke.cpp | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 97ae02e3b..c452c825c 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -248,7 +248,7 @@ Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_toler Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double width); //references to pointers, because magic -void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); +void subdivideCurve(const Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) { @@ -269,7 +269,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) } } - //don't ever let it be zero + //don't let it be zero if (attach_start <= 0.00000001) { attach_start.param_set_value( 0.00000001 ); zeroStart = true; @@ -329,12 +329,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) throwaway_path = Outline::PathOutsideOutline(pathv_out[1], -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - if (!zeroStart) { - throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path); - } else { - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - } + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); if (!zeroEnd) { //append the ending taper @@ -346,25 +341,17 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; - throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path); + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); } //append the inside outline of the path (against direction) throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - if (!zeroEnd) { - //throwaway_path.setInitial(real_path.finalPoint()); - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - } else { - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - } - - //hmm - real_path.setFinal(real_path.initialPoint()); - - real_path.close(); + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + real_path.appendNew(real_path.initialPoint()); + real_path.close(); + real_pathv.push_back(real_path); return real_pathv; -- cgit v1.2.3 From 4007abe02509fc1e312a007fb26f31c5a595df26 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 3 Apr 2014 21:04:51 -0400 Subject: Begin first stage of resolving issue with duplicate knots (bzr r13090.1.46) --- src/live_effects/lpe-taperstroke.cpp | 10 ++++++++++ src/live_effects/pathoutlineprovider.cpp | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index c452c825c..dc70782c4 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -657,6 +657,11 @@ void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point con Geom::Point const s = snap_knot_position(p, state); SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); + if (!curve) { + //oops + lpe->attach_start.param_set_value(0); + return; + } Geom::PathVector pathv = curve->get_pathvector(); Piecewise > pwd2; Geom::Path p_in = return_at_first_cusp(pathv[0]); @@ -678,6 +683,11 @@ void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const Geom::Point const s = snap_knot_position(p, state); SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); + if (!curve) { + //oops + lpe->attach_end.param_set_value(0); + return; + } Geom::PathVector pathv = curve->get_pathvector(); Piecewise > pwd2; Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index 56f741417..a696728d6 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -1,3 +1,5 @@ +#include //g_critical + #include "pathoutlineprovider.h" #include "livarot/path-description.h" #include <2geom/angle.h> @@ -262,7 +264,7 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve delete arc1; arc1 = NULL; } - } catch (std::exception ex) { + } catch (std::exception & ex) { printf("Exception occured, probably NaN or infinite valued points: %s\n", ex.what()); path_builder.appendNew(endPt); } -- cgit v1.2.3 From 6f10c7f675fae8c20f24f01b7cffb861f3726e9d Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 6 Apr 2014 17:38:30 -0400 Subject: Properly allow effect stacking with knotholders (and add extra LPE functionality) (bzr r13090.1.48) --- src/live_effects/effect.cpp | 18 +++++++++ src/live_effects/effect.h | 8 ++++ src/live_effects/lpe-attach-path.cpp | 11 ++---- src/live_effects/lpe-attach-path.h | 2 - src/live_effects/lpe-knot.cpp | 4 ++ src/live_effects/lpe-knot.h | 3 +- src/live_effects/lpe-tangent_to_curve.cpp | 19 ++++------ src/live_effects/lpe-tangent_to_curve.h | 1 - src/live_effects/lpe-taperstroke.cpp | 62 +++++++++++++++---------------- 9 files changed, 74 insertions(+), 54 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 8bf210270..99282a312 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -373,6 +373,24 @@ void Effect::doOnRemove (SPLPEItem const* lpeitem) { } +//secret impl methods (shhhh!) +void Effect::doOnApply_impl(SPLPEItem const* lpeitem) +{ + sp_lpe_item = const_cast(lpeitem); + sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); + pathvector_before_effect = sp_curve->get_pathvector(); + doOnApply(lpeitem); +} + +void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) +{ + sp_lpe_item = const_cast(lpeitem); + sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); + pathvector_before_effect = sp_curve->get_pathvector(); + + doBeforeEffect(lpeitem); +} + /** * Effects can have a parameter path set before they are applied by accepting a nonzero number of * mouse clicks. This method activates the pen context, which waits for the specified number of diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 85c930def..d2d9f3b63 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -53,6 +53,11 @@ public: EffectType effectType() const; + //basically, to get this method called before the derived classes, a bit + //of indirection is needed. We first call these methods, then the below. + void doOnApply_impl(SPLPEItem const* lpeitem); + void doBeforeEffect_impl(SPLPEItem const* lpeitem); + virtual void doOnApply (SPLPEItem const* lpeitem); virtual void doBeforeEffect (SPLPEItem const* lpeitem); @@ -149,6 +154,9 @@ protected: // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. bool concatenate_before_pwd2; + SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. + SPCurve * sp_curve; + std::vector pathvector_before_effect; private: bool provides_own_flash_paths; // if true, the standard flash path is suppressed diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index 0cceb1cb7..96372892e 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -62,15 +62,10 @@ void LPEAttachPath::resetDefaults(SPItem const * item) curve_end_previous_origin = end_path_curve_end.getOrigin(); } -void LPEAttachPath::doBeforeEffect(SPLPEItem const *lpeitem) -{ - lpe_effect = const_cast (lpeitem); -} - void LPEAttachPath::doEffect (SPCurve * curve) { std::vector this_pathv = curve->get_pathvector(); - if (lpe_effect && !this_pathv.empty()) { + if (sp_lpe_item && !this_pathv.empty()) { Geom::Path p = Geom::Path(this_pathv.front().initialPoint()); bool set_start_end = start_path_curve_end.getOrigin() != curve_start_previous_origin; @@ -79,7 +74,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) if (start_path.linksToPath()) { std::vector linked_pathv = start_path.get_pathvector(); - Geom::Affine linkedtransform = start_path.getObject()->getRelativeTransform(lpe_effect); + Geom::Affine linkedtransform = start_path.getObject()->getRelativeTransform(sp_lpe_item); if ( !linked_pathv.empty() ) { @@ -132,7 +127,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) if (end_path.linksToPath()) { std::vector linked_pathv = end_path.get_pathvector(); - Geom::Affine linkedtransform = end_path.getObject()->getRelativeTransform(lpe_effect); + Geom::Affine linkedtransform = end_path.getObject()->getRelativeTransform(sp_lpe_item); if ( !linked_pathv.empty() ) { diff --git a/src/live_effects/lpe-attach-path.h b/src/live_effects/lpe-attach-path.h index 390282f90..1d6c590d1 100644 --- a/src/live_effects/lpe-attach-path.h +++ b/src/live_effects/lpe-attach-path.h @@ -25,7 +25,6 @@ public: LPEAttachPath(LivePathEffectObject *lpeobject); virtual ~LPEAttachPath(); - virtual void doBeforeEffect(const SPLPEItem *lpeitem); virtual void doEffect (SPCurve * curve); virtual void resetDefaults(SPItem const * item); @@ -45,7 +44,6 @@ private: ScalarParam end_path_position; TransformedPointParam end_path_curve_start; VectorParam end_path_curve_end; - SPLPEItem * lpe_effect; }; }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 581c632f5..05b6ed795 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -538,6 +538,10 @@ LPEKnot::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); + + if (SP_IS_PATH(lpeitem)) { + supplied_path = SP_PATH(lpeitem)->getCurve()->get_pathvector(); + } gpaths = std::vector(); gstroke_widths = std::vector(); diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h index b937f9021..12ab32e5b 100644 --- a/src/live_effects/lpe-knot.h +++ b/src/live_effects/lpe-knot.h @@ -64,7 +64,8 @@ public: void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); protected: - virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); + std::vector supplied_path; //for knotholder business private: void updateSwitcher(); diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp index dbebdf7fb..bce4876af 100644 --- a/src/live_effects/lpe-tangent_to_curve.cpp +++ b/src/live_effects/lpe-tangent_to_curve.cpp @@ -16,8 +16,6 @@ #include #include "live_effects/lpe-tangent_to_curve.h" -// FIXME: The following are only needed to convert the path's SPCurve* to pwd2. -// There must be a more convenient way to achieve this. #include "sp-path.h" #include "display/curve.h" @@ -108,13 +106,13 @@ LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desk { KnotHolderEntity *e = new TtC::KnotHolderEntityLeftEnd(this); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Adjust the \"left\" end of the tangent") ); + _("Adjust the left end of the tangent") ); knotholder->add(e); } { KnotHolderEntity *e = new TtC::KnotHolderEntityRightEnd(this); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Adjust the \"right\" end of the tangent") ); + _("Adjust the right end of the tangent") ); knotholder->add(e); } }; @@ -130,14 +128,13 @@ KnotHolderEntityAttachPt::knot_set(Geom::Point const &p, Geom::Point const &/*or Geom::Point const s = snap_knot_position(p, state); - // FIXME: There must be a better way of converting the path's SPCurve* to pwd2. - SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); - Geom::PathVector pathv = curve->get_pathvector(); - Piecewise > pwd2; - for (unsigned int i=0; i < pathv.size(); i++) { - pwd2.concat(pathv[i].toPwSb()); + if ( !SP_IS_SHAPE(lpe->sp_lpe_item) ) { + //lpe->t_attach.param_set_value(0); + g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); + return; } - + Piecewise > pwd2 = paths_to_pw( lpe->pathvector_before_effect ); + double t0 = nearest_point(s, pwd2); lpe->t_attach.param_set_value(t0); diff --git a/src/live_effects/lpe-tangent_to_curve.h b/src/live_effects/lpe-tangent_to_curve.h index 309afc14b..8e44c01d1 100644 --- a/src/live_effects/lpe-tangent_to_curve.h +++ b/src/live_effects/lpe-tangent_to_curve.h @@ -34,7 +34,6 @@ class LPETangentToCurve : public Effect { public: LPETangentToCurve(LivePathEffectObject *lpeobject); virtual ~LPETangentToCurve(); - virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index dc70782c4..901abff70 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -235,9 +235,11 @@ Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_toler } //clearly it's collinear if two occupy the same point - g_assert(!are_near(start_point, cross_point, 0.0000001)); - g_assert(!are_near(cross_point, end_point, 0.0000001)); - g_assert(!are_near(start_point, end_point, 0.0000001)); + if (are_near(start_point, cross_point, 0.0000001) || + are_near(cross_point, end_point, 0.0000001) || + are_near(start_point, end_point, 0.0000001) ) { + g_critical("Holy crap, something went wrong! %s:%d\n", __FILE__, __LINE__); + } if (!are_collinear(start_point, cross_point, end_point, smooth_tolerance)) break; @@ -533,12 +535,6 @@ Geom::Piecewise > stretch_along(Geom::Piecewiseextent(); - noffset *= pattBndsY->extent(); - toffset *= pattBndsX->extent(); - }*/ - //Prevent more than 90% overlap... if (xspace < -pattBndsX->extent()*.9) { xspace = -pattBndsX->extent()*.9; @@ -587,12 +583,6 @@ Geom::Piecewise > stretch_along(Geom::Piecewiseget_curve_for_edit(); - if (!curve) { + if (!SP_IS_SHAPE(lpe->sp_lpe_item) ) { + g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); + return; + } + + SPCurve* curve; + if ( !(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve()) ) { //oops - lpe->attach_start.param_set_value(0); + //lpe->attach_start.param_set_value(0); return; } - Geom::PathVector pathv = curve->get_pathvector(); + //in case you are wondering, the above are simply sanity checks. we never want to actually + //use that object. + + Geom::PathVector pathv = lpe->pathvector_before_effect; + Piecewise > pwd2; Geom::Path p_in = return_at_first_cusp(pathv[0]); pwd2.concat(p_in.toPwSb()); - std::vector > > pwd_vec = split_at_discontinuities(pwd2); - double t0 = nearest_point(s, pwd_vec[0]); + double t0 = nearest_point(s, pwd2); lpe->attach_start.param_set_value(t0); // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. @@ -682,22 +680,24 @@ void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const Geom::Point const s = snap_knot_position(p, state); - SPCurve *curve = SP_PATH(item)->get_curve_for_edit(); - if (!curve) { + if (!SP_IS_SHAPE(lpe->sp_lpe_item) ) { + g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); + return; + } + + SPCurve* curve; + if ( !(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve()) ) { //oops - lpe->attach_end.param_set_value(0); + //lpe->attach_end.param_set_value(0); return; } - Geom::PathVector pathv = curve->get_pathvector(); - Piecewise > pwd2; + Geom::PathVector pathv = lpe->pathvector_before_effect; Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); - pwd2.concat(p_in.toPwSb()); - std::vector > > pwd_vec = split_at_discontinuities(pwd2); - - double t0 = nearest_point(s, pwd_vec[0]); + Piecewise > pwd2 = p_in.toPwSb(); + + double t0 = nearest_point(s, pwd2); lpe->attach_end.param_set_value(t0); - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); } Geom::Point KnotHolderEntityAttachBegin::knot_get() const -- cgit v1.2.3 From a354238633c206078acc11a60d02382cee572740 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 12 Apr 2014 00:52:48 -0400 Subject: Wonderful code optimizations (bzr r13090.1.50) --- src/live_effects/lpe-taperstroke.cpp | 153 +++---------------------------- src/live_effects/pathoutlineprovider.cpp | 79 ++++++---------- src/live_effects/pathoutlineprovider.h | 6 ++ 3 files changed, 46 insertions(+), 192 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 901abff70..ce07ed962 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -180,77 +180,15 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) //actual effect impl here -Geom::Path return_at_first_cusp (Geom::Path const & path_in, double smooth_tolerance = 0.05) +Geom::Path return_at_first_cusp (Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) { - Geom::Path path_out = Geom::Path(); - - for (unsigned i = 0; i < path_in.size(); i++) { - path_out.append(path_in[i]); - if (path_in.size() == 1) - break; - - //determine order of curve - int order = Outline::bezierOrder(&path_in[i]); - - Geom::Point start_point; - Geom::Point cross_point = path_in[i].finalPoint(); - Geom::Point end_point; - - g_assert(path_in[i].finalPoint() == path_in[i+1].initialPoint()); - - //can you tell that the following expressions have been shaped by - //repeated compiler errors? ;) - switch (order) { - case 3: - start_point = (static_cast(&path_in[i]))->operator[] (2); - //major league b***f***ing - if (are_near(start_point, cross_point, 0.0000001)) { - start_point = (static_cast(&path_in[i]))->operator[] (1); - } - break; - case 2: - //this never happens - start_point = (static_cast(&path_in[i]))->operator[] (1); - break; - case 1: - default: - start_point = path_in[i].initialPoint(); - } - - order = Outline::bezierOrder(&path_in[i+1]); - - switch (order) { - case 3: - end_point = (static_cast(&path_in[i+1]))->operator[] (1); - if (are_near(end_point, cross_point, 0.0000001)) { - end_point = (static_cast(&path_in[i+1]))->operator[] (2); - } - break; - case 2: - end_point = (static_cast(&path_in[i+1]))->operator[] (1); - break; - case 1: - default: - end_point = path_in[i+1].finalPoint(); - } - - //clearly it's collinear if two occupy the same point - if (are_near(start_point, cross_point, 0.0000001) || - are_near(cross_point, end_point, 0.0000001) || - are_near(start_point, end_point, 0.0000001) ) { - g_critical("Holy crap, something went wrong! %s:%d\n", __FILE__, __LINE__); - } - - if (!are_collinear(start_point, cross_point, end_point, smooth_tolerance)) - break; - } - return path_out; + return Geom::split_at_cusps(path_in)[0]; } Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double width); //references to pointers, because magic -void subdivideCurve(const Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); +void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) { @@ -378,34 +316,9 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa trimmed_start.append(path_in[0] [i]); } - - //this is pretty annoying - //previously I wrote a function for this but it wasted a lot of time - //so I optimized it back into here. - unsigned order = Outline::bezierOrder(curve_start); - switch (order) { - case 3: { - Geom::CubicBezier *cb = static_cast(curve_start); - std::pair cb_pair = cb->subdivide((attach_start - loc)); - trimmed_start.append(cb_pair.first); - curve_start = cb_pair.second.duplicate(); //goes out of scope - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_start); - std::pair qb_pair = qb->subdivide((attach_start - loc)); - trimmed_start.append(qb_pair.first); - curve_start = qb_pair.second.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide((attach_start - loc)); - trimmed_start.append(lb_pair.first); - curve_start = lb_pair.second.duplicate(); - break; - } - } + Geom::Curve * temp; + subdivideCurve(curve_start, attach_start - loc, temp, curve_start); + trimmed_start.append(*temp); //special case: path is one segment long //special case: what if the two knots occupy the same segment? @@ -416,31 +329,9 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa //we have to do some shifting here because the value changed when we reduced the length //of the previous segment. - order = Outline::bezierOrder(curve_start); - switch (order) { - case 3: { - Geom::CubicBezier *cb = static_cast(curve_start); - std::pair cb_pair = cb->subdivide(t); - trimmed_end.append(cb_pair.second); - curve_start = cb_pair.first.duplicate(); - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_start); - std::pair qb_pair = qb->subdivide(t); - trimmed_end.append(qb_pair.second); - curve_start = qb_pair.first.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_start); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); - trimmed_end.append(lb_pair.second); - curve_start = lb_pair.first.duplicate(); - break; - } - } - + subdivideCurve(curve_start, t, curve_start, temp); + trimmed_end.append(*temp); + for (unsigned j = (size - attach_end) + 1; j < size; j++) { trimmed_end.append(path_in[0] [j]); } @@ -468,30 +359,8 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_end); - order = Outline::bezierOrder(curve_end); - switch (order) { - case 3: { - Geom::CubicBezier *cb = static_cast(curve_end); - std::pair cb_pair = cb->subdivide(t); - trimmed_end.append(cb_pair.second); - curve_end = cb_pair.first.duplicate(); - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_end); - std::pair qb_pair = qb->subdivide(t); - trimmed_end.append(qb_pair.second); - curve_end = qb_pair.first.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_end); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); - trimmed_end.append(lb_pair.second); - curve_end = lb_pair.first.duplicate(); - break; - } - } + subdivideCurve(curve_end, t, curve_end, temp); + trimmed_end.append(*temp); for (unsigned j = (size - attach_end) + 1; j < size; j++) { trimmed_end.append(path_in[0] [j]); diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index a696728d6..5a95da75d 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -9,6 +9,7 @@ #include <2geom/shape.h> #include <2geom/transforms.h> #include <2geom/path-sink.h> +#include "helper/geom-nodetype.h" #include namespace Geom { @@ -99,21 +100,25 @@ static Circle touching_circle( D2 const &curve, double t, double tol=0.0 return Geom::Circle(center, fabs(radius)); } -static std::vector split_at_cusps(const Geom::Path& in) +std::vector split_at_cusps(const Geom::Path& in) { - Geom::PathVector out = Geom::PathVector(); - Geom::Path temp = Geom::Path(); - - for (unsigned path_descr = 0; path_descr < in.size(); path_descr++) { - temp = Geom::Path(); - temp.append(in[path_descr]); + PathVector out = PathVector(); + Path temp = Path(); + + for (unsigned i = 0; i < in.size(); i++) { + temp.append(in[i]); + if ( get_nodetype(in[i], in[i + 1]) != Geom::NODE_SMOOTH ) { + out.push_back(temp); + temp = Path(); + } + } + if (temp.size() > 0) { out.push_back(temp); } - return out; } -static Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) +Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in) { std::vector temp; sbasis_to_bezier(temp, sbasis_in, 4); @@ -140,13 +145,9 @@ typedef Geom::Piecewise PWD2; unsigned bezierOrder (const Geom::Curve* curve_in) { using namespace Geom; - //cast it - const CubicBezier *cbc = dynamic_cast(curve_in); - if (cbc) return 3; - const QuadraticBezier * qbc = dynamic_cast(curve_in); - if (qbc) return 2; - const BezierCurveN<1U> * lbc = dynamic_cast *>(curve_in); - if (lbc) return 1; + if ( const BezierCurve* bz = dynamic_cast(curve_in) ) { + return bz->order(); + } return 0; } @@ -154,8 +155,6 @@ unsigned bezierOrder (const Geom::Curve* curve_in) //is >180 clockwise, otherwise false. bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) { - unsigned order = bezierOrder(&cbc1); - Geom::Point start_point; Geom::Point cross_point = cbc1.finalPoint(); Geom::Point end_point; @@ -167,38 +166,18 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); return false; } - switch (order) { - case 3: - start_point = (static_cast(&cbc1))->operator[] (2); - //major league b***f***ing - if (are_near(start_point, cross_point, 0.0000001)) { - start_point = (static_cast(&cbc1))->operator[] (1); - } - break; - case 2: - //this never happens - start_point = (static_cast(&cbc1))->operator[] (1); - break; - case 1: - default: - start_point = cbc1.initialPoint(); + + //let's try: + Geom::CubicBezier cubicBezier = Geom::sbasis_to_cubicbezier(cbc1.toSBasis()); + start_point = cubicBezier [2]; + //stupid thing Inkscape does: + if (are_near(start_point, cross_point, 0.0000001)) { + start_point = cubicBezier [1]; } - - order = Outline::bezierOrder(&cbc2); - - switch (order) { - case 3: - end_point = (static_cast(&cbc2))->operator[] (1); - if (are_near(end_point, cross_point, 0.0000001)) { - end_point = (static_cast(&cbc2))->operator[] (2); - } - break; - case 2: - end_point = (static_cast(&cbc2))->operator[] (1); - break; - case 1: - default: - end_point = cbc2.finalPoint(); + cubicBezier = Geom::sbasis_to_cubicbezier(cbc2.toSBasis()); + end_point = cubicBezier [1]; + if (are_near(end_point, cross_point, 0.0000001)) { + end_point = cubicBezier [2]; } //got our three points, now let's see what their clockwise angle is @@ -391,7 +370,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double Geom::Path path_builder = Geom::Path(); //the path to store the result in Geom::PathVector * path_vec; //needed because livarot returns a goddamn pointer - const unsigned k = path_in.size(); + const unsigned k = pv.size(); for (unsigned u = 0; u < k; u+=2) { to_outline = Path(); diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h index 27bc62d45..0ee0f261e 100644 --- a/src/live_effects/pathoutlineprovider.h +++ b/src/live_effects/pathoutlineprovider.h @@ -12,6 +12,12 @@ enum LineJoinType { LINEJOIN_EXTRAPOLATED }; +namespace Geom +{ + Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in); + std::vector split_at_cusps(const Geom::Path& in); +} + namespace Outline { unsigned bezierOrder (const Geom::Curve* curve_in); -- cgit v1.2.3 From 727826e1fdd2c4142b1687e50c174ed14c178427 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 12 Apr 2014 14:18:31 -0400 Subject: Fix triangles in joins (bzr r13090.1.52) --- src/live_effects/lpe-taperstroke.cpp | 58 ++++++++++++++------------------ src/live_effects/pathoutlineprovider.cpp | 45 +++++++++++++++++++++---- 2 files changed, 65 insertions(+), 38 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index ce07ed962..2400b3e37 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -197,6 +197,8 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) bool zeroStart = false; bool zeroEnd = false; + bool metInMiddle = false; + //there is a pretty good chance that people will try to drag the knots //on top of each other, so block it @@ -208,6 +210,10 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) attach_end.param_set_value( size - attach_start ); } } + + if (attach_start == size - attach_end) { + metInMiddle = true; + } //don't let it be zero if (attach_start <= 0.00000001) { @@ -232,10 +238,10 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //don't let the knots be farther than they are allowed to be if ((unsigned)attach_start >= allowed_start) { - attach_start.param_set_value((double)allowed_start - 0.00000001); + attach_start.param_set_value((double)allowed_start - 0.00001); } if ((unsigned)attach_end >= allowed_end) { - attach_end.param_set_value((double)allowed_end - 0.00000001); + attach_end.param_set_value((double)allowed_end - 0.00001); } //remember, Path::operator () means get point at time t @@ -265,11 +271,14 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) real_path.append(throwaway_path); } - //append the outside outline of the path (with direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1], - -fabs(line_width), static_cast(join_type.get_value()), miter_limit); + + if (!metInMiddle) { + //append the outside outline of the path (with direction) + throwaway_path = Outline::PathOutsideOutline(pathv_out[1], + -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + } if (!zeroEnd) { //append the ending taper @@ -460,32 +469,17 @@ Geom::Piecewise > stretch_along(Geom::Piecewise(curve_in); - std::pair cb_pair = cb->subdivide(t); - //trimmed_start.append(cb_pair.first); - val_first = cb_pair.first.duplicate(); - val_second = cb_pair.second.duplicate(); - break; - } - case 2: { - Geom::QuadraticBezier *qb = static_cast(curve_in); - std::pair qb_pair = qb->subdivide(t); - //trimmed_start.append(qb_pair.first); - val_first = qb_pair.first.duplicate(); - val_second = qb_pair.second.duplicate(); - break; - } - case 1: { - Geom::BezierCurveN<1> *lb = static_cast * >(curve_in); - std::pair, Geom::BezierCurveN<1> > lb_pair = lb->subdivide(t); - //trimmed_start.append(lb_pair.first); - val_first = lb_pair.first.duplicate(); - val_second = lb_pair.second.duplicate(); - break; - } + if (Geom::LineSegment* linear = dynamic_cast(curve_in)) { + //special case for line segments + std::pair seg_pair = linear->subdivide(t); + val_first = seg_pair.first.duplicate(); + val_second = seg_pair.second.duplicate(); + } else { + //all other cases: + Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(curve_in->toSBasis()); + std::pair cubic_pair = cubic.subdivide(t); + val_first = cubic_pair.first.duplicate(); + val_second = cubic_pair.second.duplicate(); } } diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index 5a95da75d..080f42c08 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -261,6 +261,7 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } path_builder.appendNew (endPt); } + path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); } if ( outside && lineProblem ) { Geom::Path pth; @@ -282,9 +283,22 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } path_builder.appendNew (endPt); + path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); } if ( !outside ) { - path_builder.appendNew (endPt); + /*path_builder.appendNew (endPt);*/ + Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); + if (!cross.empty()) { + path_builder.erase_last(); + Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(cbc1->toSBasis()); + cubic = cubic.subdivide(cross[0].ta).first; + path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); + cubic = Geom::sbasis_to_cubicbezier(cbc2->toSBasis()); + cubic = cubic.subdivide(cross[0].tb).second; + path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); + } else { + path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); + } } } @@ -346,9 +360,22 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); } - } else { // cross.empty() + path_builder.append(*cbc2); + } else { //probably on the inside of the corner - path_builder.appendNew ( endPt ); + /*path_builder.appendNew ( endPt );*/ + cross = Geom::crossings(*cbc1, *cbc2); + if (!cross.empty()) { + path_builder.erase_last(); + Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(cbc1->toSBasis()); + cubic = cubic.subdivide(cross[0].ta).first; + path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); + cubic = Geom::sbasis_to_cubicbezier(cbc2->toSBasis()); + cubic = cubic.subdivide(cross[0].tb).second; + path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); + } else { + path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); + } } } @@ -387,6 +414,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double if (u == 0) { //I could use the pv->operator[] (0) notation but that looks terrible path_builder.start( (*path_vec)[0].initialPoint() ); + path_builder.append( (*path_vec)[0] ); } else { //get the curves ready for the operation Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); @@ -400,10 +428,12 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } + Geom::Path temp_path = (*path_vec)[0]; + temp_path.erase(temp_path.begin()); + + path_builder.append( temp_path ); } - path_builder.append( (*path_vec)[0] ); - //outline the next segment, but don't store it yet if (path_vec) delete path_vec; @@ -430,7 +460,10 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double } //Now we can store it. - path_builder.append( (*path_vec)[0] ); + Geom::Path temp_path = (*path_vec)[0]; + temp_path.erase(temp_path.begin()); + + path_builder.append( temp_path ); if (cbc1) delete cbc1; if (cbc2) delete cbc2; -- cgit v1.2.3 From e36987cea4199ec3e51becad59b88e36c75e0955 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 12 Apr 2014 14:38:11 -0400 Subject: Fix memory leak (bzr r13090.1.53) --- src/live_effects/lpe-taperstroke.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 2400b3e37..8316daf71 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -328,6 +328,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa Geom::Curve * temp; subdivideCurve(curve_start, attach_start - loc, temp, curve_start); trimmed_start.append(*temp); + if (temp) delete temp; temp = 0; //special case: path is one segment long //special case: what if the two knots occupy the same segment? @@ -340,6 +341,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa subdivideCurve(curve_start, t, curve_start, temp); trimmed_end.append(*temp); + if (temp) delete temp; temp = 0; for (unsigned j = (size - attach_end) + 1; j < size; j++) { trimmed_end.append(path_in[0] [j]); @@ -370,6 +372,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa subdivideCurve(curve_end, t, curve_end, temp); trimmed_end.append(*temp); + if (temp) delete temp; temp = 0; for (unsigned j = (size - attach_end) + 1; j < size; j++) { trimmed_end.append(path_in[0] [j]); -- cgit v1.2.3 From 3a4844ef32ce02cbcb9f1102f61d60914bb48d72 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 12 Apr 2014 18:58:48 -0400 Subject: Enable line caps (bzr r13090.1.54) --- src/live_effects/pathoutlineprovider.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index 080f42c08..d7f5362aa 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -528,14 +528,23 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, case butt_round: pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); break; - case butt_pointy: - //I have ZERO idea what to do here. + case butt_pointy: { + Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); + double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); + Geom::Point midpoint = 0.5 * (with_direction.finalPoint() + against_direction.initialPoint()) + radius*end_deriv; + pb.lineTo(midpoint); pb.lineTo(against_direction.initialPoint()); break; - case butt_square: + } + case butt_square: { + Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); + double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); + pb.lineTo(with_direction.finalPoint() + radius*end_deriv); + pb.lineTo(against_direction.initialPoint() + radius*end_deriv); pb.lineTo(against_direction.initialPoint()); break; } + } } else { pb.moveTo(against_direction.initialPoint()); } @@ -551,14 +560,23 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, case butt_round: pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); break; - case butt_pointy: - //I have ZERO idea what to do here. + case butt_pointy: { + Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); + double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); + Geom::Point midpoint = 0.5 * (against_direction.finalPoint() + with_direction.initialPoint()) + radius*end_deriv; + pb.lineTo(midpoint); pb.lineTo(with_direction.initialPoint()); break; - case butt_square: + } + case butt_square: { + Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); + double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); + pb.lineTo(against_direction.finalPoint() + radius*end_deriv); + pb.lineTo(with_direction.initialPoint() + radius*end_deriv); pb.lineTo(with_direction.initialPoint()); break; } + } } pb.flush(); for (unsigned m = 0; i < pb.peek().size(); i++) { -- cgit v1.2.3 From fd29d6366fe47e17b732ec4cc40d40ae1f272e35 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 13 Apr 2014 12:49:05 -0400 Subject: Nothing special (bzr r13090.1.55) --- src/live_effects/pathoutlineprovider.cpp | 49 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index d7f5362aa..d8e416fea 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -389,7 +389,13 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double { // NOTE: it is important to notice the distinction between a Geom::Path and a livarot Path here! // if you do not see "Geom::" there is a different function set! - Geom::PathVector pv = split_at_cusps(path_in); + Geom::Path temporary(path_in); + if (path_in.closed()) { + //this is a terrible solution + temporary.erase_last(); + temporary.close(false); + } + Geom::PathVector pv = split_at_cusps(temporary); Path to_outline; Path outlined_result; @@ -469,6 +475,12 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double if (cbc2) delete cbc2; if (path_vec) delete path_vec; } + if (path_in.closed()) { + temporary = Geom::Path(); + temporary.append(*path_in.end()); + Geom::Path temporary2 = doAdvHalfOutline(temporary, line_width, miter_limit, extrapolate); + path_builder.append(temporary2/*, Geom::Path::STITCH_DISCONTINUOUS*/); + } } return path_builder; @@ -492,25 +504,19 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, } else { //Geom::Path absolutely refuses to do what I want with these Geom::Path newPath = path_in[i]; - newPath.close(false); - Geom::Piecewise > pwd2 = newPath.toPwSb(); - newPath = Geom::path_from_piecewise(pwd2, 0.01)[0]; - //fuk this + if (Geom::distance(newPath.finalPoint(), newPath.initialPoint()) == newPath[newPath.size()].length()) { + Geom::LineSegment linear(newPath.finalPoint(), newPath.initialPoint()); + Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(linear.toSBasis()); + newPath.appendNew(cubic[1], cubic[2], cubic[3]); + } + //newPath.close(false); with_direction = Outline::doAdvHalfOutline( newPath, -line_width, miter_lim, extrapolate ); against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); - - /*if (dynamic_cast *>(&newPath[newPath.size()])) { - //delete the 'Z' - newPath.erase_last(); - newPath.append(path_in[i][path_in[i].size() - 1]); - newPath.appendNew(newPath.initialPoint()); - newPath.erase_last(); - } else { - //delete the 'Z' - newPath.erase_last(); - newPath.append(path_in[i][path_in[i].size() - 1]); - newPath.appendNew(newPath.initialPoint()); - newPath.erase_last(); + /*if (Geom::distance(newPath.finalPoint(), newPath.initialPoint()) != newPath[newPath.size()].length()) { + with_direction.erase_last(); + with_direction.erase_last(); + against_direction.erase(against_direction.begin()); + against_direction.erase(against_direction.begin()); }*/ } Geom::PathBuilder pb; @@ -579,8 +585,9 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, } } pb.flush(); - for (unsigned m = 0; i < pb.peek().size(); i++) { - path_out.push_back(pb.peek()[m]); + path_out.push_back(pb.peek()[0]); + if (path_in[i].closed()) { + path_out.push_back(pb.peek()[1]); } } else { Path p = Path(); @@ -658,8 +665,6 @@ Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, Lin return path_out; } else if (linejoin_type == LINEJOIN_REFLECTED) { //reflected half outline - Geom::PathVector pathvec; - pathvec.push_back(path_in); path_out = doAdvHalfOutline(path_in, line_width, miter_lim, false); return path_out; } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) { -- cgit v1.2.3 From 6f508cfcaa161695711309d3413b90d2b3f44ea0 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 14 Apr 2014 21:50:06 -0400 Subject: Minor things (bzr r13090.1.58) --- src/live_effects/Makefile_insert | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index ac7c33e2f..e2c35c3bd 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -88,12 +88,13 @@ ink_common_sources += \ live_effects/lpe-attach-path.cpp \ live_effects/lpe-attach-path.h \ live_effects/lpe-fill-between-strokes.cpp \ - live_effects/lpe-fill-between-stroke.h \ + live_effects/lpe-fill-between-strokes.h \ live_effects/lpe-fill-between-many.cpp \ live_effects/lpe-fill-between-many.h \ live_effects/lpe-ellipse_5pts.cpp \ live_effects/lpe-ellipse_5pts.h \ live_effects/pathoutlineprovider.cpp \ + live_effects/pathoutlineprovider.h \ live_effects/lpe-jointype.cpp \ live_effects/lpe-jointype.h \ live_effects/lpe-taperstroke.cpp \ -- cgit v1.2.3 From 313863173f0d2f406dd3c36aea90099f22a04531 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 17 Apr 2014 13:58:57 -0400 Subject: Semi-fix for Join type on closed paths (bzr r13090.1.59) --- src/live_effects/pathoutlineprovider.cpp | 78 ++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 33 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index d8e416fea..4836b0d98 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -389,13 +389,8 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double { // NOTE: it is important to notice the distinction between a Geom::Path and a livarot Path here! // if you do not see "Geom::" there is a different function set! - Geom::Path temporary(path_in); - if (path_in.closed()) { - //this is a terrible solution - temporary.erase_last(); - temporary.close(false); - } - Geom::PathVector pv = split_at_cusps(temporary); + + Geom::PathVector pv = split_at_cusps(path_in); Path to_outline; Path outlined_result; @@ -434,6 +429,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); } + //store it Geom::Path temp_path = (*path_vec)[0]; temp_path.erase(temp_path.begin()); @@ -475,11 +471,44 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double if (cbc2) delete cbc2; if (path_vec) delete path_vec; } - if (path_in.closed()) { - temporary = Geom::Path(); - temporary.append(*path_in.end()); - Geom::Path temporary2 = doAdvHalfOutline(temporary, line_width, miter_limit, extrapolate); - path_builder.append(temporary2/*, Geom::Path::STITCH_DISCONTINUOUS*/); + } + + if (path_in.closed()) { + if ( path_in[path_in.size() - 1].length() != Geom::distance(path_in[path_in.size() - 1].finalPoint(), path_in.initialPoint())) { + //handle case for last segment curved + outlined_result = Path(); + to_outline = Path(); + + Geom::Path oneCurve; oneCurve.append(path_in[0]); + + to_outline.LoadPath(oneCurve, Geom::Affine(), false, false); + to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); + + path_vec = outlined_result.MakePathVector(); + + Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate();//(*path_vec)[0] [0].duplicate(); + Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate();//path_builder[path_builder.size() - 1].duplicate(); + + Geom::Path temporary; //why do we need this? you'll see in a bit + temporary.append(*cbc1); + + if (extrapolate) { + extrapolate_curves(temporary, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, + outside_angle ( path_in[path_in.size() - 1], path_in [0] )); + } else { + reflect_curves (temporary, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, + outside_angle ( path_in[path_in.size() - 1], path_in [0] )); + } + //extract the appended curves + if (temporary[0].finalPoint() != path_builder[path_builder.size() - 1].finalPoint()) { + path_builder.erase(path_builder.begin()); + } else { + temporary.erase_last(); + } + path_builder.erase_last(); + + path_builder.append(temporary, Geom::Path::STITCH_DISCONTINUOUS); + path_builder.close(); } } @@ -498,27 +527,10 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, //since you've made it this far, hopefully all this is obvious :P Geom::Path with_direction; Geom::Path against_direction; - if ( !path_in[i].closed() ) { - with_direction = Outline::doAdvHalfOutline( path_in[i], -line_width, miter_lim, extrapolate ); - against_direction = Outline::doAdvHalfOutline( path_in[i].reverse(), -line_width, miter_lim, extrapolate ); - } else { - //Geom::Path absolutely refuses to do what I want with these - Geom::Path newPath = path_in[i]; - if (Geom::distance(newPath.finalPoint(), newPath.initialPoint()) == newPath[newPath.size()].length()) { - Geom::LineSegment linear(newPath.finalPoint(), newPath.initialPoint()); - Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(linear.toSBasis()); - newPath.appendNew(cubic[1], cubic[2], cubic[3]); - } - //newPath.close(false); - with_direction = Outline::doAdvHalfOutline( newPath, -line_width, miter_lim, extrapolate ); - against_direction = Outline::doAdvHalfOutline( newPath.reverse(), -line_width, miter_lim, extrapolate ); - /*if (Geom::distance(newPath.finalPoint(), newPath.initialPoint()) != newPath[newPath.size()].length()) { - with_direction.erase_last(); - with_direction.erase_last(); - against_direction.erase(against_direction.begin()); - against_direction.erase(against_direction.begin()); - }*/ - } + + with_direction = Outline::doAdvHalfOutline( path_in[i], -line_width, miter_lim, extrapolate ); + against_direction = Outline::doAdvHalfOutline( path_in[i].reverse(), -line_width, miter_lim, extrapolate ); + Geom::PathBuilder pb; //add in the...do I really need to say this? -- cgit v1.2.3 From d7d371a372254ac945dac7f5f6ac17ff1d96298f Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Fri, 18 Apr 2014 14:36:25 -0400 Subject: Move my path effects outside test effects (stable) (bzr r13090.1.61) --- src/live_effects/effect.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 99282a312..3787dd849 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -110,8 +110,6 @@ const Util::EnumData LPETypeData[] = { {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, - {JOIN_TYPE, N_("Join type"), "join_type"}, - {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, #endif /* 0.46 */ {BEND_PATH, N_("Bend"), "bend_path"}, @@ -137,6 +135,9 @@ const Util::EnumData LPETypeData[] = { {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, +/* lp:~inkscapebrony/inkscape/inkscape */ + {JOIN_TYPE, N_("Join type"), "join_type"}, + {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); -- cgit v1.2.3 From 6cf3f3c4fa0309fbe2af3849cbb0c1f3e9d2b2e7 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 19 Apr 2014 21:14:39 -0400 Subject: remove easter eggs (bzr r13090.1.62) --- src/live_effects/lpe-jointype.cpp | 7 +- src/live_effects/lpe-powerstroke.cpp | 3 + src/live_effects/lpe-taperstroke.cpp | 108 ++++++++++++++++++++----------- src/live_effects/pathoutlineprovider.cpp | 58 ++++++++++++----- 4 files changed, 119 insertions(+), 57 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 3b2887bb5..f3ec02530 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -52,9 +52,9 @@ static const Util::EnumDataConverter JoinTypeConverter(JoinTypeData, s LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : Effect(lpeobject), - line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 10.), + line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.), linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), - linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, join_pointy), + linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) { @@ -164,7 +164,8 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) std::vector LPEJoinType::doEffect_path(std::vector const & path_in) { return Outline::PathVectorOutline(path_in, line_width, static_cast(linecap_type.get_value()), - static_cast(linejoin_type.get_value()), miter_limit); + static_cast(linejoin_type.get_value()), + (attempt_force_join ? std::numeric_limits::max() : miter_limit)); } } //namespace LivePathEffect diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index d17def471..b63a2bf01 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -662,6 +662,9 @@ LPEPowerStroke::doEffect_path (std::vector const & path_in) if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast(interpolator)) { johan->setBeta(interpolator_beta); } + if (Geom::Interpolate::CubicBezierSmooth *smooth = dynamic_cast(interpolator)) { + smooth->setBeta(interpolator_beta); + } Geom::Path strokepath = interpolator->interpolateToPath(ts); delete interpolator; diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 8316daf71..c29690d4f 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -34,6 +34,11 @@ #include "knot-holder-entity.h" #include "knotholder.h" +template +inline bool withinRange(T value, T low, T high) { + return (value > low && value < high); +} + namespace Inkscape { namespace LivePathEffect { @@ -65,12 +70,12 @@ static const Util::EnumDataConverter JoinTypeConverter(JoinType, sizeo LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), - line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 3), + line_width(_("Stroke width"), _("The (non-tapered) width of the path"), "stroke_width", &wr, this, 1.), attach_start(_("Start offset"), _("Taper distance from path start"), "attach_start", &wr, this, 0.2), attach_end(_("End offset"), _("The ending position of the taper"), "end_offset", &wr, this, 0.2), smoothing(_("Taper smoothing"), _("Amount of smoothing to apply to the tapers"), "smoothing", &wr, this, 0.5), join_type(_("Join type"), _("Join type for non-smooth nodes"), "jointype", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), - miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 30.) + miter_limit(_("Miter limit"), _("Limit for miter joins"), "miter_limit", &wr, this, 100.) { show_orig_path = true; _provides_knotholder_entities = true; @@ -205,43 +210,47 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) unsigned size = path_in[0].size(); if (size == first_cusp.size()) { //check to see if the knots were dragged over each other - //if so, reset the end offset + //if so, reset the end offset, but still allow the start offset. if ( attach_start >= (size - attach_end) ) { attach_end.param_set_value( size - attach_start ); } } - if (attach_start == size - attach_end) { + if (attach_end == size - attach_start) { metInMiddle = true; } - //don't let it be zero - if (attach_start <= 0.00000001) { - attach_start.param_set_value( 0.00000001 ); - zeroStart = true; - } - if (attach_end <= 0.00000001) { - attach_end.param_set_value( 0.00000001 ); - zeroEnd = true; - } - //don't let it be integer - if (double(unsigned(attach_start)) == attach_start) { - attach_start.param_set_value(attach_start - 0.00001); - } - if (double(unsigned(attach_end)) == attach_end) { - attach_end.param_set_value(attach_end - 0.00001); + { + if (double(unsigned(attach_start)) == attach_start) { + attach_start.param_set_value(attach_start - 0.00001); + } + if (double(unsigned(attach_end)) == attach_end) { + attach_end.param_set_value(attach_end - 0.00001); + } } unsigned allowed_start = first_cusp.size(); unsigned allowed_end = last_cusp.size(); //don't let the knots be farther than they are allowed to be - if ((unsigned)attach_start >= allowed_start) { - attach_start.param_set_value((double)allowed_start - 0.00001); + { + if ((unsigned)attach_start >= allowed_start) { + attach_start.param_set_value((double)allowed_start - 0.00001); + } + if ((unsigned)attach_end >= allowed_end) { + attach_end.param_set_value((double)allowed_end - 0.00001); + } + } + + //don't let it be zero + if (attach_start < 0.0000001 || withinRange(double(attach_start), 0.00000001, 0.000001)) { + attach_start.param_set_value( 0.0000001 ); + zeroStart = true; } - if ((unsigned)attach_end >= allowed_end) { - attach_end.param_set_value((double)allowed_end - 0.00001); + if (attach_end < 0.0000001 || withinRange(double(attach_end), 0.00000001, 0.000001)) { + attach_end.param_set_value( 0.0000001 ); + zeroEnd = true; } //remember, Path::operator () means get point at time t @@ -252,7 +261,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //the following function just splits it up into three pieces. pathv_out = doEffect_simplePath(path_in); - //now for the actual tapering. We use a Pattern Along Path method to get this done. + //now for the actual tapering. We use the stretch_along method to get this done. Geom::PathVector real_pathv; Geom::Path real_path; @@ -261,13 +270,13 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) Geom::Path throwaway_path; if (!zeroStart) { - //Construct the pattern (pat_str stands for pattern string) (yes, this is easier, trust me) + //Construct the pattern (pat_str stands for pattern string) (and yes, this is easier, trust me) std::stringstream pat_str; pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); - throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; + throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; real_path.append(throwaway_path); } @@ -276,29 +285,52 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //append the outside outline of the path (with direction) throwaway_path = Outline::PathOutsideOutline(pathv_out[1], -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + if (!zeroStart) { + if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { + real_path.appendNew(throwaway_path.initialPoint()); + } else { + real_path.setFinal(throwaway_path.initialPoint()); + } + } + real_path.append(throwaway_path); } if (!zeroEnd) { //append the ending taper std::stringstream pat_str_1; - pat_str_1 << "M 0,0 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; + pat_str_1 << "M 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); pwd2 = Geom::Piecewise > (); pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); - throwaway_path = Geom::path_from_piecewise(pwd2, 0.001)[0]; - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); + throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; + if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { + real_path.appendNew(throwaway_path.initialPoint()); + } else { + real_path.setFinal(throwaway_path.initialPoint()); + } + real_path.append(throwaway_path); + } + + if (!metInMiddle) { + //append the inside outline of the path (against direction) + throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), + -fabs(line_width), static_cast(join_type.get_value()), miter_limit); + + if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { + real_path.appendNew(throwaway_path.initialPoint()); + } else { + real_path.setFinal(throwaway_path.initialPoint()); + } + real_path.append(throwaway_path); + } + + if (Geom::distance(real_path.finalPoint(), real_path.initialPoint()) > 0.0000001) { + real_path.appendNew(real_path.initialPoint()); + } else { + real_path.setFinal(real_path.initialPoint()); } - //append the inside outline of the path (against direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), - -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - - real_path.append(throwaway_path, Geom::Path::STITCH_DISCONTINUOUS); - real_path.appendNew(real_path.initialPoint()); - real_path.close(); real_pathv.push_back(real_path); diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index b5a3258fa..9ff896f84 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -162,8 +162,7 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) //assert(cbc1.finalPoint() == cbc2.initialPoint()); //short circuiting? if (cbc1.finalPoint() != cbc2.initialPoint()) { - printf("There was an issue when asserting that one curve's end is the start of the other. Line %d, File %s\n" - "By default we are going to say that this is an inside join, so we cannot make a line join for it.\n", __LINE__, __FILE__); + printf("erk! Line %d, File %s\n", __LINE__, __FILE__); return false; } @@ -261,7 +260,10 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } path_builder.appendNew (endPt); } - path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); + if (cbc1->finalPoint() != cbc2->initialPoint()) { + path_builder.appendNew(cbc2->initialPoint()); + } + path_builder.append(*cbc2); } if ( outside && lineProblem ) { Geom::Path pth; @@ -283,7 +285,10 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve } } path_builder.appendNew (endPt); - path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); + if (cbc1->finalPoint() != cbc2->initialPoint()) { + path_builder.appendNew(cbc2->initialPoint()); + } + path_builder.append(*cbc2); } if ( !outside ) { /*path_builder.appendNew (endPt);*/ @@ -297,7 +302,12 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve cubic = cubic.subdivide(cross[0].tb).second; path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); } else { - path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); + if (Geom::distance(path_builder.finalPoint(), cbc2->initialPoint()) > 0.0000001) { + path_builder.appendNew(cbc2->initialPoint()); + } else { + path_builder.setFinal(cbc2->initialPoint()); + } + path_builder.append(*cbc2); } } } @@ -360,6 +370,9 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); } + if (cbc1->finalPoint() != cbc2->initialPoint()) { + path_builder.appendNew(cbc2->initialPoint()); + } path_builder.append(*cbc2); } else { //probably on the inside of the corner @@ -374,7 +387,12 @@ void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cb cubic = cubic.subdivide(cross[0].tb).second; path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); } else { - path_builder.append(*cbc2, Geom::Path::STITCH_DISCONTINUOUS); + if (Geom::distance(path_builder.finalPoint(), cbc2->initialPoint()) > 0.0000001) { + path_builder.appendNew(cbc2->initialPoint()); + } else { + path_builder.setFinal(cbc2->initialPoint()); + } + path_builder.append(*cbc2); } } } @@ -431,6 +449,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double } //store it Geom::Path temp_path = (*path_vec)[0]; + //erase the first segment since the join code already appended it temp_path.erase(temp_path.begin()); path_builder.append( temp_path ); @@ -477,7 +496,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double Geom::Curve * cbc1; Geom::Curve * cbc2; - if ( path_in[path_in.size() - 1].length() != Geom::distance(path_in[path_in.size() - 1].finalPoint(), path_in.initialPoint())) { + if ( path_in[path_in.size()].isDegenerate() ) { //handle case for last segment curved outlined_result = Path(); to_outline = Path(); @@ -512,10 +531,10 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double if (extrapolate) { extrapolate_curves(path_builder, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( path_in[path_in.size() - 1], path_in [0] )); + outside_angle ( path_in[path_in.size() - 1], oneCurve [0] )); } else { reflect_curves (path_builder, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( path_in[path_in.size() - 1], path_in [0] )); + outside_angle ( path_in[path_in.size() - 1], oneCurve [0] )); } delete cbc1; cbc1 = cbc2->duplicate(); @@ -534,22 +553,29 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double Geom::Path temporary; //just an accessory path, we won't need it for long temporary.append(*cbc1); + const Geom::Curve& prev_curve = path_in[path_in.size()].isDegenerate() ? path_in[path_in.size() - 1] : + path_in[path_in.size()]; + if (extrapolate) { extrapolate_curves(temporary, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( path_in[path_in.size() - 1], path_in [0] )); + outside_angle ( prev_curve, path_in [0] )); } else { reflect_curves (temporary, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( path_in[path_in.size() - 1], path_in [0] )); + outside_angle ( prev_curve, path_in [0] )); } //extract the appended curves - if (temporary[0].finalPoint() != path_builder[path_builder.size() - 1].finalPoint()) { + //if (temporary[temporary.size()].initialPoint() != path_builder[0].initialPoint()) { path_builder.erase(path_builder.begin()); - } else { + /*} else { temporary.erase_last(); - } + }*/ path_builder.erase_last(); - - path_builder.append(temporary, Geom::Path::STITCH_DISCONTINUOUS); + if (Geom::distance(path_builder.finalPoint(), temporary.initialPoint()) > 0.0000001) { + path_builder.appendNew(temporary.initialPoint()); + } else { + path_builder.setFinal(temporary.initialPoint()); + } + path_builder.append(temporary); path_builder.close(); if (cbc1) delete cbc1; -- cgit v1.2.3 From 44dbc123e17a639c9a8dc7c2a2bd3d36a444823c Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 19 Apr 2014 23:12:30 -0400 Subject: Bug fixes (bzr r13090.1.63) --- src/live_effects/effect.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 3787dd849..4b48ce68c 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -378,8 +378,8 @@ void Effect::doOnRemove (SPLPEItem const* lpeitem) void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); - sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); - pathvector_before_effect = sp_curve->get_pathvector(); + /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); + pathvector_before_effect = sp_curve->get_pathvector();*/ doOnApply(lpeitem); } -- cgit v1.2.3 From 2f628e571a3817765392479766418add4bbdaa20 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 20 Apr 2014 11:03:23 -0400 Subject: minor bugfix (bzr r13090.1.64) --- src/live_effects/lpe-taperstroke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index c29690d4f..7aa896ade 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -216,7 +216,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) } } - if (attach_end == size - attach_start) { + if (attach_start == size - attach_end) { metInMiddle = true; } -- cgit v1.2.3 From 3c99062c5bc3c28b9c2b05de0ee3e9c2725a55b6 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 20 Apr 2014 13:05:53 -0400 Subject: correcting previous revision (bzr r13090.1.65) --- src/live_effects/lpe-taperstroke.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 7aa896ade..8ddaa4087 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -213,12 +213,16 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //if so, reset the end offset, but still allow the start offset. if ( attach_start >= (size - attach_end) ) { attach_end.param_set_value( size - attach_start ); + metInMiddle = true; } } if (attach_start == size - attach_end) { metInMiddle = true; } + if (attach_end == size - attach_start) { + metInMiddle = true; + } //don't let it be integer { @@ -285,7 +289,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //append the outside outline of the path (with direction) throwaway_path = Outline::PathOutsideOutline(pathv_out[1], -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - if (!zeroStart) { + if (!zeroStart && real_path.size() >= 1 && throwaway_path.size() >= 1) { if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { real_path.appendNew(throwaway_path.initialPoint()); } else { @@ -305,7 +309,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; - if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { + if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001 && real_path.size() >= 1) { real_path.appendNew(throwaway_path.initialPoint()); } else { real_path.setFinal(throwaway_path.initialPoint()); @@ -318,7 +322,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { + if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001 && real_path.size() >= 1) { real_path.appendNew(throwaway_path.initialPoint()); } else { real_path.setFinal(throwaway_path.initialPoint()); -- cgit v1.2.3 From 0f91c5cd6a3a8a07185e107da881ff4da71f7081 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 22 Apr 2014 19:03:36 +0200 Subject: align two buttons in LPE widget (bzr r11950.1.334) --- src/live_effects/lpe-bspline.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 8254a13b6..00ebcd9ba 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -318,20 +318,18 @@ Gtk::Widget *LPEBSpline::newWidget() { ++it; } + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); Gtk::Button *defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight 0.3334")))); - defaultWeight->set_alignment(0.0, 0.5); defaultWeight->signal_clicked() .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight)); - Gtk::Widget *defaultWeightWidget = dynamic_cast(defaultWeight); - vbox->pack_start(*defaultWeightWidget, true, true, 2); + buttons->pack_start(*defaultWeight, true, true, 2); Gtk::Button *makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->set_alignment(0.0, 0.5); makeCusp->signal_clicked() .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp)); - Gtk::Widget *makeCuspWidget = dynamic_cast(makeCusp); - vbox->pack_start(*makeCuspWidget, true, true, 2); + buttons->pack_start(*makeCusp, true, true, 2); + vbox->pack_start(*buttons, true, true, 2); return dynamic_cast(vbox); } -- cgit v1.2.3 From bb9297f7e0a297c85b5d40eab49677293effc88f Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 22 Apr 2014 21:44:02 +0200 Subject: Redesign of the BSpline LPE widgets (bzr r11950.1.335) --- src/live_effects/lpe-bspline.cpp | 57 ++++++++++++++++++++++++++++------------ src/live_effects/lpe-bspline.h | 4 +-- 2 files changed, 42 insertions(+), 19 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 00ebcd9ba..edf19d1e5 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -2,7 +2,8 @@ /* * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include +#include #include #include #include @@ -59,10 +60,10 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) false), weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 0.3334) { - registerParameter(dynamic_cast(&ignoreCusp)); - registerParameter(dynamic_cast(&onlySelected)); registerParameter(dynamic_cast(&weight)); registerParameter(dynamic_cast(&steps)); + registerParameter(dynamic_cast(&ignoreCusp)); + registerParameter(dynamic_cast(&onlySelected)); weight.param_set_range(0.0000, 1); weight.param_set_increments(0.1, 0.1); weight.param_set_digits(4); @@ -287,12 +288,32 @@ Gtk::Widget *LPEBSpline::newWidget() { if ((*it)->widget_is_visible) { Parameter *param = *it; Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); + if (param->param_key == "weight"){ + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::Button *defaultWeight = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); + defaultWeight->signal_clicked() + .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); + buttons->pack_start(*defaultWeight, true, true, 2); + Gtk::Button *makeCusp = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); + makeCusp->signal_clicked() + .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); + buttons->pack_start(*makeCusp, true, true, 2); + vbox->pack_start(*buttons, true, true, 2); + } if (param->param_key == "weight" || param->param_key == "steps") { Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); widgRegistered->signal_value_changed() .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); widg = dynamic_cast(widgRegistered); + if (widg){ + Gtk::HBox * scalarParameter = dynamic_cast(widg); + std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast(childList[1]); + entryWidg->set_width_chars(6); + } } if (param->param_key == "onlySelected") { Gtk::CheckButton *widgRegistered = @@ -318,24 +339,26 @@ Gtk::Widget *LPEBSpline::newWidget() { ++it; } - Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); - Gtk::Button *defaultWeight = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight 0.3334")))); - defaultWeight->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight)); - buttons->pack_start(*defaultWeight, true, true, 2); - Gtk::Button *makeCusp = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp)); - buttons->pack_start(*makeCusp, true, true, 2); - vbox->pack_start(*buttons, true, true, 2); return dynamic_cast(vbox); } -void LPEBSpline::toDefaultWeight() { changeWeight(0.3334); } +void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) { + weight.param_set_value(0.3334); + changeWeight(0.3334); + Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); + std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast(childList[1]); + entryWidg->set_text("0.3334"); +} -void LPEBSpline::toMakeCusp() { changeWeight(0.0000); } +void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) { + weight.param_set_value(0.0000); + changeWeight(0.0000); + Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); + std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast(childList[1]); + entryWidg->set_text("0.0000"); +} void LPEBSpline::toWeight() { changeWeight(weight); } diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 167810c49..aff4ce812 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -34,9 +34,9 @@ public: virtual void changeWeight(double weightValue); - virtual void toDefaultWeight(); + virtual void toDefaultWeight(Gtk::Widget *widgWeight); - virtual void toMakeCusp(); + virtual void toMakeCusp(Gtk::Widget *widgWeight); virtual void toWeight(); -- cgit v1.2.3 From 2a5ab3d65249a8a7dde08097c87562d5bca598f2 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 29 Apr 2014 19:55:14 -0400 Subject: Fix a small issue with Attach Path (bzr r13090.1.69) --- src/live_effects/effect.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 4b48ce68c..d8e057ab7 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -386,6 +386,7 @@ void Effect::doOnApply_impl(SPLPEItem const* lpeitem) void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); + //printf("(SPLPEITEM*) %p\n", sp_lpe_item); sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); pathvector_before_effect = sp_curve->get_pathvector(); -- cgit v1.2.3 From 5a8b00f027b9eb3d4abb290d2ddf26d36d71cf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20dos=20Santos=20Oliveira?= Date: Mon, 5 May 2014 04:13:35 -0300 Subject: Enabling path manipulator to comunicate if paths are bspline when accessing const objects. This change was required to correctly show on the GUI whether or not a node was a bspline. (bzr r11950.8.1) --- src/live_effects/effect.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 1da9b4cc9..940770616 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -101,6 +101,7 @@ public: Inkscape::XML::Node * getRepr(); SPDocument * getSPDoc(); LivePathEffectObject * getLPEObj() {return lpeobj;}; + LivePathEffectObject const * getLPEObj() const {return lpeobj;}; Parameter * getParameter(const char * key); void readallParameters(Inkscape::XML::Node const* repr); -- cgit v1.2.3 From e2f2dfac4f2c54eef41c4b7429fe5fb6bc5eb1d2 Mon Sep 17 00:00:00 2001 From: Josh Andler Date: Mon, 5 May 2014 01:40:12 -0700 Subject: Make experimental feature enabling more unified/easy. (bzr r13336) --- src/live_effects/effect.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 12990ee24..4c5e21194 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -5,8 +5,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -//#define LPE_ENABLE_TEST_EFFECTS - #ifdef HAVE_CONFIG_H # include "config.h" #endif -- cgit v1.2.3 From 0a3de4794a6fa71b4c6b4217d42115001503013e Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 10 May 2014 09:47:56 -0400 Subject: Fix stubborn bug 1299948 Fixed bugs: - https://launchpad.net/bugs/1299948 (bzr r13090.1.74) --- src/live_effects/parameter/path.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index cdbbef1db..44d414942 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -118,6 +118,11 @@ PathParam::param_readSVGValue(const gchar * strvalue) // Now do the attaching, which emits the changed signal. try { ref.attach(Inkscape::URI(href)); + //lp:1299948 + SPItem* i = ref.getObject(); + if (i) { + linked_modified_callback(i, SP_OBJECT_MODIFIED_FLAG); + } // else: document still processing new events. Repr of the linked object not created yet. } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); ref.detach(); -- cgit v1.2.3 From ef5f5f784221dbf04469b803c3bba265b0f93803 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 10 May 2014 16:44:06 -0400 Subject: Tentative fix for LPEs and undo Fixed bugs: - https://launchpad.net/bugs/1299948 (bzr r13341.1.5) --- src/live_effects/parameter/path.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index cdbbef1db..44d414942 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -118,6 +118,11 @@ PathParam::param_readSVGValue(const gchar * strvalue) // Now do the attaching, which emits the changed signal. try { ref.attach(Inkscape::URI(href)); + //lp:1299948 + SPItem* i = ref.getObject(); + if (i) { + linked_modified_callback(i, SP_OBJECT_MODIFIED_FLAG); + } // else: document still processing new events. Repr of the linked object not created yet. } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); ref.detach(); -- cgit v1.2.3 From 8e303a547b23758ec6c1accee912185f25718c03 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 12 May 2014 19:59:28 -0400 Subject: Commit patch for "leaned" cap. Thanks Jabiertxof! (bzr r13090.1.78) --- src/live_effects/lpe-jointype.cpp | 24 ++++++--- src/live_effects/lpe-jointype.h | 2 + src/live_effects/pathoutlineprovider.cpp | 92 ++++++++++++++++++++++++++------ src/live_effects/pathoutlineprovider.h | 14 +++-- 4 files changed, 105 insertions(+), 27 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 0c1813970..b0a6e845b 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -41,10 +41,11 @@ static const Util::EnumData JoinTypeData[] = { }; static const Util::EnumData CapTypeData[] = { - {butt_straight, N_("Butt"), "butt"}, - {butt_round, N_("Rounded"), "round"}, - {butt_square, N_("Square"), "square"}, - {butt_pointy, N_("Peak"), "peak"} + {BUTT_STRAIGHT, N_("Butt"), "butt"}, + {BUTT_ROUND, N_("Rounded"), "round"}, + {BUTT_SQUARE, N_("Square"), "square"}, + {BUTT_POINTY, N_("Peak"), "peak"}, + {BUTT_LEANED, N_("Leaned"), "leaned"} }; static const Util::EnumDataConverter CapTypeConverter(CapTypeData, sizeof(CapTypeData)/sizeof(*CapTypeData)); @@ -55,6 +56,8 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.), linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), + start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.), + end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.), miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) { @@ -62,9 +65,17 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast(&linecap_type) ); registerParameter( dynamic_cast(&line_width) ); registerParameter( dynamic_cast(&linejoin_type) ); + registerParameter( dynamic_cast(&start_lean) ); + registerParameter( dynamic_cast(&end_lean) ); registerParameter( dynamic_cast(&miter_limit) ); registerParameter( dynamic_cast(&attempt_force_join) ); was_initialized = false; + start_lean.param_set_range(-1,1); + start_lean.param_set_increments(0.1, 0.1); + start_lean.param_set_digits(4); + end_lean.param_set_range(-1,1); + end_lean.param_set_increments(0.1, 0.1); + end_lean.param_set_digits(4); } LPEJoinType::~LPEJoinType() @@ -163,9 +174,10 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) //wrapper around it. std::vector LPEJoinType::doEffect_path(std::vector const & path_in) { - return Outline::PathVectorOutline(path_in, line_width, static_cast(linecap_type.get_value()), + return Outline::PathVectorOutline(path_in, line_width, static_cast(linecap_type.get_value()), static_cast(linejoin_type.get_value()), - (attempt_force_join ? std::numeric_limits::max() : miter_limit)); + (attempt_force_join ? std::numeric_limits::max() : miter_limit), + start_lean/2 ,end_lean/2); } } //namespace LivePathEffect diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h index db113c66a..7ebce1c7e 100755 --- a/src/live_effects/lpe-jointype.h +++ b/src/live_effects/lpe-jointype.h @@ -32,6 +32,8 @@ private: ScalarParam line_width; EnumParam linecap_type; EnumParam linejoin_type; + ScalarParam start_lean; + ScalarParam end_lean; ScalarParam miter_limit; BoolParam attempt_force_join; bool was_initialized; diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index 9ff896f84..d6e0ce7ea 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -586,7 +586,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double } Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, - ButtType butt, double miter_lim, bool extrapolate) + ButtTypeMod butt, double miter_lim, bool extrapolate, double start_lean, double end_lean) { Geom::PathVector path_out; @@ -610,13 +610,13 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, //add in our line caps if (!path_in[i].closed()) { switch (butt) { - case butt_straight: + case BUTT_STRAIGHT: pb.lineTo(against_direction.initialPoint()); break; - case butt_round: + case BUTT_ROUND: pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, against_direction.initialPoint() ); break; - case butt_pointy: { + case BUTT_POINTY: { Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); Geom::Point midpoint = 0.5 * (with_direction.finalPoint() + against_direction.initialPoint()) + radius*end_deriv; @@ -624,7 +624,7 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, pb.lineTo(against_direction.initialPoint()); break; } - case butt_square: { + case BUTT_SQUARE: { Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); double radius = 0.5 * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); pb.lineTo(with_direction.finalPoint() + radius*end_deriv); @@ -632,6 +632,15 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, pb.lineTo(against_direction.initialPoint()); break; } + case BUTT_LEANED: { + Geom::Point end_deriv = -Geom::unitTangentAt(Geom::reverse(path_in[i].back().toSBasis()), 0.); + double maxRadius = (end_lean+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); + double minRadius = ((end_lean*-1)+0.5) * Geom::distance(with_direction.finalPoint(), against_direction.initialPoint()); + pb.lineTo(with_direction.finalPoint() + maxRadius*end_deriv); + pb.lineTo(against_direction.initialPoint() + minRadius*end_deriv); + pb.lineTo(against_direction.initialPoint()); + break; + } } } else { pb.moveTo(against_direction.initialPoint()); @@ -642,13 +651,13 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, //cap (if necessary) if (!path_in[i].closed()) { switch (butt) { - case butt_straight: + case BUTT_STRAIGHT: pb.lineTo(with_direction.initialPoint()); break; - case butt_round: + case BUTT_ROUND: pb.arcTo((-line_width) / 2, (-line_width) / 2, 0., true, true, with_direction.initialPoint() ); break; - case butt_pointy: { + case BUTT_POINTY: { Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); Geom::Point midpoint = 0.5 * (against_direction.finalPoint() + with_direction.initialPoint()) + radius*end_deriv; @@ -656,7 +665,7 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, pb.lineTo(with_direction.initialPoint()); break; } - case butt_square: { + case BUTT_SQUARE: { Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); double radius = 0.5 * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); pb.lineTo(against_direction.finalPoint() + radius*end_deriv); @@ -664,6 +673,15 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, pb.lineTo(with_direction.initialPoint()); break; } + case BUTT_LEANED: { + Geom::Point end_deriv = -Geom::unitTangentAt(path_in[i].front().toSBasis(), 0.); + double maxRadius = (start_lean+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); + double minRadius = ((start_lean*-1)+0.5) * Geom::distance(against_direction.finalPoint(), with_direction.initialPoint()); + pb.lineTo(against_direction.finalPoint() + minRadius*end_deriv); + pb.lineTo(with_direction.initialPoint() + maxRadius*end_deriv); + pb.lineTo(with_direction.initialPoint()); + break; + } } } pb.flush(); @@ -674,9 +692,29 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, } else { Path p = Path(); Path outlinepath = Path(); - + ButtType original_butt; + switch (butt) { + case BUTT_STRAIGHT: + original_butt = butt_straight; + break; + case BUTT_ROUND: + original_butt = butt_round; + break; + case butt_pointy: { + original_butt = butt_pointy; + break; + } + case BUTT_SQUARE: { + original_butt = butt_square; + break; + } + case BUTT_LEANED: { + original_butt = butt_straight; + break; + } + } p.LoadPath(path_in[i], Geom::Affine(), false, false); - p.Outline(&outlinepath, line_width / 2, static_cast(join), butt, miter_lim); + p.Outline(&outlinepath, line_width / 2, static_cast(join), original_butt, miter_lim); Geom::PathVector *pv_p = outlinepath.MakePathVector(); //somewhat hack-ish path_out.push_back( (*pv_p)[0].reverse() ); @@ -686,8 +724,8 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, return path_out; } -Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtType linecap_type, - LineJoinType linejoin_type, double miter_limit) +Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, + LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean) { std::vector path_out = std::vector(); if (path_in.empty()) { @@ -702,9 +740,30 @@ Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line #define miter_lim fabs(line_width * miter_limit) //magic! + ButtType original_butt; + switch (linecap_type) { + case BUTT_STRAIGHT: + original_butt = butt_straight; + break; + case BUTT_ROUND: + original_butt = butt_round; + break; + case butt_pointy: { + original_butt = butt_pointy; + break; + } + case BUTT_SQUARE: { + original_butt = butt_square; + break; + } + case BUTT_LEANED: { + original_butt = butt_straight; + break; + } + } if (linejoin_type <= 2) { p.Outline(&outlinepath, line_width / 2, static_cast(linejoin_type), - linecap_type, miter_lim); + original_butt, miter_lim); //fix memory leak std::vector *pv_p = outlinepath.MakePathVector(); path_out = *pv_p; @@ -713,12 +772,11 @@ Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line } else if (linejoin_type == 3) { //reflected arc join path_out = outlinePath(path_in, line_width, static_cast(linejoin_type), - linecap_type , miter_lim, false); + linecap_type , miter_lim, false, start_lean, end_lean); } else if (linejoin_type == 4) { //extrapolated arc join - path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true); - + path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true, start_lean, end_lean); } #undef miter_lim diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h index 0ee0f261e..272c93a49 100644 --- a/src/live_effects/pathoutlineprovider.h +++ b/src/live_effects/pathoutlineprovider.h @@ -11,7 +11,13 @@ enum LineJoinType { LINEJOIN_REFLECTED, LINEJOIN_EXTRAPOLATED }; - +enum ButtTypeMod { + BUTT_STRAIGHT, + BUTT_ROUND, + BUTT_SQUARE, + BUTT_POINTY, + BUTT_LEANED +}; namespace Geom { Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in); @@ -21,11 +27,11 @@ namespace Geom namespace Outline { unsigned bezierOrder (const Geom::Curve* curve_in); - std::vector PathVectorOutline(std::vector const & path_in, double line_width, ButtType linecap_type, - LineJoinType linejoin_type, double miter_limit); + std::vector PathVectorOutline(std::vector const & path_in, double line_width, ButtTypeMod linecap_type, + LineJoinType linejoin_type, double miter_limit, double start_lean = 0, double end_lean = 0); /*Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, - ButtType butt, double miter_lim, bool extrapolate = false);*/ + ButtTypeMod butt, double miter_lim, bool extrapolate = false);*/ Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); } -- cgit v1.2.3 From 8dbf7bd73db6bb549b3e0be3fba91cddfcb589b8 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 13 May 2014 07:35:50 +0200 Subject: Fixed a bug in bspline with snaps and 1 sice segments. Pointed by LiamW (bzr r13341.1.12) --- src/live_effects/lpe-bspline.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index edf19d1e5..454924d2b 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -96,7 +96,7 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, } void LPEBSpline::doEffect(SPCurve *curve) { - if (curve->get_segment_count() < 2) + if (curve->get_segment_count() < 1) return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); @@ -216,10 +216,26 @@ void LPEBSpline::doEffect(SPCurve *curve) { ++curve_it1; ++curve_it2; } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; //Si está cerrada la curva, la cerramos sobre el valor guardado //previamente //Si no finalizamos en el punto final - Geom::Point startNode(0, 0); + Geom::Point startNode = path_it->begin()->initialPoint(); if (path_it->closed()) { SPCurve *start = new SPCurve(); start->moveto(path_it->begin()->initialPoint()); @@ -421,7 +437,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { } } //bool hasNodesSelected = LPEBspline::hasNodesSelected(); - if (curve->get_segment_count() < 2) + if (curve->get_segment_count() < 1) return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); -- cgit v1.2.3 From 9cd50c94d560a2372a755bdf58ccf7feb7afe083 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 13 May 2014 08:50:42 +0200 Subject: Add Simplify LPE (bzr r13341.1.13) --- src/live_effects/CMakeLists.txt | 4 ++++ src/live_effects/Makefile_insert | 2 ++ src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 14 +++++++++++--- src/live_effects/parameter/Makefile_insert | 2 ++ 5 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 7aeb911b0..5979cd028 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -29,6 +29,7 @@ set(live_effects_SRC lpe-recursiveskeleton.cpp lpe-rough-hatches.cpp lpe-ruler.cpp + lpe-simplify.cpp # lpe-skeleton.cpp lpe-sketch.cpp lpe-spiro.cpp @@ -53,6 +54,7 @@ set(live_effects_SRC parameter/powerstrokepointarray.cpp parameter/random.cpp parameter/text.cpp + parameter/togglebutton.cpp parameter/unit.cpp parameter/vector.cpp @@ -90,6 +92,7 @@ set(live_effects_SRC lpe-recursiveskeleton.h lpe-rough-hatches.h lpe-ruler.h + lpe-simplify.h lpe-skeleton.h lpe-sketch.h lpe-spiro.h @@ -115,6 +118,7 @@ set(live_effects_SRC parameter/powerstrokepointarray.h parameter/random.h parameter/text.h + parameter/togglebutton.h parameter/unit.h parameter/vector.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 248030e8c..a9da81d5b 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -42,6 +42,8 @@ ink_common_sources += \ live_effects/lpe-bspline.h \ live_effects/lpe-lattice.cpp \ live_effects/lpe-lattice.h \ + live_effects/lpe-simplify.cpp \ + live_effects/lpe-simplify.h \ live_effects/lpe-envelope.cpp \ live_effects/lpe-envelope.h \ live_effects/lpe-spiro.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 342a2c849..cacb1190f 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -28,6 +28,7 @@ enum EffectType { PERSPECTIVE_PATH, SPIRO, LATTICE, + SIMPLIFY, ENVELOPE, CONSTRUCT_GRID, PERP_BISECTOR, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 9006e5359..66bce9c1d 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -26,6 +26,7 @@ #include "live_effects/lpe-perspective_path.h" #include "live_effects/lpe-spiro.h" #include "live_effects/lpe-lattice.h" +#include "live_effects/lpe-simplify.h" #include "live_effects/lpe-envelope.h" #include "live_effects/lpe-constructgrid.h" #include "live_effects/lpe-perp_bisector.h" @@ -122,6 +123,7 @@ const Util::EnumData LPETypeData[] = { {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, {BSPLINE, N_("BSpline"), "bspline"}, + {SIMPLIFY, N_("Simplify"), "simplify"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -248,6 +250,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case CLONE_ORIGINAL: neweffect = static_cast ( new LPECloneOriginal(lpeobj) ); break; + case SIMPLIFY: + neweffect = static_cast ( new LPESimplify(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; @@ -499,9 +504,12 @@ Effect::getCanvasIndicators(SPLPEItem const* lpeitem) { std::vector hp_vec; - if (!SP_IS_SHAPE(lpeitem)) { -// g_print ("How to handle helperpaths for non-shapes?\n"); // non-shapes are for example SPGroups. - return hp_vec; + // TODO: we can probably optimize this by using a lot more references + // rather than copying PathVectors all over the place + if (SP_IS_SHAPE(lpeitem) && show_orig_path) { + // add original path to helperpaths + SPCurve* curve = SP_SHAPE(lpeitem)->getCurve (); + hp_vec.push_back(curve->get_pathvector()); } // add indicators provided by the effect itself diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index efdda686a..30f1f510b 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -22,6 +22,8 @@ ink_common_sources += \ live_effects/parameter/powerstrokepointarray.h \ live_effects/parameter/text.cpp \ live_effects/parameter/text.h \ + live_effects/parameter/togglebutton.cpp \ + live_effects/parameter/togglebutton.h \ live_effects/parameter/unit.cpp \ live_effects/parameter/unit.h \ live_effects/parameter/vector.cpp \ -- cgit v1.2.3 From d516a941370f10590ad305b9fcbe1a4a7622df90 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 13 May 2014 09:44:27 +0200 Subject: Added Latice2 deformation LPE (bzr r13341.1.14) --- src/live_effects/Makefile_insert | 2 + src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 5 + src/live_effects/lpe-lattice.h | 1 - src/live_effects/lpe-lattice2.cpp | 496 +++++++++++++++++++++++++ src/live_effects/lpe-lattice2.h | 92 +++++ src/live_effects/parameter/Makefile_insert | 2 + src/live_effects/parameter/pointreseteable.cpp | 210 +++++++++++ src/live_effects/parameter/pointreseteable.h | 74 ++++ 9 files changed, 882 insertions(+), 1 deletion(-) create mode 100644 src/live_effects/lpe-lattice2.cpp create mode 100644 src/live_effects/lpe-lattice2.h create mode 100644 src/live_effects/parameter/pointreseteable.cpp create mode 100644 src/live_effects/parameter/pointreseteable.h (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index a9da81d5b..aa6a372a8 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -42,6 +42,8 @@ ink_common_sources += \ live_effects/lpe-bspline.h \ live_effects/lpe-lattice.cpp \ live_effects/lpe-lattice.h \ + live_effects/lpe-lattice2.cpp \ + live_effects/lpe-lattice2.h \ live_effects/lpe-simplify.cpp \ live_effects/lpe-simplify.h \ live_effects/lpe-envelope.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index cacb1190f..bd7f6cf23 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -28,6 +28,7 @@ enum EffectType { PERSPECTIVE_PATH, SPIRO, LATTICE, + LATTICE2, SIMPLIFY, ENVELOPE, CONSTRUCT_GRID, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 66bce9c1d..76546c093 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -26,6 +26,7 @@ #include "live_effects/lpe-perspective_path.h" #include "live_effects/lpe-spiro.h" #include "live_effects/lpe-lattice.h" +#include "live_effects/lpe-lattice2.h" #include "live_effects/lpe-simplify.h" #include "live_effects/lpe-envelope.h" #include "live_effects/lpe-constructgrid.h" @@ -124,6 +125,7 @@ const Util::EnumData LPETypeData[] = { {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, {BSPLINE, N_("BSpline"), "bspline"}, {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -253,6 +255,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case SIMPLIFY: neweffect = static_cast ( new LPESimplify(lpeobj) ); break; + case LATTICE2: + neweffect = static_cast ( new LPELattice2(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-lattice.h b/src/live_effects/lpe-lattice.h index a44dda3fd..5eb48909b 100644 --- a/src/live_effects/lpe-lattice.h +++ b/src/live_effects/lpe-lattice.h @@ -58,7 +58,6 @@ private: PointParam grid_point13; PointParam grid_point14; PointParam grid_point15; - LPELattice(const LPELattice&); LPELattice& operator=(const LPELattice&); }; diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp new file mode 100644 index 000000000..db609c9e1 --- /dev/null +++ b/src/live_effects/lpe-lattice2.cpp @@ -0,0 +1,496 @@ +/** \file + * LPE implementation + + */ +/* + * Authors: + * Johan Engelen + * Steren Giannini + * Noé Falzon + * Victor Navez + * ~suv + * Jabiertxo Arraiza +* +* Copyright (C) 2007-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-lattice2.h" + +#include "sp-shape.h" +#include "sp-item.h" +#include "sp-path.h" +#include "display/curve.h" +#include "svg/svg.h" + +#include <2geom/sbasis.h> +#include <2geom/sbasis-2d.h> +#include <2geom/sbasis-geometric.h> +#include <2geom/bezier-to-sbasis.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/d2.h> +#include <2geom/piecewise.h> +#include <2geom/transforms.h> +#include + +#include "desktop.h" // TODO: should be factored out (see below) + +using namespace Geom; + +namespace Inkscape { +namespace LivePathEffect { + +LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + // initialise your parameters here: + grid_point0(_("Control handle 0:"), _("Control handle 0 - Ctrl+Alt+Click to reset"), "gridpoint0", &wr, this), + grid_point1(_("Control handle 1:"), _("Control handle 1 - Ctrl+Alt+Click to reset"), "gridpoint1", &wr, this), + grid_point2(_("Control handle 2:"), _("Control handle 2 - Ctrl+Alt+Click to reset"), "gridpoint2", &wr, this), + grid_point3(_("Control handle 3:"), _("Control handle 3 - Ctrl+Alt+Click to reset"), "gridpoint3", &wr, this), + grid_point4(_("Control handle 4:"), _("Control handle 4 - Ctrl+Alt+Click to reset"), "gridpoint4", &wr, this), + grid_point5(_("Control handle 5:"), _("Control handle 5 - Ctrl+Alt+Click to reset"), "gridpoint5", &wr, this), + grid_point6(_("Control handle 6:"), _("Control handle 6 - Ctrl+Alt+Click to reset"), "gridpoint6", &wr, this), + grid_point7(_("Control handle 7:"), _("Control handle 7 - Ctrl+Alt+Click to reset"), "gridpoint7", &wr, this), + grid_point8x9(_("Control handle 8x9:"), _("Control handle 8x9 - Ctrl+Alt+Click to reset"), "gridpoint8x9", &wr, this), + grid_point10x11(_("Control handle 10x11:"), _("Control handle 10x11 - Ctrl+Alt+Click to reset"), "gridpoint10x11", &wr, this), + grid_point12(_("Control handle 12:"), _("Control handle 12 - Ctrl+Alt+Click to reset"), "gridpoint12", &wr, this), + grid_point13(_("Control handle 13:"), _("Control handle 13 - Ctrl+Alt+Click to reset"), "gridpoint13", &wr, this), + grid_point14(_("Control handle 14:"), _("Control handle 14 - Ctrl+Alt+Click to reset"), "gridpoint14", &wr, this), + grid_point15(_("Control handle 15:"), _("Control handle 15 - Ctrl+Alt+Click to reset"), "gridpoint15", &wr, this), + grid_point16(_("Control handle 16:"), _("Control handle 16 - Ctrl+Alt+Click to reset"), "gridpoint16", &wr, this), + grid_point17(_("Control handle 17:"), _("Control handle 17 - Ctrl+Alt+Click to reset"), "gridpoint17", &wr, this), + grid_point18(_("Control handle 18:"), _("Control handle 18 - Ctrl+Alt+Click to reset"), "gridpoint18", &wr, this), + grid_point19(_("Control handle 19:"), _("Control handle 19 - Ctrl+Alt+Click to reset"), "gridpoint19", &wr, this), + grid_point20x21(_("Control handle 20x21:"), _("Control handle 20x21 - Ctrl+Alt+Click to reset"), "gridpoint20x21", &wr, this), + grid_point22x23(_("Control handle 22x23:"), _("Control handle 22x23 - Ctrl+Alt+Click to reset"), "gridpoint22x23", &wr, this), + grid_point24x26(_("Control handle 24x26:"), _("Control handle 24x26 - Ctrl+Alt+Click to reset"), "gridpoint24x26", &wr, this), + grid_point25x27(_("Control handle 25x27:"), _("Control handle 25x27 - Ctrl+Alt+Click to reset"), "gridpoint25x27", &wr, this), + grid_point28x30(_("Control handle 28x30:"), _("Control handle 28x30 - Ctrl+Alt+Click to reset"), "gridpoint28x30", &wr, this), + grid_point29x31(_("Control handle 29x31:"), _("Control handle 29x31 - Ctrl+Alt+Click to reset"), "gridpoint29x31", &wr, this), + grid_point32x33x34x35(_("Control handle 32x33x34x35:"), _("Control handle 32x33x34x35 - Ctrl+Alt+Click to reset"), "gridpoint32x33x34x35", &wr, this) + + +{ + // register all your parameters here, so Inkscape knows which parameters this effect has: + registerParameter( dynamic_cast(&grid_point0) ); + registerParameter( dynamic_cast(&grid_point1) ); + registerParameter( dynamic_cast(&grid_point2) ); + registerParameter( dynamic_cast(&grid_point3) ); + registerParameter( dynamic_cast(&grid_point4) ); + registerParameter( dynamic_cast(&grid_point5) ); + registerParameter( dynamic_cast(&grid_point6) ); + registerParameter( dynamic_cast(&grid_point7) ); + registerParameter( dynamic_cast(&grid_point8x9) ); + registerParameter( dynamic_cast(&grid_point10x11) ); + registerParameter( dynamic_cast(&grid_point12) ); + registerParameter( dynamic_cast(&grid_point13) ); + registerParameter( dynamic_cast(&grid_point14) ); + registerParameter( dynamic_cast(&grid_point15) ); + registerParameter( dynamic_cast(&grid_point16) ); + registerParameter( dynamic_cast(&grid_point17) ); + registerParameter( dynamic_cast(&grid_point18) ); + registerParameter( dynamic_cast(&grid_point19) ); + registerParameter( dynamic_cast(&grid_point20x21) ); + registerParameter( dynamic_cast(&grid_point22x23) ); + registerParameter( dynamic_cast(&grid_point24x26) ); + registerParameter( dynamic_cast(&grid_point25x27) ); + registerParameter( dynamic_cast(&grid_point28x30) ); + registerParameter( dynamic_cast(&grid_point29x31) ); + registerParameter( dynamic_cast(&grid_point32x33x34x35) ); +} + +LPELattice2::~LPELattice2() +{ +} + +Geom::Piecewise > +LPELattice2::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) +{ + D2 sb2; + + //Initialisation of the sb2 + for(unsigned dim = 0; dim < 2; dim++) { + sb2[dim].us = 3; + sb2[dim].vs = 3; + const int depth = sb2[dim].us*sb2[dim].vs; + sb2[dim].resize(depth, Linear2d(0)); + } + + //Grouping the point params in a convenient vector + std::vector handles(36); + + handles[0] = &grid_point0; + handles[1] = &grid_point1; + handles[2] = &grid_point2; + handles[3] = &grid_point3; + handles[4] = &grid_point4; + handles[5] = &grid_point5; + handles[6] = &grid_point6; + handles[7] = &grid_point7; + handles[8] = &grid_point8x9; + handles[9] = &grid_point8x9; + handles[10] = &grid_point10x11; + handles[11] = &grid_point10x11; + handles[12] = &grid_point12; + handles[13] = &grid_point13; + handles[14] = &grid_point14; + handles[15] = &grid_point15; + handles[16] = &grid_point16; + handles[17] = &grid_point17; + handles[18] = &grid_point18; + handles[19] = &grid_point19; + handles[20] = &grid_point20x21; + handles[21] = &grid_point20x21; + handles[22] = &grid_point22x23; + handles[23] = &grid_point22x23; + handles[24] = &grid_point24x26; + handles[25] = &grid_point25x27; + handles[26] = &grid_point24x26; + handles[27] = &grid_point25x27; + handles[28] = &grid_point28x30; + handles[29] = &grid_point29x31; + handles[30] = &grid_point28x30; + handles[31] = &grid_point29x31; + handles[32] = &grid_point32x33x34x35; + handles[33] = &grid_point32x33x34x35; + handles[34] = &grid_point32x33x34x35; + handles[35] = &grid_point32x33x34x35; + + Geom::Point origin = Geom::Point(boundingbox_X.min(),boundingbox_Y.min()); + + double width = boundingbox_X.extent(); + double height = boundingbox_Y.extent(); + + //numbering is based on 4 rectangles.16 + for(unsigned dim = 0; dim < 2; dim++) { + Geom::Point dir(0,0); + dir[dim] = 1; + for(unsigned vi = 0; vi < sb2[dim].vs; vi++) { + for(unsigned ui = 0; ui < sb2[dim].us; ui++) { + for(unsigned iv = 0; iv < 2; iv++) { + for(unsigned iu = 0; iu < 2; iu++) { + unsigned corner = iu + 2*iv; + unsigned i = ui + vi*sb2[dim].us; + + //This is the offset from the Upperleft point + Geom::Point base( (ui + iu*(4-2*ui))*width/4., + (vi + iv*(4-2*vi))*height/4.); + + //Special action for corners + if(vi == 0 && ui == 0) { + base = Geom::Point(0,0); + } + + // i = Upperleft corner of the considerated rectangle + // corner = actual corner of the rectangle + // origin = Upperleft point + double dl = dot((*handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir); + sb2[dim][i][corner] = dl/( dim ? height : width )*pow(4.0,ui+vi); + } + } + } + } + } + + Piecewise > output; + output.push_cut(0.); + for(unsigned i = 0; i < pwd2_in.size(); i++) { + D2 B = pwd2_in[i]; + B[Geom::X] -= origin[Geom::X]; + B[Geom::X]*= 1/width; + B[Geom::Y] -= origin[Geom::Y]; + B[Geom::Y]*= 1/height; + //Here comes the magic + D2 tB = compose_each(sb2,B); + tB[Geom::X] = tB[Geom::X] * width + origin[Geom::X]; + tB[Geom::Y] = tB[Geom::Y] * height + origin[Geom::Y]; + + output.push(tB,i+1); + } + return output; +} + +Gtk::Widget * +LPELattice2::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); + Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset grid")))); + resetButton->set_alignment(0.0, 0.5); + resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPELattice2::resetGrid)); + Gtk::Widget* resetButtonWidget = dynamic_cast(resetButton); + resetButtonWidget->set_tooltip_text("Reset grid"); + vbox->pack_start(*resetButtonWidget, true, true,2); + std::vector::iterator it = param_vector.begin(); + 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 == "grid"){ + widg = NULL; + } + 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; + } + return dynamic_cast(vbox); +} + +void +LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem) +{ + original_bbox(lpeitem); + setDefaults(); +} + +void +LPELattice2::setDefaults() +{ + Geom::Point gp0((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp1((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp2((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp3((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp4((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp5((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp6((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp7((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp8x9((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp10x11((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp12((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp13((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp14((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp15((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp16((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp17((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp18((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp19((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp20x21((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp22x23((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp24x26((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp25x27((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp28x30((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp29x31((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp32x33x34x35((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + grid_point0.param_update_default(gp0); + grid_point1.param_update_default(gp1); + grid_point2.param_update_default(gp2); + grid_point3.param_update_default(gp3); + grid_point4.param_update_default(gp4); + grid_point5.param_update_default(gp5); + grid_point6.param_update_default(gp6); + grid_point7.param_update_default(gp7); + grid_point8x9.param_update_default(gp8x9); + grid_point10x11.param_update_default(gp10x11); + grid_point12.param_update_default(gp12); + grid_point13.param_update_default(gp13); + grid_point14.param_update_default(gp14); + grid_point15.param_update_default(gp15); + grid_point16.param_update_default(gp16); + grid_point17.param_update_default(gp17); + grid_point18.param_update_default(gp18); + grid_point19.param_update_default(gp19); + grid_point20x21.param_update_default(gp20x21); + grid_point22x23.param_update_default(gp22x23); + grid_point24x26.param_update_default(gp24x26); + grid_point25x27.param_update_default(gp25x27); + grid_point28x30.param_update_default(gp28x30); + grid_point29x31.param_update_default(gp29x31); + grid_point32x33x34x35.param_update_default(gp32x33x34x35); +} + +void +LPELattice2::resetGrid() +{ + grid_point0.param_set_and_write_default(); + grid_point1.param_set_and_write_default(); + grid_point2.param_set_and_write_default(); + grid_point3.param_set_and_write_default(); + grid_point4.param_set_and_write_default(); + grid_point5.param_set_and_write_default(); + grid_point6.param_set_and_write_default(); + grid_point7.param_set_and_write_default(); + grid_point8x9.param_set_and_write_default(); + grid_point10x11.param_set_and_write_default(); + grid_point12.param_set_and_write_default(); + grid_point13.param_set_and_write_default(); + grid_point14.param_set_and_write_default(); + grid_point15.param_set_and_write_default(); + grid_point16.param_set_and_write_default(); + grid_point17.param_set_and_write_default(); + grid_point18.param_set_and_write_default(); + grid_point19.param_set_and_write_default(); + grid_point20x21.param_set_and_write_default(); + grid_point22x23.param_set_and_write_default(); + grid_point24x26.param_set_and_write_default(); + grid_point25x27.param_set_and_write_default(); + grid_point28x30.param_set_and_write_default(); + grid_point29x31.param_set_and_write_default(); + grid_point32x33x34x35.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 +LPELattice2::resetDefaults(SPItem const* item) +{ + Effect::resetDefaults(item); + original_bbox(SP_LPE_ITEM(item)); + setDefaults(); + resetGrid(); +} + +void +LPELattice2::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 +LPELattice2::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec) +{ + hp_vec.clear(); + + SPCurve *c = new SPCurve(); + calculateCurve(grid_point0,grid_point4, c,true, true); + calculateCurve(grid_point4,grid_point8x9, c,true, false); + calculateCurve(grid_point8x9,grid_point5, c,true, false); + calculateCurve(grid_point5,grid_point1, c,true, false); + + calculateCurve(grid_point12,grid_point16, c,true, true); + calculateCurve(grid_point16,grid_point20x21, c,true, false); + calculateCurve(grid_point20x21,grid_point17, c,true, false); + calculateCurve(grid_point17,grid_point13, c,true, false); + + calculateCurve(grid_point24x26,grid_point28x30, c,true, true); + calculateCurve(grid_point28x30,grid_point32x33x34x35, c,true, false); + calculateCurve(grid_point32x33x34x35,grid_point29x31, c,true, false); + calculateCurve(grid_point29x31,grid_point25x27, c,true, false); + + calculateCurve(grid_point14,grid_point18, c,true, true); + calculateCurve(grid_point18,grid_point22x23, c,true, false); + calculateCurve(grid_point22x23,grid_point19, c,true, false); + calculateCurve(grid_point19,grid_point15, c,true, false); + + calculateCurve(grid_point2,grid_point6, c,true, true); + calculateCurve(grid_point6,grid_point10x11, c,true, false); + calculateCurve(grid_point10x11,grid_point7, c,true, false); + calculateCurve(grid_point7,grid_point3, c,true, false); + + calculateCurve(grid_point0,grid_point12, c,false, true); + calculateCurve(grid_point12,grid_point24x26, c,false, false); + calculateCurve(grid_point24x26,grid_point14, c,false, false); + calculateCurve(grid_point14,grid_point2, c,false, false); + + calculateCurve(grid_point4,grid_point16, c,false, true); + calculateCurve(grid_point16,grid_point28x30, c,false, false); + calculateCurve(grid_point28x30,grid_point18, c,false, false); + calculateCurve(grid_point18,grid_point6, c,false, false); + + calculateCurve(grid_point8x9,grid_point20x21, c,false, true); + calculateCurve(grid_point20x21,grid_point32x33x34x35, c,false, false); + calculateCurve(grid_point32x33x34x35,grid_point22x23, c,false, false); + calculateCurve(grid_point22x23,grid_point10x11, c,false, false); + + calculateCurve(grid_point5,grid_point17, c, false, true); + calculateCurve(grid_point17,grid_point29x31, c,false, false); + calculateCurve(grid_point29x31,grid_point19, c,false, false); + calculateCurve(grid_point19,grid_point7, c,false, false); + + calculateCurve(grid_point1,grid_point13, c, false, true); + calculateCurve(grid_point13,grid_point25x27, c,false, false); + calculateCurve(grid_point25x27,grid_point15, c,false, false); + calculateCurve(grid_point15,grid_point3, c, false, false); + 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-lattice2.h b/src/live_effects/lpe-lattice2.h new file mode 100644 index 000000000..461f835c6 --- /dev/null +++ b/src/live_effects/lpe-lattice2.h @@ -0,0 +1,92 @@ +#ifndef INKSCAPE_LPE_LATTICE2_H +#define INKSCAPE_LPE_LATTICE2_H + +/** \file + * LPE implementation, see lpe-lattice2.cpp. + */ + +/* + * Authors: + * Johan Engelen + * Steren Giannini + * Noé Falzon + * Victor Navez + * ~suv + * Jabiertxo Arraiza +* +* Copyright (C) Johan Engelen 2007 + * + * 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 LPELattice2 : public Effect, GroupBBoxEffect { +public: + + LPELattice2(LivePathEffectObject *lpeobject); + virtual ~LPELattice2(); + + virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); + + 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: + + PointReseteableParam grid_point0; + PointReseteableParam grid_point1; + PointReseteableParam grid_point2; + PointReseteableParam grid_point3; + PointReseteableParam grid_point4; + PointReseteableParam grid_point5; + PointReseteableParam grid_point6; + PointReseteableParam grid_point7; + PointReseteableParam grid_point8x9; + PointReseteableParam grid_point10x11; + PointReseteableParam grid_point12; + PointReseteableParam grid_point13; + PointReseteableParam grid_point14; + PointReseteableParam grid_point15; + PointReseteableParam grid_point16; + PointReseteableParam grid_point17; + PointReseteableParam grid_point18; + PointReseteableParam grid_point19; + PointReseteableParam grid_point20x21; + PointReseteableParam grid_point22x23; + PointReseteableParam grid_point24x26; + PointReseteableParam grid_point25x27; + PointReseteableParam grid_point28x30; + PointReseteableParam grid_point29x31; + PointReseteableParam grid_point32x33x34x35; + + LPELattice2(const LPELattice2&); + LPELattice2& operator=(const LPELattice2&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index 30f1f510b..1026cf11c 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -11,6 +11,8 @@ ink_common_sources += \ live_effects/parameter/random.h \ live_effects/parameter/point.cpp \ live_effects/parameter/point.h \ + live_effects/parameter/pointreseteable.cpp \ + live_effects/parameter/pointreseteable.h \ live_effects/parameter/enum.h \ live_effects/parameter/path-reference.cpp \ live_effects/parameter/path-reference.h \ diff --git a/src/live_effects/parameter/pointreseteable.cpp b/src/live_effects/parameter/pointreseteable.cpp new file mode 100644 index 000000000..ec36fc035 --- /dev/null +++ b/src/live_effects/parameter/pointreseteable.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) Johan Engelen 2007 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/pointreseteable.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "ui/widget/point.h" +#include "widgets/icon.h" +#include "inkscape.h" +#include "verbs.h" +#include "knotholder.h" +#include +#include "tools-switch.h" +#include "ui/tools/node-tool.h" + +// needed for on-canvas editting: +#include "desktop.h" + +namespace Inkscape { + +namespace LivePathEffect { + +PointReseteableParam::PointReseteableParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, const gchar *htip, Geom::Point default_value) + : Geom::Point(default_value), Parameter(label, tip, key, wr, effect), defvalue(default_value) +{ + knot_shape = SP_KNOT_SHAPE_DIAMOND; + knot_mode = SP_KNOT_MODE_XOR; + knot_color = 0xffffff00; + handle_tip = g_strdup(htip); +} + +PointReseteableParam::~PointReseteableParam() +{ + if (handle_tip) + g_free(handle_tip); +} + +void +PointReseteableParam::param_set_default() +{ + param_setValue(defvalue); +} + +void +PointReseteableParam::param_set_and_write_default() +{ + param_set_and_write_new_value(defvalue); +} + +void +PointReseteableParam::param_update_default(Geom::Point newpoint) +{ + this->defvalue = newpoint; +} + +bool +PointReseteableParam::param_readSVGValue(const gchar * strvalue) +{ + gchar ** strarray = g_strsplit(strvalue, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_setValue( Geom::Point(newx, newy) ); + return true; + } + return false; +} + +gchar * +PointReseteableParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + os << *dynamic_cast( this ); + gchar * str = g_strdup(os.str().c_str()); + return str; +} + +Gtk::Widget * +PointReseteableParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() ) ); + // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Geom::Affine transf = desktop->doc2dt(); + pointwdg->setTransform(transf); + pointwdg->setValue( *this ); + pointwdg->clearProgrammatically(); + pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); + + Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); + static_cast(hbox)->pack_start(*pointwdg, true, true); + static_cast(hbox)->show_all_children(); + + return dynamic_cast (hbox); +} + +void +PointReseteableParam::param_setValue(Geom::Point newpoint) +{ + *dynamic_cast( this ) = newpoint; + if(SP_ACTIVE_DESKTOP){ + SPDesktop* desktop = SP_ACTIVE_DESKTOP; + if (tools_isactive( desktop, TOOLS_NODES)) { + Inkscape::UI::Tools::NodeTool *nt = static_cast( desktop->event_context); + nt->update_helperpath(); + } + } +} + +void +PointReseteableParam::param_set_and_write_new_value (Geom::Point newpoint) +{ + Inkscape::SVGOStringStream os; + os << newpoint; + gchar * str = g_strdup(os.str().c_str()); + param_write_to_repr(str); + g_free(str); +} + +void +PointReseteableParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) +{ + param_set_and_write_new_value( (*this) * postmul ); +} + + +void +PointReseteableParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) +{ + knot_shape = shape; + knot_mode = mode; + knot_color = color; +} + +class PointReseteableParamKnotHolderEntity : public KnotHolderEntity { +public: + PointReseteableParamKnotHolderEntity(PointReseteableParam *p) { this->pparam = p; } + virtual ~PointReseteableParamKnotHolderEntity() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + virtual void knot_click(guint state); + +private: + PointReseteableParam *pparam; +}; + +void +PointReseteableParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) +{ + Geom::Point const s = snap_knot_position(p, state); + pparam->param_setValue(s); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Geom::Point +PointReseteableParamKnotHolderEntity::knot_get() const +{ + return *pparam; +} + +void +PointReseteableParamKnotHolderEntity::knot_click(guint state) +{ + if (state & GDK_CONTROL_MASK) { + if (state & GDK_MOD1_MASK) { + this->pparam->param_set_default(); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + } + } +} + +void +PointReseteableParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ + PointReseteableParamKnotHolderEntity *e = new PointReseteableParamKnotHolderEntity(this); + // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself??? + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); + knotholder->add(e); +} + +} /* 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/parameter/pointreseteable.h b/src/live_effects/parameter/pointreseteable.h new file mode 100644 index 000000000..5ae1fdf02 --- /dev/null +++ b/src/live_effects/parameter/pointreseteable.h @@ -0,0 +1,74 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2007 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include <2geom/point.h> + +#include "live_effects/parameter/parameter.h" + +#include "knot-holder-entity.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class PointReseteableParamKnotHolderEntity; + +class PointReseteableParam : public Geom::Point, public Parameter { +public: + PointReseteableParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + const gchar *handle_tip = NULL, + Geom::Point default_value = Geom::Point(0,0) ); // tip for automatically associated on-canvas handle + virtual ~PointReseteableParam(); + + virtual Gtk::Widget * param_newWidget(); + + bool param_readSVGValue(const gchar * strvalue); + gchar * param_getSVGValue() const; + inline const gchar *handleTip() const { return handle_tip ? handle_tip : param_tooltip.c_str(); } + + void param_setValue(Geom::Point newpoint); + void param_set_default(); + void param_set_and_write_default(); + void param_update_default(Geom::Point newpoint); + + void param_set_and_write_new_value(Geom::Point newpoint); + + virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); + + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + + virtual bool providesKnotHolderEntities() const { return true; } + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + + friend class PointReseteableParamKnotHolderEntity; +private: + PointReseteableParam(const PointReseteableParam&); + PointReseteableParam& operator=(const PointReseteableParam&); + + Geom::Point defvalue; + + SPKnotShapeType knot_shape; + SPKnotModeType knot_mode; + guint32 knot_color; + gchar *handle_tip; +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif -- cgit v1.2.3 From 291262ed193a4f2b3252967f8673290cdc94e173 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 13 May 2014 18:02:25 +0200 Subject: adding missing files from LPE simplify (bzr r13341.1.16) --- src/live_effects/lpe-simplify.cpp | 287 ++++++++++++++++++++++++++++ src/live_effects/lpe-simplify.h | 59 ++++++ src/live_effects/parameter/togglebutton.cpp | 92 +++++++++ src/live_effects/parameter/togglebutton.h | 56 ++++++ 4 files changed, 494 insertions(+) create mode 100644 src/live_effects/lpe-simplify.cpp create mode 100644 src/live_effects/lpe-simplify.h create mode 100644 src/live_effects/parameter/togglebutton.cpp create mode 100644 src/live_effects/parameter/togglebutton.h (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp new file mode 100644 index 000000000..d010e75a2 --- /dev/null +++ b/src/live_effects/lpe-simplify.cpp @@ -0,0 +1,287 @@ +#define INKSCAPE_LPE_SIMPLIFY_C +/* + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include +#include +#include "live_effects/lpe-simplify.h" +#include "display/curve.h" +#include "live_effects/parameter/parameter.h" +#include +#include "helper/geom.h" +#include "livarot/Path.h" +#include "splivarot.h" +#include <2geom/svg-path-parser.h> +#include "desktop.h" +#include "inkscape.h" +#include "svg/svg.h" +#include "ui/tools/node-tool.h" +#include <2geom/d2.h> +#include <2geom/generic-rect.h> +#include <2geom/interval.h> + + +namespace Inkscape { +namespace LivePathEffect { + +LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), + threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), + helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 2.), + nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false), + handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false), + simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false), + simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false) + { + registerParameter(dynamic_cast(&steps)); + registerParameter(dynamic_cast(&threshold)); + registerParameter(dynamic_cast(&helper_size)); + registerParameter(dynamic_cast(&nodes)); + registerParameter(dynamic_cast(&handles)); + registerParameter(dynamic_cast(&simplifyindividualpaths)); + registerParameter(dynamic_cast(&simplifyJustCoalesce)); + threshold.param_set_range(0., Geom::infinity()); + threshold.param_set_increments(0.0001, 0.0001); + threshold.param_set_digits(6); + steps.param_set_range(0, 100); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); + helper_size.param_set_range(0.1, 100); + helper_size.param_set_increments(1, 1); + helper_size.param_set_digits(1); +} + +LPESimplify::~LPESimplify() {} + +void +LPESimplify::doBeforeEffect (SPLPEItem const* lpeitem) +{ + if(!hp.empty()){ + hp.clear(); + } + bbox = SP_ITEM(lpeitem)->visualBounds(); + +} + +Gtk::Widget * +LPESimplify::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(2); + std::vector::iterator it = param_vector.begin(); + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::HBox * buttonsTwo = Gtk::manage(new Gtk::HBox(true,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 == "simplifyindividualpaths" || + param->param_key == "simplifyJustCoalesce") + { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + buttonsTwo->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } else if (param->param_key == "nodes" || + param->param_key == "handles") + { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + buttons->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) { + Gtk::HBox * scalarParameter = dynamic_cast(widg); + std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast(childList[1]); + entryWidg->set_width_chars(8); + 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(*buttons,true, true, 2); + vbox->pack_start(*buttonsTwo,true, true, 2); + return dynamic_cast(vbox); +} + +void +LPESimplify::doEffect(SPCurve *curve) { + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); + gdouble size = Geom::L2(bbox->dimensions()); + //size /= Geom::Affine(0,0,0,0,0,0).descrim(); + Path* pathliv = Path_for_pathvector(original_pathv); + if(simplifyindividualpaths){ + size = Geom::L2(Geom::bounds_fast(original_pathv)->dimensions()); + } + for (int unsigned i = 0; i < steps; i++){ + if ( simplifyJustCoalesce ) { + pathliv->Coalesce(threshold * size); + }else{ + pathliv->ConvertEvenLines(threshold * size); + pathliv->Simplify(threshold * size); + } + } + Geom::PathVector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); + generateHelperPath(outres); + curve->set_pathvector(outres); + if(SP_ACTIVE_DESKTOP && INK_IS_NODE_TOOL(SP_ACTIVE_DESKTOP->event_context)){ + SPDesktop* desktop = SP_ACTIVE_DESKTOP; + Inkscape::UI::Tools::NodeTool *nt = static_cast(desktop->event_context); + nt->update_helperpath(); + } +} + +void +LPESimplify::generateHelperPath(Geom::PathVector result) +{ + if(!handles && !nodes){ + return; + } + + if(steps < 1){ + return; + } + + Geom::CubicBezier const *cubic = NULL; + for (Geom::PathVector::iterator path_it = result.begin(); path_it != result.end(); ++path_it) { + //Si está vacío... + if (path_it->empty()){ + continue; + } + //Itreadores + 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(nodes){ + drawNode(curve_it1->initialPoint()); + } + while (curve_it2 != curve_endit) { + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + if(handles){ + drawHandle((*cubic)[1]); + drawHandle((*cubic)[2]); + drawHandleLine((*cubic)[0],(*cubic)[1]); + drawHandleLine((*cubic)[2],(*cubic)[3]); + } + } + if(nodes){ + drawNode(curve_it1->finalPoint()); + } + ++curve_it1; + ++curve_it2; + } + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + if(handles){ + drawHandle((*cubic)[1]); + drawHandle((*cubic)[2]); + drawHandleLine((*cubic)[0],(*cubic)[1]); + drawHandleLine((*cubic)[2],(*cubic)[3]); + } + } + if(nodes){ + drawNode(curve_it1->finalPoint()); + } + } +} + +void +LPESimplify::drawNode(Geom::Point p) +{ + double r = helper_size/0.67; + char const * svgd; + svgd = "M 0.999993,0.5 C 1.000065,0.7757576 0.7761859,1 0.4999926,1 0.2237994,1 -7.933901e-5,0.7757576 -7.339015e-6,0.5 -7.933901e-5,0.2242424 0.2237994,0 0.4999926,0 0.7761859,0 1.000065,0.2242424 0.999993,0.5 Z m -0.058561,0 C 0.9414949,0.74327 0.7438375,0.9416286 0.4999928,0.9416286 0.2561481,0.9416286 0.0584908,0.74327 0.0585543,0.5 0.0584908,0.25673 0.2561481,0.0583714 0.4999928,0.0583714 0.7438375,0.0583714 0.9414949,0.25673 0.9414313,0.5 Z m -0.3828447,0 c 8.5e-6,0.030303 -0.026228,0.060606 -0.058593,0.060606 -0.032366,0 -0.058603,-0.030303 -0.058593,-0.060606 -8.5e-6,-0.030303 0.026227,-0.060606 0.058593,-0.060606 0.032366,0 0.058603,0.030303 0.058593,0.060606 z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(r,0,0,r,0,0); + pathv += p - Geom::Point(0.5*r,0.5*r); + hp.push_back(pathv[0]); + hp.push_back(pathv[1]); + hp.push_back(pathv[2]); +} + +void +LPESimplify::drawHandle(Geom::Point p) +{ + double r = helper_size/0.67; + char const * svgd; + svgd = "M 0.6999623,0.35 C 0.7000128,0.5430303 0.5433044,0.7 0.3499775,0.7 0.1566506,0.7 -5.778776e-5,0.5430303 -7.344202e-6,0.35 -5.778776e-5,0.1569697 0.1566506,0 0.3499775,0 0.5433044,0 0.7000128,0.1569697 0.6999623,0.35 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(r,0,0,r,0,0); + pathv += p - Geom::Point(0.35*r,0.35*r); + hp.push_back(pathv[0]); +} + + +void +LPESimplify::drawHandleLine(Geom::Point p,Geom::Point p2) +{ + Geom::Path path; + path.start( p ); + path.appendNew( p2 ); + hp.push_back(path); +} + +void +LPESimplify::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec) +{ + hp_vec.push_back(hp); +} + + +}; //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-simplify.h b/src/live_effects/lpe-simplify.h new file mode 100644 index 000000000..6acf2f2d4 --- /dev/null +++ b/src/live_effects/lpe-simplify.h @@ -0,0 +1,59 @@ +#ifndef INKSCAPE_LPE_SIMPLIFY_H +#define INKSCAPE_LPE_SIMPLIFY_H + +/* + * Inkscape::LPESimplify + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/togglebutton.h" +#include "live_effects/lpegroupbbox.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPESimplify : public Effect , GroupBBoxEffect{ + +public: + LPESimplify(LivePathEffectObject *lpeobject); + virtual ~LPESimplify(); + + virtual void doEffect(SPCurve *curve); + + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + + virtual void generateHelperPath(Geom::PathVector result); + + virtual Gtk::Widget * newWidget(); + + virtual void drawNode(Geom::Point p); + + virtual void drawHandle(Geom::Point p); + + virtual void drawHandleLine(Geom::Point p,Geom::Point p2); + +protected: + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); + +private: + ScalarParam steps; + ScalarParam threshold; + ScalarParam helper_size; + ToggleButtonParam nodes; + ToggleButtonParam handles; + ToggleButtonParam simplifyindividualpaths; + ToggleButtonParam simplifyJustCoalesce; + + Geom::PathVector hp; + Geom::OptRect bbox; + + LPESimplify(const LPESimplify &); + LPESimplify &operator=(const LPESimplify &); + +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape +#endif diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp new file mode 100644 index 000000000..03238f935 --- /dev/null +++ b/src/live_effects/parameter/togglebutton.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) Johan Engelen 2007 + * Copyright (C) Jabiertxo Arraiza Cenoz 2014 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/togglebutton.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "widgets/icon.h" +#include "inkscape.h" +#include "verbs.h" +#include "helper-fns.h" +#include + +namespace Inkscape { + +namespace LivePathEffect { + +ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, bool default_value ) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) +{ +} + +ToggleButtonParam::~ToggleButtonParam() +{ +} + +void +ToggleButtonParam::param_set_default() +{ + param_setValue(defvalue); +} + +bool +ToggleButtonParam::param_readSVGValue(const gchar * strvalue) +{ + param_setValue(helperfns_read_bool(strvalue, defvalue)); + return true; // not correct: if value is unacceptable, should return false! +} + +gchar * +ToggleButtonParam::param_getSVGValue() const +{ + gchar * str = g_strdup(value ? "true" : "false"); + return str; +} + +Gtk::Widget * +ToggleButtonParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredToggleButton * checkwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredToggleButton( param_label, + param_tooltip, + param_key, + *param_wr, + false, + param_effect->getRepr(), + param_effect->getSPDoc()) ); + + checkwdg->setActive(value); + checkwdg->setProgrammatically = false; + checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); + + return dynamic_cast (checkwdg); +} + +void +ToggleButtonParam::param_setValue(bool newvalue) +{ + value = newvalue; +} + +} /* 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/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h new file mode 100644 index 000000000..9b1c71185 --- /dev/null +++ b/src/live_effects/parameter/togglebutton.h @@ -0,0 +1,56 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2007 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include "live_effects/parameter/parameter.h" + +namespace Inkscape { + +namespace LivePathEffect { + + +class ToggleButtonParam : public Parameter { +public: + ToggleButtonParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + bool default_value = false); + virtual ~ToggleButtonParam(); + + virtual Gtk::Widget * param_newWidget(); + + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + + void param_setValue(bool newvalue); + virtual void param_set_default(); + + bool get_value() const { return value; }; + + inline operator bool() const { return value; }; + +private: + ToggleButtonParam(const ToggleButtonParam&); + ToggleButtonParam& operator=(const ToggleButtonParam&); + + bool value; + bool defvalue; +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif -- cgit v1.2.3 From 76e9bb52fbd6a39e68cd8e34559762e2b2d1806b Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 16 May 2014 00:17:53 +0200 Subject: fix C++11 compilation (bzr r13341.1.30) --- src/live_effects/lpe-vonkoch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index c0050fa60..8b0b716fe 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -4,11 +4,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#include "live_effects/lpe-vonkoch.h" #include -#include "live_effects/lpe-vonkoch.h" #include <2geom/transforms.h> //using std::vector; -- cgit v1.2.3 From c9bc38e7eadc17562c0348d12fe58cf5fa114bd3 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 16 May 2014 00:18:42 +0200 Subject: fix C++11 compilation (bzr r13385) --- src/live_effects/lpe-vonkoch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index c0050fa60..8b0b716fe 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -4,11 +4,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#include "live_effects/lpe-vonkoch.h" #include -#include "live_effects/lpe-vonkoch.h" #include <2geom/transforms.h> //using std::vector; -- cgit v1.2.3 From c0df405028494695ebd0b0a497c7526a2520cafd Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Fri, 16 May 2014 17:53:59 -0400 Subject: Fix GTK+ 3 build (bzr r13341.1.35) --- src/live_effects/lpe-bspline.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 454924d2b..b19b697c0 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -1,14 +1,27 @@ #define INKSCAPE_LPE_BSPLINE_C + /* * Released under GNU GPL, read the file 'COPYING' for more information */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if WITH_GLIBMM_2_32 +# include +#endif + #include #include #include #include #include + #include #include + + #include "display/curve.h" #include <2geom/bezier-curve.h> #include <2geom/point.h> -- cgit v1.2.3 From 519d4aa4931a9ca00b6fd9874e49a863dc54a4df Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 30 May 2014 20:23:12 +0200 Subject: Added Perspective-Envelope live effect (bzr r13341.1.43) --- src/live_effects/CMakeLists.txt | 2 + src/live_effects/Makefile_insert | 4 +- src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 5 + src/live_effects/lpe-envelope-perspective.cpp | 414 ++++++++++++++++++++++++++ src/live_effects/lpe-envelope-perspective.h | 76 +++++ 6 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 src/live_effects/lpe-envelope-perspective.cpp create mode 100644 src/live_effects/lpe-envelope-perspective.h (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 5979cd028..610d3a9bf 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -38,6 +38,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 @@ -101,6 +102,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 aa6a372a8..c47003747 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -88,4 +88,6 @@ ink_common_sources += \ live_effects/lpe-path_length.cpp \ live_effects/lpe-path_length.h \ live_effects/lpe-line_segment.cpp \ - live_effects/lpe-line_segment.h + live_effects/lpe-line_segment.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 bd7f6cf23..4d1c1d8c1 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -53,6 +53,7 @@ enum EffectType { EXTRUDE, POWERSTROKE, CLONE_ORIGINAL, + 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 76546c093..eef954fe2 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -48,6 +48,7 @@ #include "live_effects/lpe-extrude.h" #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-clone-original.h" +#include "live_effects/lpe-envelope-perspective.h" #include "xml/node-event-vector.h" #include "sp-object.h" @@ -126,6 +127,7 @@ const Util::EnumData LPETypeData[] = { {BSPLINE, N_("BSpline"), "bspline"}, {SIMPLIFY, N_("Simplify"), "simplify"}, {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, + {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -258,6 +260,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case LATTICE2: neweffect = static_cast ( new LPELattice2(lpeobj) ); break; + case ENVELOPE_PERSPECTIVE: + neweffect = static_cast ( 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 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 +#include +#include +#include +#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(&perspective)); + 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(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(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(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(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::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); + return dynamic_cast(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 &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 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: + + 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 -- cgit v1.2.3 From 4c3611844acfa101897fed00adc839f167ae75bf Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Fri, 6 Jun 2014 15:48:19 -0400 Subject: Put lpe-envelope-perspective.cpp in CMakeLists.txt (bzr r13341.1.49) --- src/live_effects/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 610d3a9bf..5d365bb21 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -12,6 +12,7 @@ set(live_effects_SRC lpe-curvestitch.cpp lpe-dynastroke.cpp lpe-envelope.cpp + lpe-envelope-perspective.cpp lpe-extrude.cpp lpe-gears.cpp lpe-interpolate.cpp -- cgit v1.2.3 From 013b60b9f180a1bc0ee43799c6259ff5864fbf81 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 13 Jun 2014 23:04:00 +0200 Subject: Removed original path helper paths pointed by LiamW (bzr r13341.1.61) --- src/live_effects/effect.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index eef954fe2..d0a168a14 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -514,14 +514,6 @@ Effect::getCanvasIndicators(SPLPEItem const* lpeitem) { std::vector hp_vec; - // TODO: we can probably optimize this by using a lot more references - // rather than copying PathVectors all over the place - if (SP_IS_SHAPE(lpeitem) && show_orig_path) { - // add original path to helperpaths - SPCurve* curve = SP_SHAPE(lpeitem)->getCurve (); - hp_vec.push_back(curve->get_pathvector()); - } - // add indicators provided by the effect itself addCanvasIndicators(lpeitem, hp_vec); -- cgit v1.2.3 From ba32027677dee7700542b236410411fca62ba9c7 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Mon, 16 Jun 2014 23:34:16 +0200 Subject: fixes to LPEKnot, now usable again. knotholder: if knot coords are non-finite, hide knot. used for hiding the lpeknot switcher knot if there are no crossings Fixed bugs: - https://launchpad.net/bugs/781893 (bzr r13428) --- src/live_effects/lpe-knot.cpp | 24 +++++++++++++----------- src/live_effects/lpe-knot.h | 1 - 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 581c632f5..cac3a9347 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -353,7 +353,11 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : add_other_stroke_width(_("_Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true), switcher_size(_("S_witcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15), crossing_points_vector(_("Crossing Signs"), _("Crossings signs"), "crossing_points_vector", &wr, this), - gpaths(),gstroke_widths() + crossing_points(), + gpaths(), + gstroke_widths(), + selectedCrossing(0), + switcher(0.,0.) { // register all your parameters here, so Inkscape knows which parameters this effect has: registerParameter( dynamic_cast(&interruption_width) ); @@ -363,10 +367,6 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast(&switcher_size) ); registerParameter( dynamic_cast(&crossing_points_vector) ); - crossing_points = LPEKnotNS::CrossingPoints(); - selectedCrossing = 0; - switcher = Geom::Point(0,0); - _provides_knotholder_entities = true; } @@ -386,9 +386,7 @@ LPEKnot::updateSwitcher(){ //std::cout<<"placing switcher at "<(); - gstroke_widths = std::vector(); + gpaths.clear(); + gstroke_widths.clear(); + collectPathsAndWidths(lpeitem, gpaths, gstroke_widths); // std::cout<<"\nPaths on input:\n"; @@ -586,7 +585,10 @@ LPEKnot::doBeforeEffect (SPLPEItem const* lpeitem) // std::cout< crossing_points_vector;//svg storage of crossing_points LPEKnotNS::CrossingPoints crossing_points;//topology representation of the knot. -- cgit v1.2.3 From 371f45365a6b6ea42d17c8ea33cc0072f318967e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 2 Jul 2014 13:14:35 +0200 Subject: Add LPE fillet-chamfer (bzr r13341.1.74) --- src/live_effects/Makefile_insert | 2 + src/live_effects/effect.cpp | 3 + src/live_effects/lpe-fillet-chamfer.cpp | 687 +++++++++++++++++++++ src/live_effects/lpe-fillet-chamfer.h | 68 ++ src/live_effects/parameter/Makefile_insert | 2 + .../parameter/filletchamferpointarray.cpp | 653 ++++++++++++++++++++ .../parameter/filletchamferpointarray.h | 117 ++++ 7 files changed, 1532 insertions(+) create mode 100644 src/live_effects/lpe-fillet-chamfer.cpp create mode 100644 src/live_effects/lpe-fillet-chamfer.h create mode 100644 src/live_effects/parameter/filletchamferpointarray.cpp create mode 100644 src/live_effects/parameter/filletchamferpointarray.h (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index c47003747..263b33b3c 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -32,6 +32,8 @@ ink_common_sources += \ live_effects/lpe-curvestitch.h \ live_effects/lpe-constructgrid.cpp \ live_effects/lpe-constructgrid.h \ + live_effects/lpe-fillet-chamfer.cpp \ + live_effects/lpe-fillet-chamfer.h \ live_effects/lpe-gears.cpp \ live_effects/lpe-gears.h \ live_effects/lpe-interpolate.cpp \ diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index d0a168a14..f70a540e8 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -263,6 +263,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case ENVELOPE_PERSPECTIVE: neweffect = static_cast ( new LPEEnvelopePerspective(lpeobj) ); break; + case FILLET_CHAMFER: + neweffect = static_cast ( new LPEFilletChamfer(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp new file mode 100644 index 000000000..c25e3bffd --- /dev/null +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -0,0 +1,687 @@ +/* + * Copyright (C) Jabiertxo Arraiza Cenoz + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * Also to Mc- (IRC nick) for his important contribution to find real time + * values based on + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-fillet-chamfer.h" +#include +#include "style.h" +#include "live_effects/parameter/filletchamferpointarray.h" +//for update knot +#include <2geom/svg-elliptical-arc.h> +#include <2geom/line.h> +#include "selection.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/selectable-control-point.h" +#include <2geom/sbasis-to-bezier.h> +#include "ui/tool/node.h" +// FIXME: The following are only needed to convert the path's SPCurve* to pwd2. +// There must be a more convenient way to achieve this. +#include "display/curve.h" +#include "helper/geom-nodetype.h" +#include "desktop.h" +#include "ui/tools/node-tool.h" +#include +#include +#include + +using namespace Geom; +namespace Inkscape { +namespace LivePathEffect { + +const double tolerance = 0.001; +const double gapHelper = 0.00001; + +LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + fillet_chamfer_values(_("Fillet point"), _("Fillet point"), + "fillet_chamfer_values", &wr, this), + hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, + false), + ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), + "ignore_radius_0", &wr, this, false), + only_selected(_("Change only selected nodes"), + _("Change only selected nodes"), "only_selected", &wr, this, + false), + flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), + "flexible", &wr, this, false), + unit(_("Unit"), _("Unit"), "unit", &wr, this), + radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, + this, 0.), + helper_size(_("Helper size with direction"), + _("Helper size with direction"), "helper_size", &wr, this, + 0) +{ + registerParameter(dynamic_cast(&fillet_chamfer_values)); + registerParameter(dynamic_cast(&unit)); + registerParameter(dynamic_cast(&radius)); + registerParameter(dynamic_cast(&helper_size)); + registerParameter(dynamic_cast(&flexible)); + registerParameter(dynamic_cast(&ignore_radius_0)); + registerParameter(dynamic_cast(&only_selected)); + registerParameter(dynamic_cast(&hide_knots)); + radius.param_set_range(0., infinity()); + radius.param_set_increments(1, 1); + radius.param_set_digits(4); + helper_size.param_set_range(0, infinity()); + helper_size.param_set_increments(5, 5); + helper_size.param_set_digits(0); +} + +LPEFilletChamfer::~LPEFilletChamfer() {} + +Gtk::Widget *LPEFilletChamfer::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(2); + std::vector::iterator it = param_vector.begin(); + 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 == "radius") { + Inkscape::UI::Widget::Scalar *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet)); + widg = dynamic_cast(widgRegistered); + if (widg) { + Gtk::HBox *scalarParameter = dynamic_cast(widg); + std::vector childList = + scalarParameter->get_children(); + Gtk::Entry *entryWidg = dynamic_cast(childList[1]); + entryWidg->set_width_chars(6); + } + } + if (param->param_key == "flexible") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed)); + widg = dynamic_cast(widgRegistered); + } + if (param->param_key == "helper_size") { + Inkscape::UI::Widget::Scalar *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); + widg = dynamic_cast(widgRegistered); + + } + if (param->param_key == "hide_knots") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide)); + widg = dynamic_cast(widgRegistered); + } + if (param->param_key == "only_selected") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } + if (param->param_key == "ignore_radius_0") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } + 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; + } + + Gtk::HBox *filletButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::Button *fillet = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); + fillet->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); + filletButtonsContainer->pack_start(*fillet, true, true, 2); + Gtk::Button *inverse = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); + inverse->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse)); + filletButtonsContainer->pack_start(*inverse, true, true, 2); + + Gtk::HBox *chamferButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::Button *chamfer = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); + chamfer->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + chamferButtonsContainer->pack_start(*chamfer, true, true, 2); + Gtk::Button *doubleChamfer = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Double chamfer")))); + doubleChamfer->signal_clicked() + .connect(sigc::mem_fun(*this, &LPEFilletChamfer::doubleChamfer)); + chamferButtonsContainer->pack_start(*doubleChamfer, true, true, 2); + vbox->pack_start(*filletButtonsContainer, true, true, 2); + vbox->pack_start(*chamferButtonsContainer, true, true, 2); + + return dynamic_cast(vbox); +} + +void LPEFilletChamfer::toggleHide() +{ + std::vector filletChamferData = fillet_chamfer_values.data(); + std::vector result; + for (std::vector::const_iterator point_it = filletChamferData.begin(); + point_it != filletChamferData.end(); ++point_it) { + if (hide_knots) { + result.push_back(Point((*point_it)[X], abs((*point_it)[Y]) * -1)); + } else { + result.push_back(Point((*point_it)[X], abs((*point_it)[Y]))); + } + } + fillet_chamfer_values.param_set_and_write_new_value(result); + refreshKnots(); +} + +void LPEFilletChamfer::toggleFlexFixed() +{ + std::vector filletChamferData = fillet_chamfer_values.data(); + std::vector result; + unsigned int i = 0; + for (std::vector::const_iterator point_it = filletChamferData.begin(); + point_it != filletChamferData.end(); ++point_it) { + if (flexible) { + result.push_back(Point(fillet_chamfer_values.to_time(i, (*point_it)[X]), + (*point_it)[Y])); + } else { + result.push_back(Point(fillet_chamfer_values.to_len(i, (*point_it)[X]), + (*point_it)[Y])); + } + i++; + } + if (flexible) { + radius.param_set_range(0., 100); + radius.param_set_value(0); + } else { + radius.param_set_range(0., infinity()); + radius.param_set_value(0); + } + fillet_chamfer_values.param_set_and_write_new_value(result); +} + +void LPEFilletChamfer::updateFillet() +{ + double power = 0; + if (!flexible) { + power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), + "px") * -1; + } else { + power = radius; + } + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doUpdateFillet(path_from_piecewise(pwd2, tolerance), power); +} + +void LPEFilletChamfer::fillet() +{ + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 1); +} + +void LPEFilletChamfer::inverse() +{ + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 2); +} + +void LPEFilletChamfer::chamfer() +{ + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 3); +} + +void LPEFilletChamfer::doubleChamfer() +{ + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), 4); +} + +void LPEFilletChamfer::refreshKnots() +{ + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + fillet_chamfer_values.recalculate_knots(pwd2); + SPDesktop *desktop = inkscape_active_desktop(); + if (tools_isactive(desktop, TOOLS_NODES)) { + tools_switch(desktop, TOOLS_SELECT); + tools_switch(desktop, TOOLS_NODES); + } +} + +bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, + std::vector point) +{ + if (point.size() > 0) { + for (std::vector::iterator i = point.begin(); i != point.end(); + ++i) { + Geom::Point p = *i; + if (Geom::are_near(p, nodePoint, 2)) { + return true; + } + } + } + return false; +} +void LPEFilletChamfer::doUpdateFillet(std::vector original_pathv, + double power) +{ + std::vector point; + SPDesktop *desktop = inkscape_active_desktop(); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nodeTool = + INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = + nodeTool->_selected_nodes->allPoints(); + std::vector::iterator pBegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = + selection.begin(); + i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast(*i); + pBegin = point.begin(); + point.insert(pBegin, desktop->doc2dt(n->position())); + } + } + } + std::vector filletChamferData = fillet_chamfer_values.data(); + std::vector result; + int counter = 0; + for (PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + int pathCounter = 0; + if (path_it->empty()) + continue; + + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + double powerend = 0; + while (curve_it1 != curve_endit) { + powerend = power; + if (power > 0) { + powerend = counter + (power / 100); + } + if (ignore_radius_0 && (filletChamferData[counter][X] == 0 || + filletChamferData[counter][X] == counter)) { + powerend = filletChamferData[counter][X]; + } + if (filletChamferData[counter][Y] == 0) { + powerend = filletChamferData[counter][X]; + } + if (only_selected && !nodeIsSelected(curve_it1->initialPoint(), point)) { + powerend = filletChamferData[counter][X]; + } + result.push_back(Point(powerend, filletChamferData[counter][Y])); + ++curve_it1; + ++curve_it2; + counter++; + pathCounter++; + } + } + fillet_chamfer_values.param_set_and_write_new_value(result); +} + +void LPEFilletChamfer::doChangeType(std::vector original_pathv, + int type) +{ + std::vector point; + SPDesktop *desktop = inkscape_active_desktop(); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nodeTool = + INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = + nodeTool->_selected_nodes->allPoints(); + std::vector::iterator pBegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = + selection.begin(); + i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast(*i); + pBegin = point.begin(); + point.insert(pBegin, desktop->doc2dt(n->position())); + } + } + } + std::vector filletChamferData = fillet_chamfer_values.data(); + std::vector result; + int counter = 0; + for (PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + int pathCounter = 0; + if (path_it->empty()) + continue; + + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + while (curve_it1 != curve_endit) { + bool toggle = true; + if (filletChamferData[counter][Y] == 0 || + (ignore_radius_0 && (filletChamferData[counter][X] == 0 || + filletChamferData[counter][X] == counter)) || + (only_selected && + !nodeIsSelected(curve_it1->initialPoint(), point))) { + toggle = false; + } + if (toggle) { + result.push_back(Point(filletChamferData[counter][X], type)); + } else { + result.push_back(filletChamferData[counter]); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + pathCounter++; + } + } + fillet_chamfer_values.param_set_and_write_new_value(result); +} + +void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) +{ + if (SP_IS_SHAPE(lpeItem)) { + std::vector point; + PathVector const &original_pathv = + SP_SHAPE(lpeItem)->_curve->get_pathvector(); + Piecewise > pwd2_in = paths_to_pw(original_pathv); + for (PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + if (path_it->empty()) + continue; + + 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(); + // 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(); + } + } + int counter = 0; + while (curve_it1 != curve_endit) { + Geom::NodeType nodetype; + if (counter == 0) { + if (path_it->closed()) { + nodetype = get_nodetype(path_it->back_default(), *curve_it1); + } else { + nodetype = NODE_NONE; + } + } else { + nodetype = get_nodetype((*path_it)[counter - 1], *curve_it1); + } + if (nodetype == NODE_CUSP) { + point.push_back(Point(0, 1)); + } else { + point.push_back(Point(0, 0)); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + } + } + fillet_chamfer_values.param_set_and_write_new_value(point); + } else { + g_warning("LPE Fillet can only be applied to shapes (not groups)."); + } +} + +void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) +{ + if (SP_IS_SHAPE(lpeItem)) { + fillet_chamfer_values.set_helper_size(helper_size); + fillet_chamfer_values.set_unit(unit.get_abbreviation()); + SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem) + ->get_original_curve() + : SP_SHAPE(lpeItem)->getCurve(); + std::vector filletChamferData = fillet_chamfer_values.data(); + if (!filletChamferData.empty() && getKnotsNumber(c) != (int) + filletChamferData.size()) { + PathVector const original_pathv = c->get_pathvector(); + Piecewise > pwd2_in = paths_to_pw(original_pathv); + fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in); + } + } else { + g_warning("LPE Fillet can only be applied to shapes (not groups)."); + } +} + +int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) +{ + int nKnots = c->nodes_in_path(); + PathVector const pv = c->get_pathvector(); + for (std::vector::const_iterator path_it = pv.begin(); + path_it != pv.end(); ++path_it) { + if (!(*path_it).closed()) { + nKnots--; + } + } + return nKnots; +} + +void +LPEFilletChamfer::adjustForNewPath(std::vector const &path_in) +{ + if (!path_in.empty()) { + fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(path_in[0] + .toPwSb()); + } +} + +std::vector +LPEFilletChamfer::doEffect_path(std::vector const &path_in) +{ + std::vector pathvector_out; + Piecewise > pwd2_in = paths_to_pw(path_in); + pwd2_in = remove_short_cuts(pwd2_in, .01); + Piecewise > der = derivative(pwd2_in); + Piecewise > n = rot90(unitVector(der)); + fillet_chamfer_values.set_pwd2(pwd2_in, n); + std::vector filletChamferData = fillet_chamfer_values.data(); + int counter = 0; + //from http://launchpadlibrarian.net/12692602/rcp.svg + const double K = (4. / 3) * (sqrt(2) - 1); + for (PathVector::const_iterator path_it = path_in.begin(); + path_it != path_in.end(); ++path_it) { + if (path_it->empty()) + continue; + Geom::Path path_out; + 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(); + // 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(); + } + } + int counterCurves = 0; + while (curve_it1 != curve_endit) { + Coord it1_length = (*curve_it1).length(tolerance); + double time_it1, time_it2, time_it1_B, intpart; + time_it1 = modf( + fillet_chamfer_values.to_time(counter, filletChamferData[counter][X]), + &intpart); + if (filletChamferData[counter][Y] == 0) { + time_it1 = 0; + } + time_it2 = modf(fillet_chamfer_values.to_time( + counter + 1, filletChamferData[counter + 1][X]), + &intpart); + if (curve_it2 == curve_endit) { + time_it2 = modf(fillet_chamfer_values.to_time( + counter - counterCurves, + filletChamferData[counter - counterCurves][X]), + &intpart); + } + double resultLenght = + it1_length + fillet_chamfer_values.to_len( + counter + 1, filletChamferData[counter + 1][X]); + time_it1_B = 1; + if (path_it->closed() && curve_it2 == curve_endit) { + resultLenght = + it1_length + fillet_chamfer_values.to_len( + counter - counterCurves, + filletChamferData[counter - counterCurves][X]); + } + if (resultLenght > 0 && time_it2 != 0) { + time_it1_B = modf(fillet_chamfer_values.to_time(counter, -resultLenght), + &intpart); + } else { + if (time_it2 == 0) { + time_it1_B = 1; + } else { + time_it1_B = gapHelper; + } + } + if (filletChamferData[counter + 1][Y] == 0) { + time_it1_B = 1; + time_it2 = 0; + } + if (time_it1_B < time_it1) { + time_it1_B = time_it1 + gapHelper; + } + Curve *knotCurve1 = curve_it1->portion(time_it1, time_it1_B); + if (counterCurves > 0) { + knotCurve1->setInitial(path_out.finalPoint()); + } else { + path_out.start((*curve_it1).pointAt(time_it1)); + } + Curve *knotCurve2 = (*path_it).front().portion(time_it2, 1); + if (curve_it2 != curve_endit) { + knotCurve2 = (*curve_it2).portion(time_it2, 1); + } + Point startArcPoint = knotCurve1->finalPoint(); + Point endArcPoint = (*path_it).front().pointAt(time_it2); + if (curve_it2 != curve_endit) { + endArcPoint = (*curve_it2).pointAt(time_it2); + } + double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K; + double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K; + Geom::CubicBezier const *cubic1 = + dynamic_cast(&*knotCurve1); + Ray ray1(startArcPoint, curve_it1->finalPoint()); + if (cubic1) { + ray1.setPoints((*cubic1)[2], startArcPoint); + } + Point handle1 = Point::polar(ray1.angle(),k1) + startArcPoint; + Geom::CubicBezier const *cubic2 = + dynamic_cast(&*knotCurve2); + Ray ray2(curve_it1->finalPoint(), endArcPoint); + if (cubic2) { + ray2.setPoints(endArcPoint, (*cubic2)[1]); + } + Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); + bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, + endArcPoint - startArcPoint) < 0; + double angle = angle_between(ray1, ray2, ccwToggle); + double handleAngle = ray1.angle() - angle; + if (ccwToggle) { + handleAngle = ray1.angle() + angle; + } + Point inverseHandle1 = Point::polar(handleAngle,k1) + startArcPoint; + handleAngle = ray2.angle() + angle; + if (ccwToggle) { + handleAngle = ray2.angle() - angle; + } + Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); + if (time_it1_B != 1) { + if (time_it1_B != gapHelper && time_it1_B != time_it1 + gapHelper) { + path_out.append(*knotCurve1); + } + int type = abs(filletChamferData[counter + 1][Y]); + if (type == 3 || type == 4) { + if (type == 4) { + Geom::Point central = middle_point(startArcPoint, endArcPoint); + LineSegment chamferCenter(central, curve_it1->finalPoint()); + path_out.appendNew(chamferCenter.pointAt(0.5)); + } + path_out.appendNew(endArcPoint); + } else if (type == 2) { + path_out.appendNew(inverseHandle1, inverseHandle2, + endArcPoint); + } else { + path_out.appendNew(handle1, handle2, endArcPoint); + } + } else { + path_out.append(*knotCurve1); + } + if (path_it->closed() && curve_it2 == curve_endit) { + path_out.close(); + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + counterCurves++; + } + pathvector_out.push_back(path_out); + } + return pathvector_out; +} + +}; //namespace LivePathEffect +}; /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offset:((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-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h new file mode 100644 index 000000000..f5eee0205 --- /dev/null +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -0,0 +1,68 @@ +#ifndef INKSCAPE_LPE_FILLET_CHAMFER_H +#define INKSCAPE_LPE_FILLET_CHAMFER_H + +/* + * Inkscape::LPEFilletChamfer + * Copyright (C) Jabiertxo Arraiza Cenoz + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/unit.h" +#include "live_effects/effect.h" +#include "live_effects/parameter/bool.h" +#include "live_effects/parameter/filletchamferpointarray.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEFilletChamfer : public Effect { + +public: + LPEFilletChamfer(LivePathEffectObject *lpeobject); + virtual ~LPEFilletChamfer(); + + std::vector doEffect_path(std::vector const &path_in); + + virtual void doOnApply(SPLPEItem const *lpeItem); + virtual void doBeforeEffect(SPLPEItem const *lpeItem); + virtual int getKnotsNumber(SPCurve const *c); + virtual void adjustForNewPath(std::vector const &path_in); + virtual void toggleHide(); + virtual void toggleFlexFixed(); + virtual void chamfer(); + virtual void fillet(); + virtual void doubleChamfer(); + virtual void inverse(); + virtual void updateFillet(); + virtual void doUpdateFillet(std::vector original_pathv, + double power); + virtual void doChangeType(std::vector original_pathv, int type); + virtual bool nodeIsSelected(Geom::Point nodePoint, + std::vector points); + virtual void refreshKnots(); + virtual Gtk::Widget *newWidget(); + FilletChamferPointArrayParam fillet_chamfer_values; + +private: + + BoolParam hide_knots; + BoolParam ignore_radius_0; + BoolParam only_selected; + BoolParam flexible; + UnitParam unit; + ScalarParam radius; + ScalarParam helper_size; + + LPEFilletChamfer(const LPEFilletChamfer &); + LPEFilletChamfer &operator=(const LPEFilletChamfer &); + +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape +#endif diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index 1026cf11c..1137ef34b 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -22,6 +22,8 @@ ink_common_sources += \ live_effects/parameter/originalpath.h \ live_effects/parameter/powerstrokepointarray.cpp \ live_effects/parameter/powerstrokepointarray.h \ + live_effects/parameter/filletchamferpointarray.cpp \ + live_effects/parameter/filletchamferpointarray.h \ live_effects/parameter/text.cpp \ live_effects/parameter/text.h \ live_effects/parameter/togglebutton.cpp \ diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp new file mode 100644 index 000000000..94a26dd8d --- /dev/null +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -0,0 +1,653 @@ +/* + * Copyright (C) Jabiertxo Arraiza Cenoz + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "knotholder.h" +#include "sp-lpe-item.h" +#include <2geom/piecewise.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/sbasis-geometric.h> +#include "selection.h" + +// needed for on-canvas editting: +#include "desktop.h" +#include "live_effects/lpeobject.h" +#include "helper/geom-nodetype.h" +#include "helper/geom-curves.h" +#include +#include "ui/tools/node-tool.h" +#include + +using namespace Geom; + +namespace Inkscape { + +namespace LivePathEffect { + +FilletChamferPointArrayParam::FilletChamferPointArrayParam( + const Glib::ustring &label, const Glib::ustring &tip, + const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr, + Effect *effect) + : ArrayParam(label, tip, key, wr, effect, 0) +{ + knot_shape = SP_KNOT_SHAPE_DIAMOND; + knot_mode = SP_KNOT_MODE_XOR; + knot_color = 0x00ff0000; +} + +FilletChamferPointArrayParam::~FilletChamferPointArrayParam() {} + +Gtk::Widget *FilletChamferPointArrayParam::param_newWidget() +{ + return NULL; + /* + Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = + Gtk::manage( + new Inkscape::UI::Widget::RegisteredTransformedPoint( + param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() + ) ); + // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Affine transf = desktop->doc2dt(); + pointwdg->setTransform(transf); + pointwdg->setValue( *this ); + pointwdg->clearProgrammatically(); + pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, + _("Change point parameter")); + + Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); + static_cast(hbox)->pack_start(*pointwdg, true, true); + static_cast(hbox)->show_all_children(); + + return dynamic_cast (hbox); + */ +} + +void +FilletChamferPointArrayParam::param_transform_multiply(Affine const &postmul, + bool /*set*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + if (prefs->getBool("/options/transform/rectcorners", true) && + _vector[1][X] <= 0) { + std::vector result; + for (std::vector::const_iterator point_it = _vector.begin(); + point_it != _vector.end(); ++point_it) { + Coord A = + (*point_it)[X] * ((postmul.expansionX() + postmul.expansionY()) / 2); + result.push_back(Point(A, (*point_it)[Y])); + } + param_set_and_write_new_value(result); + } + + // param_set_and_write_new_value( (*this) * postmul ); +} + +/** call this method to recalculate the controlpoints such that they stay at the + * same location relative to the new path. Useful after adding/deleting nodes to + * the path.*/ +void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( + Piecewise > const &pwd2_in) +{ + if (!last_pwd2.empty()) { + PathVector const pathv = + path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); + PathVector last_pathv = + path_from_piecewise(remove_short_cuts(last_pwd2, 0.1), 0.001); + std::vector result; + unsigned long counter = 0; + unsigned long counterPaths = 0; + unsigned long counterCurves = 0; + long offset = 0; + long offsetPaths = 0; + Geom::NodeType nodetype; + for (PathVector::const_iterator path_it = pathv.begin(); + path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + counterPaths++; + counter++; + continue; + } + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + counterCurves = 0; + while (curve_it1 != curve_endit) { + //if start a path get node type + if (counterCurves == 0) { + if (path_it->closed()) { + if (path_it->back_closed().isDegenerate()) { + nodetype = get_nodetype(path_it->back_open(), *curve_it1); + } else { + nodetype = get_nodetype(path_it->back_closed(), *curve_it1); + } + } else { + nodetype = NODE_NONE; + } + } else { + //check node type also whith straight lines because get_nodetype + //return non cusp node in a node inserted inside a straight line + //todo: if the path remove some nodes whith the result of a straight + //line but with handles, the node inserted into dont fire the knot + // because is not handle as cusp node by get_nodetype function + bool this_is_line = true; + bool next_is_line = is_straight_curve(*curve_it1); + this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); + nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); + if (this_is_line || next_is_line) { + nodetype = NODE_CUSP; + } + } + if (last_pathv.size() > pathv.size() || + (last_pathv[counterPaths].size() > counter - offset && + !are_near(curve_it1->initialPoint(), + last_pathv[counterPaths][counter - offset].initialPoint(), + 0.1))) { + if (last_pathv.size() > counterPaths && curve_it2 == curve_endit) { + if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) { + offset = abs(last_pathv[counterPaths].size() - + pathv[counterPaths].size()); + } else if (last_pathv[counterPaths].size() > + pathv[counterPaths].size()) { + offset = (abs(last_pathv[counterPaths].size() - + pathv[counterPaths].size())) * -1; + } else { + offset = 0; + } + offsetPaths += offset; + offset = offsetPaths; + } else if (counterCurves == 0 && last_pathv.size() <= pathv.size() && + counter - offset <= last_pathv[counterPaths].size() && + are_near(curve_it1->initialPoint(), + last_pathv[counterPaths].finalPoint(), 0.1) && + !last_pathv[counterPaths].closed()) { + long e = counter - offset + 1; + std::vector tmp = _vector; + for (unsigned long i = + last_pathv[counterPaths].size() + counter - offset; + i > counterCurves - offset + 1; i--) { + + if (tmp[i - 1][X] > 0) { + double fractpart, intpart; + fractpart = modf(tmp[i - 1][X], &intpart); + _vector[e] = Point(e + fractpart, tmp[i - 1][Y]); + } else { + _vector[e] = Point(tmp[i - 1][X], tmp[i - 1][Y]); + } + e++; + } + //delete temp vector + std::vector().swap(tmp); + if (last_pathv.size() > counterPaths) { + last_pathv[counterPaths] = last_pathv[counterPaths].reverse(); + } + } else { + if (last_pathv.size() > counterPaths) { + if (last_pathv[counterPaths].size() < + pathv[counterPaths].size()) { + offset++; + } else if (last_pathv[counterPaths].size() > + pathv[counterPaths].size()) { + offset--; + continue; + } + } else { + offset++; + } + } + double xPos = 0; + if (_vector[1][X] > 0) { + xPos = nearest_point(curve_it1->initialPoint(), pwd2_in); + } + if (nodetype == NODE_CUSP) { + result.push_back(Point(xPos, 1)); + } else { + result.push_back(Point(xPos, 0)); + } + } else { + double xPos = _vector[counter - offset][X]; + if (_vector.size() <= (unsigned)(counter - offset)) { + if (_vector[1][X] > 0) { + xPos = nearest_point(curve_it1->initialPoint(), pwd2_in); + } else { + xPos = 0; + } + } + if (nodetype == NODE_CUSP) { + double vectorY = _vector[counter - offset][Y]; + if (_vector.size() <= (unsigned)(counter - offset) || vectorY == 0) { + vectorY = 1; + } + result.push_back(Point(xPos, vectorY)); + } else { + if (_vector[1][X] < 0) { + xPos = 0; + } + result.push_back(Point(floor(xPos), 0)); + } + } + ++curve_it1; + if (curve_it2 != curve_endit) { + ++curve_it2; + } + counter++; + counterCurves++; + } + counterPaths++; + } + _vector = result; + write_to_SVG(); + } +} + +void FilletChamferPointArrayParam::recalculate_knots( + Piecewise > const &pwd2_in) +{ + bool change = false; + PathVector pathv = path_from_piecewise(pwd2_in, 0.001); + if (!pathv.empty()) { + std::vector result; + int counter = 0; + int counterCurves = 0; + Geom::NodeType nodetype; + for (PathVector::const_iterator path_it = pathv.begin(); + path_it != pathv.end(); ++path_it) { + if (path_it->empty()) { + counter++; + continue; + } + 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() && path_it->back_closed().isDegenerate()) { + const Curve &closingline = path_it->back_closed(); + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + curve_endit = path_it->end_open(); + } + } + counterCurves = 0; + while (curve_it1 != curve_endit) { + //if start a path get node type + if (counterCurves == 0) { + if (path_it->closed()) { + if (path_it->back_closed().isDegenerate()) { + nodetype = get_nodetype(path_it->back_open(), *curve_it1); + } else { + nodetype = get_nodetype(path_it->back_closed(), *curve_it1); + } + } else { + nodetype = NODE_NONE; + } + } else { + bool this_is_line = true; + bool next_is_line = is_straight_curve(*curve_it1); + this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); + nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); + if (this_is_line || next_is_line) { + nodetype = NODE_CUSP; + } + } + if (nodetype == NODE_CUSP) { + double vectorY = _vector[counter][Y]; + if (vectorY == 0) { + vectorY = 1; + change = true; + } + result.push_back(Point(_vector[counter][X], vectorY)); + } else { + double xPos = floor(_vector[counter][X]); + if (_vector[1][X] < 0) { + xPos = 0; + } + double vectorY = _vector[counter][Y]; + if (vectorY != 0) { + change = true; + } + result.push_back(Point(xPos, 0)); + } + ++curve_it1; + ++curve_it2; + if (curve_it2 != curve_endit) { + counter++; + } + counterCurves++; + } + } + if (change) { + _vector = result; + write_to_SVG(); + } + } +} + +void FilletChamferPointArrayParam::set_pwd2( + Piecewise > const &pwd2_in, + Piecewise > const &pwd2_normal_in) +{ + last_pwd2 = pwd2_in; + last_pwd2_normal = pwd2_normal_in; +} + +void FilletChamferPointArrayParam::set_helper_size(int hs) +{ + helper_size = hs; +} + +void FilletChamferPointArrayParam::set_unit(const gchar *abbr) +{ + unit = abbr; +} + +void FilletChamferPointArrayParam::updateCanvasIndicators() +{ + std::vector ts = data(); + hp.clear(); + unsigned int i = 0; + Piecewise > const &n = get_pwd2_normal(); + for (std::vector::const_iterator point_it = ts.begin(); + point_it != ts.end(); ++point_it) { + double Xvalue = to_time(i, (*point_it)[X]); + double XPlusValue = to_time(i, -helper_size) - i; + if (Xvalue == i) { + i++; + continue; + } + Point canvas_point = last_pwd2.valueAt(Xvalue) + 0 * n.valueAt(Xvalue); + Point start_point = last_pwd2.valueAt(Xvalue + XPlusValue) + + helper_size * n.valueAt(Xvalue + XPlusValue); + Point end_point = last_pwd2.valueAt(Xvalue + XPlusValue) - + helper_size * n.valueAt(Xvalue + XPlusValue); + Geom::Path arrow; + arrow.start(start_point); + arrow.appendNew(canvas_point); + arrow.appendNew(end_point); + hp.push_back(arrow); + i++; + } +} + +void FilletChamferPointArrayParam::addCanvasIndicators( + SPLPEItem const */*lpeitem*/, std::vector &hp_vec) +{ + hp_vec.push_back(hp); +} + +double FilletChamferPointArrayParam::len_to_time(int index, double len) +{ + double t = 0; + if (last_pwd2.size() > (unsigned) index) { + if (len != 0) { + if (last_pwd2[index][0].degreesOfFreedom() != 2) { + Piecewise > u; + u.push_cut(0); + u.push(last_pwd2[index], 1); + std::vector t_roots = roots(arcLengthSb(u) - std::abs(len)); + if (t_roots.size() > 0) { + t = t_roots[0]; + } + } else { + double lenghtPart = 0; + if (last_pwd2.size() > (unsigned) index) { + lenghtPart = length(last_pwd2[index], EPSILON); + } + if (std::abs(len) < lenghtPart && lenghtPart != 0) { + t = std::abs(len) / lenghtPart; + } + } + } + t = double(index) + t; + } else { + t = double(last_pwd2.size() - 1); + } + + return t; +} + +double FilletChamferPointArrayParam::time_to_len(int index, double time) +{ + double intpart; + double len = 0; + time = modf(time, &intpart); + double lenghtPart = 0; + if (last_pwd2.size() <= (unsigned) index || time == 0) { + return len; + } + if (last_pwd2[index][0].degreesOfFreedom() != 2) { + Piecewise > u; + u.push_cut(0); + u.push(last_pwd2[index], 1); + u = portion(u, 0, time); + return length(u, 0.001) * -1; + } + lenghtPart = length(last_pwd2[index], EPSILON); + return (time * lenghtPart) * -1; +} + +double FilletChamferPointArrayParam::to_time(int index, double A) +{ + if (A > 0) { + return A; + } else { + return len_to_time(index, A); + } +} + +double FilletChamferPointArrayParam::to_len(int index, double A) +{ + if (A > 0) { + return time_to_len(index, A); + } else { + return A; + } +} + +void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, + SPKnotModeType mode, + guint32 color) +{ + knot_shape = shape; + knot_mode = mode; + knot_color = color; +} +/* +class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity { +public: + FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam +*p, unsigned int index); + virtual ~FilletChamferPointArrayParamKnotHolderEntity() {} + + virtual void knot_set(Point const &p, Point const &origin, guint state); + virtual Point knot_get() const; + virtual void knot_click(guint state); + virtual void knot_doubleclicked(guint state); + + /Checks whether the index falls within the size of the parameter's vector/ + bool valid_index(unsigned int index) const { + return (_pparam->_vector.size() > index); + }; + +private: + FilletChamferPointArrayParam *_pparam; + unsigned int _index; +}; +/*/ + +FilletChamferPointArrayParamKnotHolderEntity:: +FilletChamferPointArrayParamKnotHolderEntity( + FilletChamferPointArrayParam *p, unsigned int index) + : _pparam(p), _index(index) {} + +void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, + Point const &origin, + guint state) +{ + using namespace Geom; + + if (!valid_index(_index)) { + return; + } + /// @todo how about item transforms??? + Piecewise > const &pwd2 = _pparam->get_pwd2(); + //todo: add snapping + //Geom::Point const s = snap_knot_position(p, state); + double t = nearest_point(p, pwd2[_index]); + if (t == 1) { + t = 0.9999; + } + t += _index; + + if (_pparam->_vector.at(_index)[X] <= 0) { + _pparam->_vector.at(_index) = + Point(_pparam->time_to_len(_index, t), _pparam->_vector.at(_index)[Y]); + } else { + _pparam->_vector.at(_index) = Point(t, _pparam->_vector.at(_index)[Y]); + } + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const +{ + using namespace Geom; + + if (!valid_index(_index)) { + return Point(infinity(), infinity()); + } + + Piecewise > const &pwd2 = _pparam->get_pwd2(); + + double time_it = _pparam->to_time(_index, _pparam->_vector.at(_index)[X]); + Point canvas_point = pwd2.valueAt(time_it); + + _pparam->updateCanvasIndicators(); + return canvas_point; + +} + +void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) +{ + if (state & GDK_CONTROL_MASK) { + using namespace Geom; + double type = _pparam->_vector.at(_index)[Y] + 1; + if (type > 4) { + type = 1; + } + _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type); + _pparam->param_set_and_write_new_value(_pparam->_vector); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + const gchar *tip; + if (type == 3) { + tip = _("Chamfer: Ctrl+click toogle type, " + "Shift+click open dialog"); + } else if (type == 2) { + tip = _("Inverse Fillet: Ctrl+click toogle type, " + "Shift+click open dialog"); + } else if (type == 1) { + tip = _("Fillet: Ctrl+click toogle type, " + "Shift+click open dialog"); + } else { + tip = _("Double Chamfer: Ctrl+click toogle type, " + "Shift+click open dialog"); + } + this->knot->tip = g_strdup(tip); + this->knot->show(); + //} + } else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) { + Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), + _pparam->_vector.at(_index).y()); + Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( + this->desktop, offset, this, _pparam->unit); + } + +} + +void +FilletChamferPointArrayParamKnotHolderEntity::knot_doubleclicked(guint state) +{ + //todo: fill the double click dialog whith this parameters in the added file + //src/ui/dialog/lpe-fillet-chamfer-properties.cpp(.h) + //My idea for when have enought time is: + //label whith radius in percent + //label whith radius in size -maybe handle units- + //entry whith actual radius -in flexible % mode or fixed -?px- + //2 radio options to switch entry from fixed or flexible, also update the + //entry + //Checkbox or two radios to swith fillet or chamfer + +} + +void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset( + Geom::Point offset) +{ + _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y()); + this->parent_holder->knot_ungrabbed_handler(this->knot, 0); +} + +void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, + SPDesktop *desktop, + SPItem *item) +{ + recalculate_knots(get_pwd2()); + for (unsigned int i = 0; i < _vector.size(); ++i) { + if (_vector[i][Y] <= 0) { + continue; + } + const gchar *tip; + if (_vector[i][Y] == 3) { + tip = _("Chamfer: Ctrl+click toogle type, " + "Shift+click open dialog"); + } else if (_vector[i][Y] == 2) { + tip = _("Inverse Fillet: Ctrl+click toogle type, " + "Shift+click open dialog"); + } else if (_vector[i][Y] == 1) { + tip = _("Fillet: Ctrl+click toogle type, " + "Shift+click open dialog"); + } else { + tip = _("Double Chamfer: Ctrl+click toogle type, " + "Shift+click open dialog"); + } + FilletChamferPointArrayParamKnotHolderEntity *e = + new FilletChamferPointArrayParamKnotHolderEntity(this, i); + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip), + knot_shape, knot_mode, knot_color); + knotholder->add(e); + } + updateCanvasIndicators(); +} + +} /* 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/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h new file mode 100644 index 000000000..93d6e9f4c --- /dev/null +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -0,0 +1,117 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H +#define INKSCAPE_LIVEPATHEFFECT_FILLET_CHAMFER_POINT_ARRAY_H + +/* + * Inkscape::LivePathEffectParameters + * Copyright (C) Jabiertxo Arraiza Cenoz + * Special thanks to Johan Engelen for the base of the effect -powerstroke- + * Also to ScislaC for point me to the idea + * Also su_v for his construvtive feedback and time + * and finaly to Liam P. White for his big help on coding, that save me a lot of + * hours + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include <2geom/point.h> + +#include "live_effects/parameter/array.h" + +#include "knot-holder-entity.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class FilletChamferPointArrayParamKnotHolderEntity; + +class FilletChamferPointArrayParam : public ArrayParam { +public: + FilletChamferPointArrayParam(const Glib::ustring &label, + const Glib::ustring &tip, + const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, + Effect *effect); + virtual ~FilletChamferPointArrayParam(); + + virtual Gtk::Widget *param_newWidget(); + + virtual void param_transform_multiply(Geom::Affine const &postmul, + bool /*set*/); + + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, + guint32 color); + virtual double to_time(int index, double A); + virtual double to_len(int index, double A); + virtual double len_to_time(int index, double len); + virtual double time_to_len(int index, double time); + virtual void set_helper_size(int hs); + virtual void set_unit(const gchar *abbr); + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, + std::vector &hp_vec); + virtual bool providesKnotHolderEntities() const { + return true; + } + virtual void updateCanvasIndicators(); + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, + SPItem *item); + + void set_pwd2(Geom::Piecewise > const &pwd2_in, + Geom::Piecewise > const &pwd2_normal_in); + Geom::Piecewise > const &get_pwd2() const { + return last_pwd2; + } + Geom::Piecewise > const &get_pwd2_normal() const { + return last_pwd2_normal; + } + + void recalculate_controlpoints_for_new_pwd2( + Geom::Piecewise > const &pwd2_in); + void recalculate_knots( + Geom::Piecewise > const &pwd2_in); + friend class FilletChamferPointArrayParamKnotHolderEntity; + +private: + FilletChamferPointArrayParam(const FilletChamferPointArrayParam &); + FilletChamferPointArrayParam &operator=(const FilletChamferPointArrayParam &); + + SPKnotShapeType knot_shape; + SPKnotModeType knot_mode; + guint32 knot_color; + int helper_size; + const gchar *unit; + Geom::PathVector hp; + + Geom::Piecewise > last_pwd2; + Geom::Piecewise > last_pwd2_normal; +}; + +class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity { +public: + FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam *p, + unsigned int index); + virtual ~FilletChamferPointArrayParamKnotHolderEntity() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, + guint state); + virtual Geom::Point knot_get() const; + virtual void knot_click(guint state); + virtual void knot_doubleclicked(guint state); + virtual void knot_set_offset(Geom::Point offset); + + /*Checks whether the index falls within the size of the parameter's vector*/ + bool valid_index(unsigned int index) const { + return (_pparam->_vector.size() > index); + } + ; + +private: + FilletChamferPointArrayParam *_pparam; + unsigned int _index; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif -- cgit v1.2.3 From 22e482dd499a412dba05b570fec09cf08bc668f2 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 2 Jul 2014 13:29:03 +0200 Subject: Fixed CMakeLists.txt pointed by Liam (bzr r13341.1.75) --- src/live_effects/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 5d365bb21..a4d35b339 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -14,6 +14,7 @@ set(live_effects_SRC lpe-envelope.cpp lpe-envelope-perspective.cpp lpe-extrude.cpp + lpe-fillet-chamfer.cpp lpe-gears.cpp lpe-interpolate.cpp lpe-knot.cpp @@ -48,6 +49,7 @@ set(live_effects_SRC parameter/array.cpp parameter/bool.cpp + parameter/filletchamferpointarray.cpp parameter/parameter.cpp parameter/path.cpp parameter/originalpath.cpp @@ -77,6 +79,7 @@ set(live_effects_SRC lpe-dynastroke.h lpe-envelope.h lpe-extrude.h + lpe-fillet-chamfer.h lpe-gears.h lpe-interpolate.h lpe-knot.h @@ -112,6 +115,7 @@ set(live_effects_SRC parameter/array.h parameter/bool.h + parameter/filletchamferpointarray.h parameter/enum.h parameter/parameter.h parameter/path-reference.h -- cgit v1.2.3 From 0349a5a8eee52baeed06c92aee0d4d3bc3ade043 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 2 Jul 2014 18:18:25 -0400 Subject: Fix build (bzr r13341.1.76) --- src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 4d1c1d8c1..942ef5891 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -54,6 +54,7 @@ enum EffectType { POWERSTROKE, CLONE_ORIGINAL, ENVELOPE_PERSPECTIVE, + 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 f70a540e8..6e0960216 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -49,6 +49,7 @@ #include "live_effects/lpe-powerstroke.h" #include "live_effects/lpe-clone-original.h" #include "live_effects/lpe-envelope-perspective.h" +#include "live_effects/lpe-fillet-chamfer.h" #include "xml/node-event-vector.h" #include "sp-object.h" -- cgit v1.2.3 From c9db2b11320dffc291faaf044815d3c4c782211e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 3 Jul 2014 00:29:58 +0200 Subject: Put correctly doubles in a function (bzr r13341.1.77) --- src/live_effects/lpe-fillet-chamfer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index c25e3bffd..1fb68020d 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -525,7 +525,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) std::vector filletChamferData = fillet_chamfer_values.data(); int counter = 0; //from http://launchpadlibrarian.net/12692602/rcp.svg - const double K = (4. / 3) * (sqrt(2) - 1); + const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); for (PathVector::const_iterator path_it = path_in.begin(); path_it != path_in.end(); ++path_it) { if (path_it->empty()) -- cgit v1.2.3 From 962ef8a02c2dbaf2049c1951ec8953ba885f9e19 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 5 Jul 2014 12:01:13 -0400 Subject: Fix FTBFS gtk3 & make check (bzr r13341.1.78) --- src/live_effects/parameter/filletchamferpointarray.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 94a26dd8d..457b68dd2 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -8,6 +8,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <2geom/piecewise.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/sbasis-geometric.h> + #include "ui/dialog/lpe-fillet-chamfer-properties.h" #include "live_effects/parameter/filletchamferpointarray.h" #include "live_effects/effect.h" @@ -15,9 +19,6 @@ #include "svg/stringstream.h" #include "knotholder.h" #include "sp-lpe-item.h" -#include <2geom/piecewise.h> -#include <2geom/sbasis-to-bezier.h> -#include <2geom/sbasis-geometric.h> #include "selection.h" // needed for on-canvas editting: @@ -25,8 +26,10 @@ #include "live_effects/lpeobject.h" #include "helper/geom-nodetype.h" #include "helper/geom-curves.h" -#include #include "ui/tools/node-tool.h" + +// TODO due to internal breakage in glibmm headers, +// this has to be included last. #include using namespace Geom; -- cgit v1.2.3 From f0c7df3517326ecf248ee6e768e1c835d072561c Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 6 Jul 2014 10:13:13 -0400 Subject: Fix an oddity with path effects dialog, gtk3 only (bzr r13341.1.79) --- src/live_effects/parameter/parameter.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index a5de2169e..401d89884 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -43,6 +43,14 @@ Parameter::param_write_to_repr(const char * svgd) param_effect->getRepr()->setAttribute(param_key.c_str(), svgd); } + +// In gtk2, this wasn't an issue; we could toss around +// G_MAXDOUBLE and not worry about size allocations. But +// in gtk3, it is an issue: it allocates widget size for the maxmium +// value you pass to it, leading to some insane lengths. +const double SCALARPARAM_G_MAXDOUBLE = 10000000000; + + /*########################################### * REAL PARAM */ @@ -51,8 +59,8 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, gdouble default_value) : Parameter(label, tip, key, wr, effect), value(default_value), - min(-G_MAXDOUBLE), - max(G_MAXDOUBLE), + min(-SCALARPARAM_G_MAXDOUBLE), + max(SCALARPARAM_G_MAXDOUBLE), integer(false), defvalue(default_value), digits(2), -- cgit v1.2.3 From f021bb175a1d26ffe8f51df479c3cc23abfbbde4 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 6 Jul 2014 11:39:19 -0400 Subject: Extension of fix for 13420: effects often set upper limit to inf, causing problems in gtk3 (bzr r13341.1.80) --- src/live_effects/parameter/parameter.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 401d89884..7732eee76 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -48,6 +48,7 @@ Parameter::param_write_to_repr(const char * svgd) // G_MAXDOUBLE and not worry about size allocations. But // in gtk3, it is an issue: it allocates widget size for the maxmium // value you pass to it, leading to some insane lengths. +// If you need this to be more, please be conservative about it. const double SCALARPARAM_G_MAXDOUBLE = 10000000000; @@ -116,8 +117,22 @@ ScalarParam::param_set_value(gdouble val) void ScalarParam::param_set_range(gdouble min, gdouble max) { - this->min = min; - this->max = max; + // if you look at client code, you'll see that many effects + // has a tendency to set an upper range of Geom::infinity(). + // Once again, in gtk2, this is not a problem. But in gtk3, + // widgets get allocated the amount of size they ask for, + // leading to excessively long widgets. + + if (min >= -SCALARPARAM_G_MAXDOUBLE) { + this->min = min; + } else { + this->min = -SCALARPARAM_G_MAXDOUBLE; + } + if (max <= SCALARPARAM_G_MAXDOUBLE) { + this->max = max; + } else { + this->max = SCALARPARAM_G_MAXDOUBLE; + } param_set_value(value); // reset value to see whether it is in ranges } -- cgit v1.2.3 From 8ce05e18118b2fb9a1475cd833394d4b40153031 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 6 Jul 2014 13:53:10 -0400 Subject: Coding style improvements (bzr r13341.1.81) --- src/live_effects/effect.cpp | 16 +-- src/live_effects/lpe-fillet-chamfer.cpp | 202 +++++++++++++------------------- src/live_effects/lpe-fillet-chamfer.h | 69 +++++++---- src/live_effects/parameter/bool.h | 2 +- 4 files changed, 134 insertions(+), 155 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 6e0960216..f0611785b 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -108,7 +108,7 @@ const Util::EnumData LPETypeData[] = { {TEXT_LABEL, N_("Text label"), "text_label"}, #endif /* 0.46 */ - {BEND_PATH, N_("Bend"), "bend_path"}, + {BEND_PATH, N_("Bend"), "bend_path"}, {GEARS, N_("Gears"), "gears"}, {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"}, @@ -122,13 +122,15 @@ const Util::EnumData LPETypeData[] = { {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, {SKETCH, N_("Sketch"), "sketch"}, {RULER, N_("Ruler"), "ruler"}, -/* 0.49 */ - {POWERSTROKE, N_("Power stroke"), "powerstroke"}, - {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, +/* 0.91 */ + {POWERSTROKE, N_("Power stroke"), "powerstroke"}, + {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, {BSPLINE, N_("BSpline"), "bspline"}, - {SIMPLIFY, N_("Simplify"), "simplify"}, - {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"}, + {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, + // TRANSLATORS: "Envelope Perspective" should be equivalent to "perspective transformation" + {ENVELOPE_PERSPECTIVE, N_("Envelope Perspective"), "envelope-perspective"}, + {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 1fb68020d..fc2173a67 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -1,36 +1,39 @@ /* - * Copyright (C) Jabiertxo Arraiza Cenoz + * Author(s): + * Jabiertxo Arraiza Cenoz + * + * Copyright (C) 2014 Author(s) + * * Special thanks to Johan Engelen for the base of the effect -powerstroke- * Also to ScislaC for point me to the idea * Also su_v for his construvtive feedback and time * Also to Mc- (IRC nick) for his important contribution to find real time * values based on - * and finaly to Liam P. White for his big help on coding, that save me a lot of - * hours + * and finaly to Liam P. White for his big help on coding, that save me a lot of hours + * * Released under GNU GPL, read the file 'COPYING' for more information */ - #include "live_effects/lpe-fillet-chamfer.h" -#include -#include "style.h" -#include "live_effects/parameter/filletchamferpointarray.h" -//for update knot + +#include <2geom/sbasis-to-bezier.h> #include <2geom/svg-elliptical-arc.h> #include <2geom/line.h> + +#include "desktop.h" +#include "display/curve.h" +#include "helper/geom-nodetype.h" +#include "live_effects/parameter/filletchamferpointarray.h" + +// for programmatically updating knots #include "selection.h" +#include "tools-switch.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/selectable-control-point.h" -#include <2geom/sbasis-to-bezier.h> #include "ui/tool/node.h" -// FIXME: The following are only needed to convert the path's SPCurve* to pwd2. -// There must be a more convenient way to achieve this. -#include "display/curve.h" -#include "helper/geom-nodetype.h" -#include "desktop.h" #include "ui/tools/node-tool.h" -#include -#include -#include + +// TODO due to internal breakage in glibmm headers, this must be last: +#include using namespace Geom; namespace Inkscape { @@ -39,34 +42,26 @@ namespace LivePathEffect { const double tolerance = 0.001; const double gapHelper = 0.00001; -LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) - : Effect(lpeobject), - fillet_chamfer_values(_("Fillet point"), _("Fillet point"), - "fillet_chamfer_values", &wr, this), - hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, - false), - ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), - "ignore_radius_0", &wr, this, false), - only_selected(_("Change only selected nodes"), - _("Change only selected nodes"), "only_selected", &wr, this, - false), - flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), - "flexible", &wr, this, false), - unit(_("Unit"), _("Unit"), "unit", &wr, this), - radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, - this, 0.), - helper_size(_("Helper size with direction"), - _("Helper size with direction"), "helper_size", &wr, this, - 0) +LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + fillet_chamfer_values(_("Fillet point"), _("Fillet point"), "fillet_chamfer_values", &wr, this), + hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this, false), + ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false), + only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), + flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), + unit(_("Unit"), _("Unit"), "unit", &wr, this), + radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), + helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) { - registerParameter(dynamic_cast(&fillet_chamfer_values)); - registerParameter(dynamic_cast(&unit)); - registerParameter(dynamic_cast(&radius)); - registerParameter(dynamic_cast(&helper_size)); - registerParameter(dynamic_cast(&flexible)); - registerParameter(dynamic_cast(&ignore_radius_0)); - registerParameter(dynamic_cast(&only_selected)); - registerParameter(dynamic_cast(&hide_knots)); + registerParameter(&fillet_chamfer_values); + registerParameter(&unit); + registerParameter(&radius); + registerParameter(&helper_size); + registerParameter(&flexible); + registerParameter(&ignore_radius_0); + registerParameter(&only_selected); + registerParameter(&hide_knots); + radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); @@ -90,53 +85,32 @@ Gtk::Widget *LPEFilletChamfer::newWidget() while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter *param = *it; - Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); + Gtk::Widget *widg = param->param_newWidget(); if (param->param_key == "radius") { - Inkscape::UI::Widget::Scalar *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_value_changed() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet)); - widg = dynamic_cast(widgRegistered); + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet)); + widg = widgRegistered; if (widg) { Gtk::HBox *scalarParameter = dynamic_cast(widg); - std::vector childList = - scalarParameter->get_children(); + std::vector childList = scalarParameter->get_children(); Gtk::Entry *entryWidg = dynamic_cast(childList[1]); entryWidg->set_width_chars(6); } + } else if (param->param_key == "flexible") { + Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed)); + } else if (param->param_key == "helper_size") { + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); + } else if (param->param_key == "hide_knots") { + Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide)); + } else if (param->param_key == "only_selected") { + Gtk::manage(widg); + } else if (param->param_key == "ignore_radius_0") { + Gtk::manage(widg); } - if (param->param_key == "flexible") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed)); - widg = dynamic_cast(widgRegistered); - } - if (param->param_key == "helper_size") { - Inkscape::UI::Widget::Scalar *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_value_changed() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::refreshKnots)); - widg = dynamic_cast(widgRegistered); - - } - if (param->param_key == "hide_knots") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleHide)); - widg = dynamic_cast(widgRegistered); - } - if (param->param_key == "only_selected") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widg = dynamic_cast(widgRegistered); - } - if (param->param_key == "ignore_radius_0") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widg = dynamic_cast(widgRegistered); - } + Glib::ustring *tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -153,32 +127,27 @@ Gtk::Widget *LPEFilletChamfer::newWidget() } Gtk::HBox *filletButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *fillet = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); - fillet->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); + Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); + fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); + filletButtonsContainer->pack_start(*fillet, true, true, 2); - Gtk::Button *inverse = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); - inverse->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse)); + Gtk::Button *inverse = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); + inverse->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse)); filletButtonsContainer->pack_start(*inverse, true, true, 2); Gtk::HBox *chamferButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); - Gtk::Button *chamfer = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); - chamfer->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); + chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + chamferButtonsContainer->pack_start(*chamfer, true, true, 2); - Gtk::Button *doubleChamfer = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Double chamfer")))); - doubleChamfer->signal_clicked() - .connect(sigc::mem_fun(*this, &LPEFilletChamfer::doubleChamfer)); + Gtk::Button *doubleChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Double chamfer")))); + doubleChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::doubleChamfer)); chamferButtonsContainer->pack_start(*doubleChamfer, true, true, 2); + vbox->pack_start(*filletButtonsContainer, true, true, 2); vbox->pack_start(*chamferButtonsContainer, true, true, 2); - return dynamic_cast(vbox); + return vbox; } void LPEFilletChamfer::toggleHide() @@ -227,8 +196,7 @@ void LPEFilletChamfer::updateFillet() { double power = 0; if (!flexible) { - power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), - "px") * -1; + power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), "px") * -1; } else { power = radius; } @@ -271,8 +239,7 @@ void LPEFilletChamfer::refreshKnots() } } -bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, - std::vector point) +bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector point) { if (point.size() > 0) { for (std::vector::iterator i = point.begin(); i != point.end(); @@ -285,20 +252,15 @@ bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, } return false; } -void LPEFilletChamfer::doUpdateFillet(std::vector original_pathv, - double power) +void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pathv, double power) { std::vector point; SPDesktop *desktop = inkscape_active_desktop(); if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nodeTool = - INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = - nodeTool->_selected_nodes->allPoints(); + Inkscape::UI::Tools::NodeTool *nodeTool = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = nodeTool->_selected_nodes->allPoints(); std::vector::iterator pBegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = - selection.begin(); - i != selection.end(); ++i) { + for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i) { if ((*i)->selected()) { Inkscape::UI::Node *n = dynamic_cast(*i); pBegin = point.begin(); @@ -350,8 +312,7 @@ void LPEFilletChamfer::doUpdateFillet(std::vector original_pathv, fillet_chamfer_values.param_set_and_write_new_value(result); } -void LPEFilletChamfer::doChangeType(std::vector original_pathv, - int type) +void LPEFilletChamfer::doChangeType(std::vector const& original_pathv, int type) { std::vector point; SPDesktop *desktop = inkscape_active_desktop(); @@ -374,8 +335,7 @@ void LPEFilletChamfer::doChangeType(std::vector original_pathv, std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; int counter = 0; - for (PathVector::const_iterator path_it = original_pathv.begin(); - path_it != original_pathv.end(); ++path_it) { + for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { int pathCounter = 0; if (path_it->empty()) continue; @@ -418,11 +378,9 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) { if (SP_IS_SHAPE(lpeItem)) { std::vector point; - PathVector const &original_pathv = - SP_SHAPE(lpeItem)->_curve->get_pathvector(); + PathVector const &original_pathv = SP_SHAPE(lpeItem)->_curve->get_pathvector(); Piecewise > pwd2_in = paths_to_pw(original_pathv); - for (PathVector::const_iterator path_it = original_pathv.begin(); - path_it != original_pathv.end(); ++path_it) { + for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) continue; diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index f5eee0205..420425650 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -2,50 +2,57 @@ #define INKSCAPE_LPE_FILLET_CHAMFER_H /* - * Inkscape::LPEFilletChamfer - * Copyright (C) Jabiertxo Arraiza Cenoz + * Author(s): + * Jabiertxo Arraiza Cenoz + * + * Copyright (C) 2014 Author(s) + * * Special thanks to Johan Engelen for the base of the effect -powerstroke- * Also to ScislaC for point me to the idea * Also su_v for his construvtive feedback and time - * and finaly to Liam P. White for his big help on coding, that save me a lot of - * hours + * and finaly to Liam P. White for his big help on coding, that save me a lot of hours + * * Released under GNU GPL, read the file 'COPYING' for more information */ + +#include + #include "live_effects/parameter/enum.h" -#include "live_effects/parameter/unit.h" -#include "live_effects/effect.h" #include "live_effects/parameter/bool.h" +#include "live_effects/parameter/unit.h" + #include "live_effects/parameter/filletchamferpointarray.h" +#include "live_effects/effect.h" namespace Inkscape { namespace LivePathEffect { -class LPEFilletChamfer : public Effect { +class LPEFilletChamfer : public Effect { public: LPEFilletChamfer(LivePathEffectObject *lpeobject); virtual ~LPEFilletChamfer(); - std::vector doEffect_path(std::vector const &path_in); + virtual std::vector doEffect_path(std::vector const &path_in); virtual void doOnApply(SPLPEItem const *lpeItem); virtual void doBeforeEffect(SPLPEItem const *lpeItem); - virtual int getKnotsNumber(SPCurve const *c); virtual void adjustForNewPath(std::vector const &path_in); - virtual void toggleHide(); - virtual void toggleFlexFixed(); - virtual void chamfer(); - virtual void fillet(); - virtual void doubleChamfer(); - virtual void inverse(); - virtual void updateFillet(); - virtual void doUpdateFillet(std::vector original_pathv, - double power); - virtual void doChangeType(std::vector original_pathv, int type); - virtual bool nodeIsSelected(Geom::Point nodePoint, - std::vector points); - virtual void refreshKnots(); - virtual Gtk::Widget *newWidget(); + virtual Gtk::Widget* newWidget(); + + int getKnotsNumber(SPCurve const *c); + void toggleHide(); + void toggleFlexFixed(); + void chamfer(); + void fillet(); + void doubleChamfer(); + void inverse(); + void updateFillet(); + void doUpdateFillet(std::vector const& original_pathv, double power); + void doChangeType(std::vector const& original_pathv, int type); + bool nodeIsSelected(Geom::Point nodePoint, std::vector points); + void refreshKnots(); + FilletChamferPointArrayParam fillet_chamfer_values; private: @@ -63,6 +70,18 @@ private: }; -}; //namespace LivePathEffect -}; //namespace Inkscape +} //namespace LivePathEffect +} //namespace Inkscape + #endif + +/* + 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/parameter/bool.h b/src/live_effects/parameter/bool.h index fafb1beca..b45eeb0b3 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -4,7 +4,7 @@ /* * Inkscape::LivePathEffectParameters * -* Copyright (C) Johan Engelen 2007 + * Copyright (C) Johan Engelen 2007 * * Released under GNU GPL, read the file 'COPYING' for more information */ -- cgit v1.2.3 From 57e29f547e8d93040d3aa40205a8ef6b866f61a7 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 7 Jul 2014 16:39:05 +0200 Subject: Changed toogle button to more clear combobox in envelope-prespective LPE (bzr r13341.1.83) --- src/live_effects/lpe-envelope-perspective.cpp | 49 ++++++++++++++++----------- src/live_effects/lpe-envelope-perspective.h | 2 +- 2 files changed, 31 insertions(+), 20 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp index bfd6e56d7..02cb67db3 100644 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ b/src/live_effects/lpe-envelope-perspective.cpp @@ -29,17 +29,29 @@ 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: - 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) + 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(&perspective)); + registerParameter( dynamic_cast(&deform_type)); registerParameter( dynamic_cast(&Up_Left_Point) ); registerParameter( dynamic_cast(&Up_Right_Point) ); registerParameter( dynamic_cast(&Down_Left_Point) ); @@ -54,7 +66,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { using Geom::X; using Geom::Y; double projmatrix[3][3]; - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ std::vector handles(4); handles[0] = Down_Left_Point; handles[1] = Up_Left_Point; @@ -144,7 +156,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { curve_endit = path_it->end_open(); } } - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ nCurve->moveto(project_point(curve_it1->initialPoint(),projmatrix)); }else{ nCurve->moveto(project_point(curve_it1->initialPoint())); @@ -159,7 +171,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { pointAt2 = curve_it1->finalPoint(); } pointAt3 = curve_it1->finalPoint(); - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ pointAt1 = project_point(pointAt1,projmatrix); pointAt2 = project_point(pointAt2,projmatrix); pointAt3 = project_point(pointAt3,projmatrix); @@ -181,7 +193,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { pointAt2 = curve_it1->finalPoint(); } pointAt3 = curve_it1->finalPoint(); - if(perspective){ + if(deform_type == DEFORMATION_PERSPECTIVE){ pointAt1 = project_point(pointAt1,projmatrix); pointAt2 = project_point(pointAt2,projmatrix); pointAt3 = project_point(pointAt3,projmatrix); @@ -191,7 +203,7 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) { pointAt3 = project_point(pointAt3); } nCurve->curveto(pointAt1, pointAt2, pointAt3); - if(perspective){ + 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); @@ -251,13 +263,6 @@ LPEEnvelopePerspective::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::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)); @@ -319,6 +324,12 @@ LPEEnvelopePerspective::newWidget() 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,&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); } @@ -411,4 +422,4 @@ LPEEnvelopePerspective::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: file_type=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 index 6aae33936..0de9a0e35 100644 --- a/src/live_effects/lpe-envelope-perspective.h +++ b/src/live_effects/lpe-envelope-perspective.h @@ -60,7 +60,7 @@ protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); private: - BoolParam perspective; + EnumParam deform_type; PointReseteableParam Up_Left_Point; PointReseteableParam Up_Right_Point; PointReseteableParam Down_Left_Point; -- cgit v1.2.3 From 88e1060e6c6ebcd0ede7cc2841b899d84072aaa0 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 7 Jul 2014 22:10:45 -0400 Subject: Bugged powerstroke point array tried accessing points on a quickly diverging path Fixed bugs: - https://launchpad.net/bugs/1333465 (bzr r13447) --- src/live_effects/parameter/powerstrokepointarray.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index fecdfeda8..647986da6 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -176,7 +176,10 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const Piecewise > const & n = _pparam->get_pwd2_normal(); Point offset_point = _pparam->_vector.at(_index); - + if (offset_point[X] > pwd2.size() || offset_point[X] < 0) { + g_warning("Broken powerstroke point at %f, I won't try to add that", offset_point[X]); + return Geom::Point(infinity(), infinity()); + } Point canvas_point = pwd2.valueAt(offset_point[X]) + offset_point[Y] * n.valueAt(offset_point[X]); return canvas_point; } -- cgit v1.2.3 From d4ca4b1bcfbfb921b3c615d1e39405ae1afc9b40 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 7 Jul 2014 22:11:55 -0400 Subject: Bugged powerstroke point array tried accessing points on a quickly diverging path Fixed bugs: - https://launchpad.net/bugs/1333465 (bzr r13341.1.86) --- src/live_effects/parameter/powerstrokepointarray.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index fecdfeda8..647986da6 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -176,7 +176,10 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() const Piecewise > const & n = _pparam->get_pwd2_normal(); Point offset_point = _pparam->_vector.at(_index); - + if (offset_point[X] > pwd2.size() || offset_point[X] < 0) { + g_warning("Broken powerstroke point at %f, I won't try to add that", offset_point[X]); + return Geom::Point(infinity(), infinity()); + } Point canvas_point = pwd2.valueAt(offset_point[X]) + offset_point[Y] * n.valueAt(offset_point[X]); return canvas_point; } -- cgit v1.2.3 From 4dd0c8e37a02f75a7e301cc6ef7292bb18e86b44 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 8 Jul 2014 10:58:09 -0400 Subject: Add signals to ToggleButton; more coding style (bzr r13341.1.87) --- src/live_effects/lpe-bspline.cpp | 1242 +++++++++++++-------------- src/live_effects/lpe-bspline.h | 52 +- src/live_effects/lpe-fillet-chamfer.cpp | 4 +- src/live_effects/parameter/togglebutton.cpp | 19 +- src/live_effects/parameter/togglebutton.h | 17 +- 5 files changed, 671 insertions(+), 663 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index b19b697c0..a004b8490 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -8,10 +8,13 @@ # include #endif -#if WITH_GLIBMM_2_32 +#if WITH_GLIBMM_2_32 && HAVE_GLIBMM_THREADS_H # include #endif +#include <2geom/bezier-curve.h> +#include <2geom/point.h> + #include #include #include @@ -21,10 +24,7 @@ #include #include - #include "display/curve.h" -#include <2geom/bezier-curve.h> -#include <2geom/point.h> #include "helper/geom-curves.h" #include "live_effects/lpe-bspline.h" #include "live_effects/lpeobject.h" @@ -48,7 +48,8 @@ #include "display/sp-canvas.h" #include #include -// For handling un-continuous paths: + +// For handling non-contiguous paths: #include "message-stack.h" #include "inkscape.h" #include "desktop.h" @@ -58,320 +59,303 @@ using Inkscape::DocumentUndo; namespace Inkscape { namespace LivePathEffect { -LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) - : Effect(lpeobject), - // initialise your parameters here: - //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, - //Geom::Point(100,100)), - steps(_("Steps whith CTRL:"), - _("Change number of steps whith CTRL pressed"), "steps", &wr, this, - 2), - ignoreCusp(_("Ignore cusp nodes:"), _("Change ignoring cusp nodes"), - "ignoreCusp", &wr, this, true), - onlySelected(_("Change only selected nodes:"), - _("Change only selected nodes"), "onlySelected", &wr, this, - false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", - &wr, this, 0.3334) { - registerParameter(dynamic_cast(&weight)); - registerParameter(dynamic_cast(&steps)); - registerParameter(dynamic_cast(&ignoreCusp)); - registerParameter(dynamic_cast(&onlySelected)); - weight.param_set_range(0.0000, 1); - weight.param_set_increments(0.1, 0.1); - weight.param_set_digits(4); - steps.param_set_range(1, 10); - steps.param_set_increments(1, 1); - steps.param_set_digits(0); +LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), + ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), + onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 0.3334) +{ + registerParameter(&weight); + registerParameter(&steps); + registerParameter(&ignoreCusp); + registerParameter(&onlySelected); + + weight.param_set_range(0.0000, 1); + weight.param_set_increments(0.1, 0.1); + weight.param_set_digits(4); + + steps.param_set_range(1, 10); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); } LPEBSpline::~LPEBSpline() {} -void LPEBSpline::createAndApply(const char *name, SPDocument *doc, - SPItem *item) { - if (!SP_IS_SHAPE(item)) { - g_warning("LPE BSpline can only be applied to shapes (not groups)."); - } else { - // Path effect definition - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); - repr->setAttribute("effect", name); - - doc->getDefs()->getRepr() - ->addChild(repr, NULL); // adds to and assigns the 'id' attribute - const gchar *repr_id = repr->attribute("id"); - Inkscape::GC::release(repr); - - gchar *href = g_strdup_printf("#%s", repr_id); - SP_LPE_ITEM(item)->addPathEffect(href, true); - g_free(href); - } -} - -void LPEBSpline::doEffect(SPCurve *curve) { - if (curve->get_segment_count() < 1) - return; - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - curve->reset(); - - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo - 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 - - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point previousNode(0, 0); - Geom::Point node(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::Point nextPointAt2(0, 0); - Geom::Point nextPointAt3(0, 0); - Geom::D2 SBasisIn; - Geom::D2 SBasisOut; - Geom::D2 SBasisHelper; - Geom::CubicBezier const *cubic = NULL; - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline - nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while (curve_it2 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path - //recto de entrada y de salida - SPCurve *in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - SBasisIn = in->first_segment()->toSBasis(); - pointAt1 = SBasisIn.valueAt( - Geom::nearest_point((*cubic)[1], *in->first_segment())); - pointAt2 = SBasisIn.valueAt( - Geom::nearest_point((*cubic)[2], *in->first_segment())); - } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - in->reset(); - delete in; - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - SPCurve *out = new SPCurve(); - out->moveto(curve_it2->initialPoint()); - out->lineto(curve_it2->finalPoint()); - cubic = dynamic_cast(&*curve_it2); - if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt( - Geom::nearest_point((*cubic)[1], *out->first_segment())); - nextPointAt2 = SBasisOut.valueAt( - Geom::nearest_point((*cubic)[2], *out->first_segment())); - ; - nextPointAt3 = out->first_segment()->finalPoint(); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de - //los manejadores de la curva - SPCurve *lineHelper = new SPCurve(); - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de - //principio de curva - previousNode = node; - //Y este hará de final de curva - node = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, node); - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - SPCurve *out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); - nextPointAt3 = out->first_segment()->finalPoint(); +void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) +{ + if (!SP_IS_SHAPE(item)) { + g_warning("LPE BSpline can only be applied to shapes (not groups)."); } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //Si está cerrada la curva, la cerramos sobre el valor guardado - //previamente - //Si no finalizamos en el punto final - Geom::Point startNode = path_it->begin()->initialPoint(); - if (path_it->closed()) { - SPCurve *start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - Geom::D2 SBasisStart = start->first_segment()->toSBasis(); - SPCurve *lineHelper = new SPCurve(); - cubic = dynamic_cast(&*path_it->begin()); - if (cubic) { - lineHelper->moveto(SBasisStart.valueAt( - Geom::nearest_point((*cubic)[1], *start->first_segment()))); - } else { - lineHelper->moveto(start->first_segment()->initialPoint()); - } - start->reset(); - delete start; - - SPCurve *end = new SPCurve(); - end->moveto(curve_it1->initialPoint()); - end->lineto(curve_it1->finalPoint()); - Geom::D2 SBasisEnd = end->first_segment()->toSBasis(); - //Geom::BezierCurve const *bezier = dynamic_cast(&*curve_endit); - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - lineHelper->lineto(SBasisEnd.valueAt( - Geom::nearest_point((*cubic)[2], *end->first_segment()))); - } else { - lineHelper->lineto(end->first_segment()->finalPoint()); - } - end->reset(); - delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - startNode = SBasisHelper.valueAt(0.5); - nCurve->curveto(nextPointAt1, nextPointAt2, startNode); - nCurve->move_endpoints(startNode, startNode); - } else { - SPCurve *start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - startNode = start->first_segment()->initialPoint(); - start->reset(); - delete start; - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(startNode, nextPointAt3); - } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); + // Path effect definition + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); + repr->setAttribute("effect", name); + + doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to and assigns the 'id' attribute + const gchar *repr_id = repr->attribute("id"); + Inkscape::GC::release(repr); + + gchar *href = g_strdup_printf("#%s", repr_id); + SP_LPE_ITEM(item)->addPathEffect(href, true); + g_free(href); } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; - } } -Gtk::Widget *LPEBSpline::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); - std::vector::iterator it = param_vector.begin(); - 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 == "weight"){ - Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); - Gtk::Button *defaultWeight = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); - defaultWeight->signal_clicked() - .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); - buttons->pack_start(*defaultWeight, true, true, 2); - Gtk::Button *makeCusp = - Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->signal_clicked() - .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); - buttons->pack_start(*makeCusp, true, true, 2); - vbox->pack_start(*buttons, true, true, 2); - } - if (param->param_key == "weight" || param->param_key == "steps") { - Inkscape::UI::Widget::Scalar *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_value_changed() - .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); - widg = dynamic_cast(widgRegistered); - if (widg){ - Gtk::HBox * scalarParameter = dynamic_cast(widg); - std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); - Gtk::Entry* entryWidg = dynamic_cast(childList[1]); - entryWidg->set_width_chars(6); +void LPEBSpline::doEffect(SPCurve *curve) +{ + if (curve->get_segment_count() < 1) + return; + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + 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 + + 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 + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point previousNode(0, 0); + Geom::Point node(0, 0); + Geom::Point pointAt1(0, 0); + Geom::Point pointAt2(0, 0); + Geom::Point nextPointAt1(0, 0); + Geom::Point nextPointAt2(0, 0); + Geom::Point nextPointAt3(0, 0); + Geom::D2 SBasisIn; + Geom::D2 SBasisOut; + Geom::D2 SBasisHelper; + Geom::CubicBezier const *cubic = NULL; + 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(); + } + } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último + while (curve_it2 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path + //recto de entrada y de salida + SPCurve *in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + SBasisIn = in->first_segment()->toSBasis(); + pointAt1 = SBasisIn.valueAt( + Geom::nearest_point((*cubic)[1], *in->first_segment())); + pointAt2 = SBasisIn.valueAt( + Geom::nearest_point((*cubic)[2], *in->first_segment())); + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + in->reset(); + delete in; + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + SPCurve *out = new SPCurve(); + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + cubic = dynamic_cast(&*curve_it2); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt( + Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt( + Geom::nearest_point((*cubic)[2], *out->first_segment())); + ; + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de + //los manejadores de la curva + SPCurve *lineHelper = new SPCurve(); + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de + //principio de curva + previousNode = node; + //Y este hará de final de curva + node = SBasisHelper.valueAt(0.5); + nCurve->curveto(pointAt1, pointAt2, node); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); } - } - if (param->param_key == "onlySelected") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widg = dynamic_cast(widgRegistered); - } - if (param->param_key == "ignoreCusp") { - Gtk::CheckButton *widgRegistered = - Gtk::manage(dynamic_cast(widg)); - widg = dynamic_cast(widgRegistered); - } - Glib::ustring *tip = param->param_getTooltip(); - if (widg) { - vbox->pack_start(*widg, true, true, 2); - if (tip) { - widg->set_tooltip_text(*tip); + out->reset(); + delete out; + //Si está cerrada la curva, la cerramos sobre el valor guardado + //previamente + //Si no finalizamos en el punto final + Geom::Point startNode = path_it->begin()->initialPoint(); + if (path_it->closed()) { + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + Geom::D2 SBasisStart = start->first_segment()->toSBasis(); + SPCurve *lineHelper = new SPCurve(); + cubic = dynamic_cast(&*path_it->begin()); + if (cubic) { + lineHelper->moveto(SBasisStart.valueAt( + Geom::nearest_point((*cubic)[1], *start->first_segment()))); + } else { + lineHelper->moveto(start->first_segment()->initialPoint()); + } + start->reset(); + delete start; + + SPCurve *end = new SPCurve(); + end->moveto(curve_it1->initialPoint()); + end->lineto(curve_it1->finalPoint()); + Geom::D2 SBasisEnd = end->first_segment()->toSBasis(); + + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + lineHelper->lineto(SBasisEnd.valueAt( + Geom::nearest_point((*cubic)[2], *end->first_segment()))); + } else { + lineHelper->lineto(end->first_segment()->finalPoint()); + } + end->reset(); + delete end; + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + startNode = SBasisHelper.valueAt(0.5); + nCurve->curveto(nextPointAt1, nextPointAt2, startNode); + nCurve->move_endpoints(startNode, startNode); } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + startNode = start->first_segment()->initialPoint(); + start->reset(); + delete start; + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->move_endpoints(startNode, nextPointAt3); } - } + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); + } + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; } +} + +Gtk::Widget *LPEBSpline::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); + std::vector::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter *param = *it; + Gtk::Widget *widg = Gtk::manage(param->param_newWidget()); + if (param->param_key == "weight") { + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true, 0)); + + Gtk::Button *defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); + defaultWeight->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); + buttons->pack_start(*defaultWeight, true, true, 2); + + Gtk::Button *makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); + makeCusp->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); + buttons->pack_start(*makeCusp, true, true, 2); + + vbox->pack_start(*buttons, true, true, 2); + } + if (param->param_key == "weight" || param->param_key == "steps") { + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); + + if (widg) { + Gtk::HBox * scalarParameter = dynamic_cast(widg); + std::vector childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast(childList[1]); + entryWidg->set_width_chars(6); + } + } - ++it; - } - return dynamic_cast(vbox); + 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; + } + return vbox; } -void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) { +void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) +{ weight.param_set_value(0.3334); changeWeight(0.3334); Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); @@ -380,7 +364,8 @@ void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) { entryWidg->set_text("0.3334"); } -void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) { +void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) +{ weight.param_set_value(0.0000); changeWeight(0.0000); Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); @@ -389,348 +374,353 @@ void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) { entryWidg->set_text("0.0000"); } -void LPEBSpline::toWeight() { changeWeight(weight); } - -void LPEBSpline::changeWeight(double weightValue) { - SPDesktop *desktop = inkscape_active_desktop(); - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList *items = (GSList *)selection->itemList(); - SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; - SPPath *path = SP_PATH(item); - SPCurve *curve = path->get_curve_for_edit(); - LPEBSpline::doBSplineFromWidget(curve, weightValue); - gchar *str = sp_svg_write_path(curve->get_pathvector()); - path->getRepr()->setAttribute("inkscape:original-d", str); - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - nt->desktop->updateNow(); - } - g_free(str); - curve->unref(); - desktop->clearWaitingCursor(); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, - _("Modified the weight of the BSpline")); +void LPEBSpline::toWeight() +{ + changeWeight(weight); } -bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) { - using Geom::X; - using Geom::Y; - - if (points.size() > 0) { - for (std::vector::iterator i = points.begin(); - i != points.end(); ++i) { - Geom::Point p = *i; - if (Geom::are_near(p, nodePoint, 0.0001)) { - return true; - } else { - } +void LPEBSpline::changeWeight(double weightValue) +{ + SPDesktop *desktop = inkscape_active_desktop(); + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList *items = (GSList *)selection->itemList(); + SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; + SPPath *path = SP_PATH(item); + SPCurve *curve = path->get_curve_for_edit(); + LPEBSpline::doBSplineFromWidget(curve, weightValue); + gchar *str = sp_svg_write_path(curve->get_pathvector()); + path->getRepr()->setAttribute("inkscape:original-d", str); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); + nt->desktop->updateNow(); } - } - return false; + g_free(str); + curve->unref(); + desktop->clearWaitingCursor(); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, _("Modified the weight of a BSpline")); } -void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { - using Geom::X; - using Geom::Y; - SPDesktop *desktop = inkscape_active_desktop(); - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = - nt->_selected_nodes->allPoints(); - points.clear(); - std::vector::iterator pbegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = - selection.begin(); - i != selection.end(); ++i) { - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast(*i); - pbegin = points.begin(); - points.insert(pbegin, desktop->doc2dt(n->position())); - } - } - } - //bool hasNodesSelected = LPEBspline::hasNodesSelected(); - if (curve->get_segment_count() < 1) - return; - // Make copy of old path as it is changed during processing - Geom::PathVector const original_pathv = curve->get_pathvector(); - curve->reset(); - - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo - 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 - - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - Geom::Point pointAt0(0, 0); - Geom::Point pointAt1(0, 0); - Geom::Point pointAt2(0, 0); - Geom::Point pointAt3(0, 0); - Geom::Point nextPointAt0(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::Point nextPointAt2(0, 0); - Geom::Point nextPointAt3(0, 0); - Geom::D2 SBasisIn; - Geom::D2 SBasisOut; - Geom::CubicBezier const *cubic = NULL; - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline - nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while (curve_it2 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path - //recto de entrada y de salida - SPCurve *in = new SPCurve(); - in->moveto(curve_it1->initialPoint()); - in->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - pointAt0 = in->first_segment()->initialPoint(); - pointAt3 = in->first_segment()->finalPoint(); - SBasisIn = in->first_segment()->toSBasis(); - if (!onlySelected) { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); - } - } else { - pointAt1 = in->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); +bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) +{ + using Geom::X; + using Geom::Y; + + if (points.size() > 0) { + for (std::vector::iterator i = points.begin(); + i != points.end(); ++i) { + Geom::Point p = *i; + if (Geom::are_near(p, nodePoint, 0.0001)) { + return true; + } else { } - } else { - pointAt2 = in->first_segment()->finalPoint(); - } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } + return false; +} + +void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) +{ + using Geom::X; + using Geom::Y; + SPDesktop *desktop = inkscape_active_desktop(); + if (INK_IS_NODE_TOOL(desktop->event_context)) { + Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); + Inkscape::UI::ControlPointSelection::Set &selection = + nt->_selected_nodes->allPoints(); + points.clear(); + std::vector::iterator pbegin; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = + selection.begin(); + i != selection.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast(*i); + pbegin = points.begin(); + points.insert(pbegin, desktop->doc2dt(n->position())); } - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } + //bool hasNodesSelected = LPEBspline::hasNodesSelected(); + if (curve->get_segment_count() < 1) + return; + // Make copy of old path as it is changed during processing + Geom::PathVector const original_pathv = curve->get_pathvector(); + curve->reset(); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + 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 + + 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 + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + Geom::Point pointAt0(0, 0); + Geom::Point pointAt1(0, 0); + Geom::Point pointAt2(0, 0); + Geom::Point pointAt3(0, 0); + Geom::Point nextPointAt0(0, 0); + Geom::Point nextPointAt1(0, 0); + Geom::Point nextPointAt2(0, 0); + Geom::Point nextPointAt3(0, 0); + Geom::D2 SBasisIn; + Geom::D2 SBasisOut; + Geom::CubicBezier const *cubic = NULL; + 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(); } - } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } } - } else { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - if (nodeIsSelected(pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); - } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último + while (curve_it2 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path + //recto de entrada y de salida + SPCurve *in = new SPCurve(); + in->moveto(curve_it1->initialPoint()); + in->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast(&*curve_it1); + pointAt0 = in->first_segment()->initialPoint(); + pointAt3 = in->first_segment()->finalPoint(); + SBasisIn = in->first_segment()->toSBasis(); + if (!onlySelected) { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.0000) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + } } else { - pointAt1 = (*cubic)[1]; + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { + if (nodeIsSelected(pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + if (weightValue != 0.0000) { + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } + } else { + pointAt1 = (*cubic)[1]; + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { + if (nodeIsSelected(pointAt3)) { + pointAt2 = SBasisIn.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } + } else { + pointAt2 = (*cubic)[2]; + } + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + if (!ignoreCusp && weightValue != 0.000) { + if (nodeIsSelected(pointAt0)) { + pointAt1 = SBasisIn.valueAt(weightValue); + pointAt1 = + Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + } else { + pointAt1 = in->first_segment()->initialPoint(); + } + if (nodeIsSelected(pointAt3)) { + pointAt2 = SBasisIn.valueAt(weightValue); + pointAt2 = + Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + } else { + pointAt2 = in->first_segment()->finalPoint(); + } + } else { + pointAt1 = in->first_segment()->initialPoint(); + pointAt2 = in->first_segment()->finalPoint(); + } + } } - } else { - pointAt1 = in->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - if (nodeIsSelected(pointAt3)) { - pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); - } + in->reset(); + delete in; + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de + //los manejadores de la curva + nCurve->curveto(pointAt1, pointAt2, pointAt3); + //aumentamos los valores para el siguiente paso en el bucle + ++curve_it1; + ++curve_it2; + } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt0 = out->first_segment()->initialPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + cubic = dynamic_cast(&*curve_it1); + if (!onlySelected) { + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + if (weightValue != 0.0000) { + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } } else { - pointAt2 = (*cubic)[2]; + if (!ignoreCusp && weightValue != 0.0000) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } } - } else { - pointAt2 = in->first_segment()->finalPoint(); - } } else { - if (!ignoreCusp && weightValue != 0.000) { - if (nodeIsSelected(pointAt0)) { - pointAt1 = SBasisIn.valueAt(weightValue); - pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + if (cubic) { + if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { + if (nodeIsSelected(nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + if (weightValue != 0.0000) { + nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001, + nextPointAt1[Y] + 0.0001); + } + } else { + nextPointAt1 = (*cubic)[1]; + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { + if (nodeIsSelected(nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(1 - weightValue); + if (weightValue != 0.0000) { + nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001, + nextPointAt2[Y] + 0.0001); + } + } else { + nextPointAt2 = (*cubic)[2]; + } + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } } else { - pointAt1 = in->first_segment()->initialPoint(); + if (!ignoreCusp && weightValue != 0.0000) { + if (nodeIsSelected(nextPointAt0)) { + nextPointAt1 = SBasisOut.valueAt(weightValue); + nextPointAt1 = + Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + if (nodeIsSelected(nextPointAt3)) { + nextPointAt2 = SBasisOut.valueAt(weightValue); + nextPointAt2 = + Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); + } else { + nextPointAt2 = out->first_segment()->finalPoint(); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + } } - if (nodeIsSelected(pointAt3)) { - pointAt2 = SBasisIn.valueAt(weightValue); - pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); - } else { - pointAt2 = in->first_segment()->finalPoint(); - } - } else { - pointAt1 = in->first_segment()->initialPoint(); - pointAt2 = in->first_segment()->finalPoint(); - } - } - } - in->reset(); - delete in; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de - //los manejadores de la curva - nCurve->curveto(pointAt1, pointAt2, pointAt3); - //aumentamos los valores para el siguiente paso en el bucle - ++curve_it1; - ++curve_it2; - } - SPCurve *out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt0 = out->first_segment()->initialPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - cubic = dynamic_cast(&*curve_it1); - if (!onlySelected) { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - if (weightValue != 0.0000) { - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - } - } - } else { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { - if (nodeIsSelected(nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - if (weightValue != 0.0000) { - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001, - nextPointAt1[Y] + 0.0001); - } - } else { - nextPointAt1 = (*cubic)[1]; - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { - if (nodeIsSelected(nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001, - nextPointAt2[Y] + 0.0001); - } - } else { - nextPointAt2 = (*cubic)[2]; - } + out->reset(); + delete out; + //Aberiguamos la ultima parte de la curva correspondiente al último + //segmento + //Y hacemos lo propio con el path de salida + //nextPointAt0 = curveOut.valueAt(0); + if (path_it->closed()) { + nCurve->curveto(nextPointAt1, nextPointAt2, + path_it->begin()->initialPoint()); + nCurve->move_endpoints(path_it->begin()->initialPoint(), + path_it->begin()->initialPoint()); } else { - nextPointAt2 = out->first_segment()->finalPoint(); + nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); + nCurve->move_endpoints(path_it->begin()->initialPoint(), nextPointAt3); } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - if (nodeIsSelected(nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (nodeIsSelected(nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(weightValue); - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); } - } - } - out->reset(); - delete out; - //Aberiguamos la ultima parte de la curva correspondiente al último - //segmento - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - if (path_it->closed()) { - nCurve->curveto(nextPointAt1, nextPointAt2, - path_it->begin()->initialPoint()); - nCurve->move_endpoints(path_it->begin()->initialPoint(), - path_it->begin()->initialPoint()); - } else { - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(path_it->begin()->initialPoint(), nextPointAt3); - } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; - } } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index aff4ce812..f37741a4a 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -15,44 +15,40 @@ namespace Inkscape { namespace LivePathEffect { class LPEBSpline : public Effect { - public: - LPEBSpline(LivePathEffectObject *lpeobject); - virtual ~LPEBSpline(); - - virtual void createAndApply(const char *name, SPDocument *doc, SPItem *item); - - virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } - - virtual void doEffect(SPCurve *curve); - - virtual void doBSplineFromWidget(SPCurve *curve, double value); - - virtual bool nodeIsSelected(Geom::Point nodePoint); - - virtual Gtk::Widget *newWidget(); + LPEBSpline(LivePathEffectObject *lpeobject); + virtual ~LPEBSpline(); - virtual void changeWeight(double weightValue); + virtual void createAndApply(const char *name, SPDocument *doc, SPItem *item); + virtual LPEPathFlashType pathFlashType() const { + return SUPPRESS_FLASH; + } + virtual void doEffect(SPCurve *curve); - virtual void toDefaultWeight(Gtk::Widget *widgWeight); + void doBSplineFromWidget(SPCurve *curve, double value); + bool nodeIsSelected(Geom::Point nodePoint); - virtual void toMakeCusp(Gtk::Widget *widgWeight); + virtual Gtk::Widget *newWidget(); - virtual void toWeight(); + void changeWeight(double weightValue); + void toDefaultWeight(Gtk::Widget *widgWeight); + void toMakeCusp(Gtk::Widget *widgWeight); + void toWeight(); - ScalarParam steps; + // TODO make this private + ScalarParam steps; private: - std::vector points; - BoolParam ignoreCusp; - BoolParam onlySelected; - ScalarParam weight; + std::vector points; + BoolParam ignoreCusp; + BoolParam onlySelected; + ScalarParam weight; - LPEBSpline(const LPEBSpline &); - LPEBSpline &operator=(const LPEBSpline &); + LPEBSpline(const LPEBSpline &); + LPEBSpline &operator=(const LPEBSpline &); }; -}; //namespace LivePathEffect -}; //namespace Inkscape +} //namespace LivePathEffect +} //namespace Inkscape #endif diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index fc2173a67..a24f5e60e 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -434,9 +434,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) if (SP_IS_SHAPE(lpeItem)) { fillet_chamfer_values.set_helper_size(helper_size); fillet_chamfer_values.set_unit(unit.get_abbreviation()); - SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem) - ->get_original_curve() - : SP_SHAPE(lpeItem)->getCurve(); + SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem)->get_original_curve() : SP_SHAPE(lpeItem)->getCurve(); std::vector filletChamferData = fillet_chamfer_values.data(); if (!filletChamferData.empty() && getKnotsNumber(c) != (int) filletChamferData.size()) { diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index 03238f935..d447afa6f 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -29,6 +29,9 @@ ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::us ToggleButtonParam::~ToggleButtonParam() { + if (_toggled_connection.connected()) { + _toggled_connection.disconnect(); + } } void @@ -54,6 +57,10 @@ ToggleButtonParam::param_getSVGValue() const Gtk::Widget * ToggleButtonParam::param_newWidget() { + if (_toggled_connection.connected()) { + _toggled_connection.disconnect(); + } + Inkscape::UI::Widget::RegisteredToggleButton * checkwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredToggleButton( param_label, param_tooltip, @@ -65,9 +72,12 @@ ToggleButtonParam::param_newWidget() checkwdg->setActive(value); checkwdg->setProgrammatically = false; - checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); + // TRANSLATORS: "toggle" is a verb here + checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Toggle path effect parameter")); + + _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled)); - return dynamic_cast (checkwdg); + return checkwdg; } void @@ -76,6 +86,11 @@ ToggleButtonParam::param_setValue(bool newvalue) value = newvalue; } +void +ToggleButtonParam::toggled() { + _signal_toggled.emit(); +} + } /* namespace LivePathEffect */ } /* namespace Inkscape */ diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h index 9b1c71185..753af6dbd 100644 --- a/src/live_effects/parameter/togglebutton.h +++ b/src/live_effects/parameter/togglebutton.h @@ -2,14 +2,14 @@ #define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H /* - * Inkscape::LivePathEffectParameters - * -* Copyright (C) Johan Engelen 2007 + * Copyright (C) Jabiertxo Arraiza Cenoz 2014 * * Released under GNU GPL, read the file 'COPYING' for more information */ #include +#include +#include #include "live_effects/parameter/parameter.h" @@ -17,7 +17,10 @@ namespace Inkscape { namespace LivePathEffect { - +/** + * class ToggleButtonParam: + * represents a Gtk::ToggleButton as a Live Path Effect parameter + */ class ToggleButtonParam : public Parameter { public: ToggleButtonParam( const Glib::ustring& label, @@ -39,6 +42,9 @@ public: bool get_value() const { return value; }; inline operator bool() const { return value; }; + + sigc::signal& signal_toggled() { return _signal_toggled; } + virtual void toggled(); private: ToggleButtonParam(const ToggleButtonParam&); @@ -46,6 +52,9 @@ private: bool value; bool defvalue; + + sigc::signal _signal_toggled; + sigc::connection _toggled_connection; }; -- cgit v1.2.3 From 6d5bd2bf07165531a10d9925e8800fe5c9cd9be3 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 14 Jul 2014 00:59:33 +0200 Subject: Update togglebutton parameter to handle if you want: Active text, Active icon, Inactive text, Inactive Icon (bzr r13341.1.88) --- src/live_effects/lpe-simplify.cpp | 16 +++--- src/live_effects/parameter/togglebutton.cpp | 77 ++++++++++++++++++++++++++--- src/live_effects/parameter/togglebutton.h | 16 +++++- 3 files changed, 94 insertions(+), 15 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index d010e75a2..104cbde98 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -19,7 +19,7 @@ #include <2geom/d2.h> #include <2geom/generic-rect.h> #include <2geom/interval.h> - +#include "ui/icon-names.h" namespace Inkscape { namespace LivePathEffect { @@ -29,10 +29,14 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 2.), - nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false), - handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false), - simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false), - simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false) + nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false, + "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")), + handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false, + "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")), + simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false, + "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")), + simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false, + "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")) { registerParameter(dynamic_cast(&steps)); registerParameter(dynamic_cast(&threshold)); @@ -41,7 +45,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) registerParameter(dynamic_cast(&handles)); registerParameter(dynamic_cast(&simplifyindividualpaths)); registerParameter(dynamic_cast(&simplifyJustCoalesce)); - threshold.param_set_range(0., Geom::infinity()); + threshold.param_set_range(0.0001, Geom::infinity()); threshold.param_set_increments(0.0001, 0.0001); threshold.param_set_digits(6); steps.param_set_range(0, 100); diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index d447afa6f..d92b9836f 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -5,6 +5,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include +#include +#include +#include + #include "ui/widget/registered-widget.h" #include "live_effects/parameter/togglebutton.h" #include "live_effects/effect.h" @@ -14,7 +19,6 @@ #include "inkscape.h" #include "verbs.h" #include "helper-fns.h" -#include namespace Inkscape { @@ -22,9 +26,13 @@ namespace LivePathEffect { ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, bool default_value ) - : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) + Effect* effect, bool default_value, const Glib::ustring& inactive_label, + char const * icon_active, char const * icon_inactive, + Inkscape::IconSize icon_size) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), + inactiveLabel(inactive_label), iconActive(icon_active), iconInactive(icon_inactive), iconSize(icon_size) { + checkwdg = NULL; } ToggleButtonParam::~ToggleButtonParam() @@ -61,7 +69,7 @@ ToggleButtonParam::param_newWidget() _toggled_connection.disconnect(); } - Inkscape::UI::Widget::RegisteredToggleButton * checkwdg = Gtk::manage( + checkwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredToggleButton( param_label, param_tooltip, param_key, @@ -69,21 +77,76 @@ ToggleButtonParam::param_newWidget() false, param_effect->getRepr(), param_effect->getSPDoc()) ); - + GtkWidget * boxButton = gtk_hbox_new (false, 0); + GtkWidget * labelButton = gtk_label_new (""); + if (!param_label.empty()) { + if(value || inactiveLabel.empty()){ + gtk_label_set_text(GTK_LABEL(labelButton), param_label.c_str()); + }else{ + gtk_label_set_text(GTK_LABEL(labelButton), inactiveLabel.c_str()); + } + } + gtk_widget_show(labelButton); + if ( iconActive ) { + if(!iconInactive){ + iconInactive = iconActive; + } + gtk_widget_show(boxButton); + GtkWidget *iconButton = sp_icon_new(iconSize, iconActive); + if(!value){ + iconButton = sp_icon_new(iconSize, iconInactive); + } + gtk_widget_show(iconButton); + gtk_box_pack_start (GTK_BOX(boxButton), iconButton, true, true, 2); + if (!param_label.empty()) { + gtk_box_pack_start (GTK_BOX(boxButton), labelButton, true, true, 2); + } + }else{ + gtk_box_pack_start (GTK_BOX(boxButton), labelButton, true, true, 2); + } + checkwdg->add(*Gtk::manage(Glib::wrap(boxButton))); checkwdg->setActive(value); checkwdg->setProgrammatically = false; - // TRANSLATORS: "toggle" is a verb here - checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Toggle path effect parameter")); + checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled)); return checkwdg; } +void +ToggleButtonParam::refresh_button() +{ + if(!checkwdg){ + return; + } + Gtk::Widget * boxButton = checkwdg->get_child(); + if(!boxButton){ + return; + } + GList * childs = gtk_container_get_children(GTK_CONTAINER(boxButton->gobj())); + guint totalWidgets = g_list_length (childs); + if (!param_label.empty()) { + if(value || inactiveLabel.empty()){ + gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), param_label.c_str()); + }else{ + gtk_label_set_text(GTK_LABEL(g_list_nth_data(childs, totalWidgets-1)), inactiveLabel.c_str()); + } + } + if ( iconActive ) { + GdkPixbuf * iconPixbuf = sp_pixbuf_new( iconSize, iconActive ); + if(!value){ + iconPixbuf = sp_pixbuf_new( iconSize, iconInactive); + } + gtk_image_set_from_pixbuf (GTK_IMAGE(g_list_nth_data(childs, 0)), iconPixbuf); + } +} + void ToggleButtonParam::param_setValue(bool newvalue) { value = newvalue; + refresh_button(); } void diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h index 753af6dbd..4e545bcfd 100644 --- a/src/live_effects/parameter/togglebutton.h +++ b/src/live_effects/parameter/togglebutton.h @@ -12,6 +12,8 @@ #include #include "live_effects/parameter/parameter.h" +#include "icon-size.h" +#include "ui/widget/registered-widget.h" namespace Inkscape { @@ -28,7 +30,11 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - bool default_value = false); + bool default_value = false, + const Glib::ustring& inactive_label = "", + char const * icon_active = NULL, + char const * icon_inactive = NULL, + Inkscape::IconSize icon_size = Inkscape::ICON_SIZE_SMALL_TOOLBAR); virtual ~ToggleButtonParam(); virtual Gtk::Widget * param_newWidget(); @@ -50,9 +56,15 @@ private: ToggleButtonParam(const ToggleButtonParam&); ToggleButtonParam& operator=(const ToggleButtonParam&); + void refresh_button(); bool value; bool defvalue; - + const Glib::ustring inactiveLabel; + const char * iconActive; + const char * iconInactive; + Inkscape::IconSize iconSize; + Inkscape::UI::Widget::RegisteredToggleButton * checkwdg; + sigc::signal _signal_toggled; sigc::connection _toggled_connection; }; -- cgit v1.2.3 From 50c1511c5721029101e0e69a48401adfba104f6f Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Fri, 18 Jul 2014 21:53:39 -0400 Subject: Fix build (bzr r13341.1.89) --- src/live_effects/lpe-simplify.cpp | 6 +++--- src/live_effects/parameter/togglebutton.cpp | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 104cbde98..17b97eda9 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -1,9 +1,9 @@ -#define INKSCAPE_LPE_SIMPLIFY_C /* * Released under GNU GPL, read the file 'COPYING' for more information */ -#include -#include + +#include + #include "live_effects/lpe-simplify.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index d92b9836f..ceb4f98ff 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -5,9 +5,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include -#include -#include +#include #include #include "ui/widget/registered-widget.h" -- cgit v1.2.3 From 94d507366a97e2d5fbfb7d2b2c32f69830844a13 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 21 Jul 2014 17:05:54 +0200 Subject: Add icons on/off to use in simplify LPE toggle buttons (bzr r13341.1.90) --- src/live_effects/lpe-simplify.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 17b97eda9..1a02375cd 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -30,13 +30,13 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 2.), nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false, - "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")), + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false, - "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")), + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false, - "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")), + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false, - "", INKSCAPE_ICON("system-run"), INKSCAPE_ICON("process-stop")) + "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")) { registerParameter(dynamic_cast(&steps)); registerParameter(dynamic_cast(&threshold)); -- cgit v1.2.3 From db11af074f242faa77a1763efc54d26752fa6d93 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 22 Jul 2014 18:55:10 +0200 Subject: Fixed alignaments of toggle buttons (bzr r13341.1.95) --- src/live_effects/parameter/togglebutton.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index ceb4f98ff..5658d238f 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -95,12 +95,12 @@ ToggleButtonParam::param_newWidget() iconButton = sp_icon_new(iconSize, iconInactive); } gtk_widget_show(iconButton); - gtk_box_pack_start (GTK_BOX(boxButton), iconButton, true, true, 2); + gtk_box_pack_start (GTK_BOX(boxButton), iconButton, false, false, 1); if (!param_label.empty()) { - gtk_box_pack_start (GTK_BOX(boxButton), labelButton, true, true, 2); + gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1); } }else{ - gtk_box_pack_start (GTK_BOX(boxButton), labelButton, true, true, 2); + gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1); } checkwdg->add(*Gtk::manage(Glib::wrap(boxButton))); checkwdg->setActive(value); -- cgit v1.2.3 From fe12278d612a0c52bcbff2736f18d4e590410b71 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 22 Jul 2014 22:35:50 -0400 Subject: Duplicate LPE entries (bzr r13090.1.91) --- src/live_effects/effect.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 179759ed6..777d500e9 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -147,11 +147,6 @@ const Util::EnumData LPETypeData[] = { {SIMPLIFY, N_("Simplify"), "simplify"}, {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"}, - {SIMPLIFY, N_("Simplify"), "simplify"}, - {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - // TRANSLATORS: "Envelope Perspective" should be equivalent to "perspective transformation" - {ENVELOPE_PERSPECTIVE, N_("Envelope Perspective"), "envelope-perspective"}, - {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); -- cgit v1.2.3 From 76244246733cc1f1f3874aa498ad75977ebc6cd7 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 22 Jul 2014 22:39:21 -0400 Subject: This file does not need executable permissions (bzr r13090.1.93) --- src/live_effects/lpe-jointype.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/live_effects/lpe-jointype.h (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h old mode 100755 new mode 100644 -- cgit v1.2.3 From 3a6ed95f3fa5921c78b24f9ae73df7d442827571 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 23 Jul 2014 16:16:43 -0400 Subject: Refactoring of linejoin code (bzr r13090.1.94) --- src/live_effects/pathoutlineprovider.cpp | 551 +++++++++++++++---------------- src/live_effects/pathoutlineprovider.h | 33 +- 2 files changed, 283 insertions(+), 301 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index d6e0ce7ea..482f1f5e0 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -125,8 +125,7 @@ Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in return Geom::CubicBezier( temp ); } -static boost::optional intersection_point( Geom::Point const & origin_a, Geom::Point const & vector_a, - Geom::Point const & origin_b, Geom::Point const & vector_b) +static boost::optional intersection_point(Geom::Point const & origin_a, Geom::Point const & vector_a, Geom::Point const & origin_b, Geom::Point const & vector_b) { Geom::Coord denom = cross(vector_b, vector_a); if (!Geom::are_near(denom,0.)) { @@ -135,13 +134,16 @@ static boost::optional intersection_point( Geom::Point const & orig } return boost::none; } -} + +} // namespace Geom namespace Outline { typedef Geom::D2 D2SB; typedef Geom::Piecewise PWD2; +// UTILITY + unsigned bezierOrder (const Geom::Curve* curve_in) { using namespace Geom; @@ -151,25 +153,28 @@ unsigned bezierOrder (const Geom::Curve* curve_in) return 0; } -//returns true if the angle formed by the curves and their handles -//is >180 clockwise, otherwise false. +/** + * @return true if the angle formed by the curves and their handles is greater than 180 degrees clockwise, otherwise false. + */ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) { Geom::Point start_point; Geom::Point cross_point = cbc1.finalPoint(); Geom::Point end_point; - //assert(cbc1.finalPoint() == cbc2.initialPoint()); - //short circuiting? - if (cbc1.finalPoint() != cbc2.initialPoint()) { - printf("erk! Line %d, File %s\n", __LINE__, __FILE__); + if (cross_point != cbc2.initialPoint()) { + g_warning("Non-contiguous path in Outline::outside_angle()"); return false; } - //let's try: Geom::CubicBezier cubicBezier = Geom::sbasis_to_cubicbezier(cbc1.toSBasis()); start_point = cubicBezier [2]; - //stupid thing Inkscape does: + + /* + * Because the node editor does not yet support true quadratics, paths are converted to + * cubic beziers in the node tool with degenerate handles on one side. + */ + if (are_near(start_point, cross_point, 0.0000001)) { start_point = cubicBezier [1]; } @@ -178,9 +183,11 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) if (are_near(end_point, cross_point, 0.0000001)) { end_point = cubicBezier [2]; } - //got our three points, now let's see what their clockwise angle is - //Much credit to Wikipedia for the following ( http://en.wikipedia.org/wiki/Graham_scan ) + // got our three points, now let's see what their clockwise angle is + + // Definition of a Graham scan + /******************************************************************** # Three points are a counter-clockwise turn if ccw > 0, clockwise if # ccw < 0, and collinear if ccw = 0 because ccw is a determinant that @@ -191,27 +198,90 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) double ccw = ( (cross_point.x() - start_point.x()) * (end_point.y() - start_point.y()) ) - ( (cross_point.y() - start_point.y()) * (end_point.x() - start_point.x()) ); - if (ccw > 0) return true; - return false; + return ccw > 0; } -void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, - double miter_limit, double line_width, bool outside = false) -{ - bool lineProblem = (dynamic_cast *>(cbc1)) || (dynamic_cast *>(cbc2)); - if ( outside && !lineProblem ) { - Geom::Path pth; - pth.append(*cbc1); +// LINE JOINS - Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); +typedef Geom::BezierCurveN<1u> BezierLine; - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); +/** + * Removes the crossings on an interior join. + * @param path_builder Contains the incoming segment; result is appended to this + * @param outgoing The outgoing segment + */ +void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing) { + Geom::Curve const& incoming = path_builder.back(); + + // Using Geom::crossings to find intersections between two curves + Geom::Crossings cross = Geom::crossings(incoming, outgoing); + if (!cross.empty()) { + // Crossings found, create the join + Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(incoming.toSBasis()); + cubic = cubic.subdivide(cross[0].ta).first; + // erase the last segment, as we're going to overwrite it now + path_builder.erase_last(); + path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); + cubic = Geom::sbasis_to_cubicbezier(outgoing.toSBasis()); + cubic = cubic.subdivide(cross[0].tb).second; + path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); + } else { + // No crossings occurred, or Geom::crossings() failed; default to bevel + if (Geom::are_near(incoming.finalPoint(), outgoing.initialPoint())) { + path_builder.appendNew(outgoing.initialPoint()); + } else { + path_builder.setFinal(outgoing.initialPoint()); + } + } +} + +/** + * Try to create a miter join. Falls back to bevel if no miter can be created. + * @param path_builder Path to append curves to; back() is the incoming curve + * @param outgoing Outgoing curve. + * @param miter_limit When mitering, don't exceed this length + * @param line_width The thickness of the line. + */ +void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { + using namespace Geom; + Curve const& incoming = path_builder.back(); + Point tang1 = unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.); + Point tang2 = unitTangentAt(outgoing.toSBasis(), 0); + + boost::optional p = intersection_point (incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); + if (p) { + // check size of miter + Point point_on_path = incoming.finalPoint() - rot90(tang1) * line_width; + Coord len = distance(*p, point_on_path); + if (len <= miter_limit) { + // miter OK + path_builder.appendNew(*p); + } + } + path_builder.appendNew(outgoing.initialPoint()); +} - Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(cbc1->toSBasis()), 0.); - Geom::Circle circle2 = Geom::touching_circle(cbc2->toSBasis(), 0); +/** + * Smoothly extrapolate curves along a circular route. Falls back to miter if necessary. + * @param path_builder Path to append curves to; back() is the incoming curve + * @param outgoing Outgoing curve. + * @param miter_limit When mitering, don't exceed this length + * @param line_width The thickness of the line. Used for miter fallback. + */ +void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { + Geom::Curve const& incoming = path_builder.back(); + Geom::Point endPt = outgoing.initialPoint(); + + // The method used when extrapolating curves fails to work when either side of the join to be extrapolated + // is a line segment. When this situation is encountered, fall back to a regular miter join. + bool lineProblem = (dynamic_cast(&incoming)) || (dynamic_cast(&outgoing)); + if (lineProblem == false) { + // Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.); + Geom::Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0); + + Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.); + Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0); Geom::Point points[2]; int solutions = Geom::circle_circle_intersection(circle1, circle2, points[0], points[1]); @@ -225,239 +295,161 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve sol = points[0]; } else { // both points are good, choose nearest - sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? - points[0] : points[1]; + sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? points[0] : points[1]; } - Geom::EllipticalArc *arc0 = circle1.arc(cbc1->finalPoint(), 0.5*(cbc1->finalPoint()+sol), sol, true); + + Geom::EllipticalArc *arc0 = circle1.arc(incoming.finalPoint(), 0.5*(incoming.finalPoint()+sol), sol, true); Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); try { if (arc0) { path_builder.append (arc0->toSBasis()); delete arc0; arc0 = NULL; + } else { + throw std::exception(); } if (arc1) { path_builder.append (arc1->toSBasis()); delete arc1; arc1 = NULL; + } else { + throw std::exception(); } - } catch (std::exception & ex) { - printf("Exception occured, probably NaN or infinite valued points: %s\n", ex.what()); + + } catch (std::exception const & ex) { + g_warning("Error extrapolating line join: %s\n", ex.what()); path_builder.appendNew(endPt); } } else { - boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) { - //check size of miter - Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; - Geom::Coord len = distance(*p, point_on_path); - if (len <= miter_limit) { - // miter OK - path_builder.appendNew (*p); - } - } - path_builder.appendNew (endPt); - } - if (cbc1->finalPoint() != cbc2->initialPoint()) { - path_builder.appendNew(cbc2->initialPoint()); - } - path_builder.append(*cbc2); - } - if ( outside && lineProblem ) { - Geom::Path pth; - pth.append(*cbc1); - Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) { - //check size of miter - Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; - Geom::Coord len = distance(*p, point_on_path); - if (len <= miter_limit) { - // miter OK - path_builder.appendNew (*p); - } - } - path_builder.appendNew (endPt); - if (cbc1->finalPoint() != cbc2->initialPoint()) { - path_builder.appendNew(cbc2->initialPoint()); - } - path_builder.append(*cbc2); - } - if ( !outside ) { - /*path_builder.appendNew (endPt);*/ - Geom::Crossings cross = Geom::crossings(*cbc1, *cbc2); - if (!cross.empty()) { - path_builder.erase_last(); - Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(cbc1->toSBasis()); - cubic = cubic.subdivide(cross[0].ta).first; - path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); - cubic = Geom::sbasis_to_cubicbezier(cbc2->toSBasis()); - cubic = cubic.subdivide(cross[0].tb).second; - path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); - } else { - if (Geom::distance(path_builder.finalPoint(), cbc2->initialPoint()) > 0.0000001) { - path_builder.appendNew(cbc2->initialPoint()); - } else { - path_builder.setFinal(cbc2->initialPoint()); - } - path_builder.append(*cbc2); + // 1 or no solutions found, default to miter + miter_curves(path_builder, outgoing, miter_limit, line_width); } + } else { + // Line segments exist + miter_curves(path_builder, outgoing, miter_limit, line_width); } } -void reflect_curves(Geom::Path& path_builder, Geom::Curve* cbc1, Geom::Curve* cbc2, Geom::Point endPt, - double miter_limit, double line_width, bool outside = false) +/** + * Extrapolate curves by reflecting them along the line that would be given by beveling the join. + * @param path_builder Path to append curves to; back() is the incoming curve + * @param outgoing Outgoing curve. + * @param miter_limit When mitering, don't exceed this length + * @param line_width The thickness of the line. Used for miter fallback. + */ +void reflect_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { - //the most important work for the reflected join is done here - - //determine where we are in the path. If we're on the inside, ignore - //and just lineTo. On the outside, we'll do a little reflection magic :) - Geom::Crossings cross; + using namespace Geom; + Curve const& incoming = path_builder.back(); + // On the outside, we'll take the incoming curve, the outgoing curve, and + // reflect them over the line formed by taking the unit tangent vector at times + // 0 and 1, respectively, rotated by 90 degrees. + Crossings cross; + + // reflect curves along the line that would be given by beveling the join + Point tang1 = unitTangentAt(reverse(incoming.toSBasis()), 0.); + D2SB newcurve1 = incoming.toSBasis() * reflection(-rot90(tang1), incoming.finalPoint()); + CubicBezier bzr1 = sbasis_to_cubicbezier(reverse(newcurve1)); + + Point tang2 = Geom::unitTangentAt(outgoing.toSBasis(), 0.); + D2SB newcurve2 = outgoing.toSBasis() * reflection(-rot90(tang2), outgoing.initialPoint()); + CubicBezier bzr2 = sbasis_to_cubicbezier(reverse(newcurve2)); + + cross = crossings(bzr1, bzr2); + if (cross.empty()) { + // paths don't cross, fall back to miter + miter_curves(path_builder, outgoing, miter_limit, line_width); + } else { + // reflected join + std::pair sub1 = bzr1.subdivide(cross[0].ta); + std::pair sub2 = bzr2.subdivide(cross[0].tb); + + // TODO it seems as if a bug in 2geom sometimes doesn't catch the first + // crossing of paths, but the second instead; but only sometimes. + path_builder.appendNew (sub1.first[1], sub1.first[2], sub2.second[0]); + path_builder.appendNew (sub2.second[1], sub2.second[2], outgoing.initialPoint()); + } +} - if (outside) { - Geom::Path pth; - pth.append(*cbc1); - - Geom::Point tang1 = Geom::unitTangentAt(Geom::reverse(pth.toPwSb()[0]), 0.); - - //reflect curves along the bevel - D2SB newcurve1 = pth.toPwSb()[0] * - Geom::reflection ( -Geom::rot90(tang1) , - cbc1->finalPoint() ); - - Geom::CubicBezier bzr1 = sbasis_to_cubicbezier(Geom::reverse(newcurve1)); - - pth = Geom::Path(); - pth.append( *cbc2 ); - Geom::Point tang2 = Geom::unitTangentAt(pth.toPwSb()[0], 0); - - D2SB newcurve2 = pth.toPwSb()[0] * - Geom::reflection ( -Geom::rot90(tang2) , - cbc2->initialPoint() ); - Geom::CubicBezier bzr2 = sbasis_to_cubicbezier(Geom::reverse(newcurve2)); - - cross = Geom::crossings(bzr1, bzr2); - if ( cross.empty() ) { - //curves didn't cross; default to miter - boost::optional p = intersection_point (cbc1->finalPoint(), tang1, - cbc2->initialPoint(), tang2); - if (p) { - //check size of miter - Geom::Point point_on_path = cbc1->finalPoint() - rot90(tang1) * line_width; - Geom::Coord len = distance(*p, point_on_path); - if (len <= miter_limit) { - // miter OK - path_builder.appendNew (*p); - } - } - //bevel - path_builder.appendNew( endPt ); - } else { - //join - std::pair sub1 = bzr1.subdivide(cross[0].ta); - std::pair sub2 = bzr2.subdivide(cross[0].tb); +// Ideal function pointer we want to pass +typedef void JoinFunc(Geom::Path& /*path_builder*/, Geom::Curve const& /*outgoing*/, double /*miter_limit*/, double /*line_width*/); - //@TODO joins have a strange tendency to cross themselves twice. Check this. +/** + * Helper function for repeated logic in outlineHalf. + */ +static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, bool outside, double width, double miter, JoinFunc func) { + Geom::Curve * cbc2 = path_vec->front()[0].duplicate(); - //sections commented out are for general stability - path_builder.appendNew (sub1.first[1], sub1.first[2], /*sub1.first[3]*/ sub2.second[0] ); - path_builder.appendNew (sub2.second[1], sub2.second[2], /*sub2.second[3]*/ endPt ); - } - if (cbc1->finalPoint() != cbc2->initialPoint()) { - path_builder.appendNew(cbc2->initialPoint()); - } - path_builder.append(*cbc2); + if (outside) { + func(path_builder, *cbc2, miter, width); } else { - //probably on the inside of the corner - /*path_builder.appendNew ( endPt );*/ - cross = Geom::crossings(*cbc1, *cbc2); - if (!cross.empty()) { - path_builder.erase_last(); - Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(cbc1->toSBasis()); - cubic = cubic.subdivide(cross[0].ta).first; - path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); - cubic = Geom::sbasis_to_cubicbezier(cbc2->toSBasis()); - cubic = cubic.subdivide(cross[0].tb).second; - path_builder.append(cubic, Geom::Path::STITCH_DISCONTINUOUS); - } else { - if (Geom::distance(path_builder.finalPoint(), cbc2->initialPoint()) > 0.0000001) { - path_builder.appendNew(cbc2->initialPoint()); - } else { - path_builder.setFinal(cbc2->initialPoint()); - } - path_builder.append(*cbc2); - } + joinInside(path_builder, *cbc2); + } + + // store it + Geom::Path temp_path = path_vec->front(); + if (!outside) { + // erase the first segment since the inside join code already appended it + temp_path.erase(temp_path.begin()); + } + + if (temp_path.initialPoint() != path_builder.finalPoint()) { + temp_path.setInitial(path_builder.finalPoint()); } + + path_builder.append(temp_path); + + delete cbc2; } -/** @brief Converts a path to one half of an outline. -* path_in: The input path to use. (To create the other side use path_in.reverse() ) -* line_width: the line width to use (usually you want to divide this by 2) -* miter_limit: the miter parameter -* extrapolate: whether the join should be extrapolated instead of reflected -*/ -Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double miter_limit, bool extrapolate = false) -{ - // NOTE: it is important to notice the distinction between a Geom::Path and a livarot Path here! +/** + * Offsets exactly one half of a bezier spline (path). + * @param path_in The input path to use. (To create the other side use path_in.reverse() ) + * @param line_width the line width to use (usually you want to divide this by 2) + * @param miter_limit the miter parameter + * @param func Join function to apply at each join. + */ + +Geom::Path outlineHalf(const Geom::Path& path_in, double line_width, double miter_limit, JoinFunc func) { + // NOTE: it is important to notice the distinction between a Geom::Path and a livarot ::Path here! // if you do not see "Geom::" there is a different function set! Geom::PathVector pv = split_at_cusps(path_in); - Path to_outline; - Path outlined_result; - - Geom::Path path_builder = Geom::Path(); //the path to store the result in - Geom::PathVector * path_vec; //needed because livarot returns a goddamn pointer + ::Path to_outline; + ::Path outlined_result; - const unsigned k = pv.size(); + Geom::Path path_builder = Geom::Path(); // the path to store the result in + Geom::PathVector* path_vec; // needed because livarot returns a pointer (TODO make this not a pointer) - for (unsigned u = 0; u < k; u+=2) { + // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well + const size_t k = pv.size(); + for (size_t u = 0; u < k; u += 2) { to_outline = Path(); outlined_result = Path(); - to_outline.LoadPath(pv[u], Geom::Affine(), false, false); + to_outline.LoadPath(pv[u], Geom::identity(), false, false); to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); - //now a curve has been outside outlined and loaded into outlined_result + // now a curve has been outside outlined and loaded into outlined_result - //get the Geom::Path + // get the Geom::Path path_vec = outlined_result.MakePathVector(); - //thing to do on the first run through + // on the first run through, there is no join if (u == 0) { - //I could use the pv->operator[] (0) notation but that looks terrible - path_builder.start( (*path_vec)[0].initialPoint() ); - path_builder.append( (*path_vec)[0] ); + path_builder.start(path_vec->front().initialPoint()); + path_builder.append(path_vec->front()); } else { - //get the curves ready for the operation - Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); - - //do the reflection/extrapolation: - if (extrapolate) { - extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); - } else { - reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u - 1] [pv[u - 1].size() - 1], pv[u] [0] )); - } - //store it - Geom::Path temp_path = (*path_vec)[0]; - //erase the first segment since the join code already appended it - temp_path.erase(temp_path.begin()); - - path_builder.append( temp_path ); + outlineHelper(path_builder, path_vec, outside_angle(pv[u-1][pv[u-1].size()-1], pv[u][0]), line_width, miter_limit, func); } - //outline the next segment, but don't store it yet - if (path_vec) delete path_vec; + // outline the next segment, but don't store it yet + if (path_vec) + delete path_vec; + path_vec = NULL; + // odd number of paths if (u < k - 1) { outlined_result = Path(); to_outline = Path(); @@ -466,29 +458,11 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double to_outline.OutsideOutline(&outlined_result, line_width / 2, join_straight, butt_straight, 10); path_vec = outlined_result.MakePathVector(); + outlineHelper(path_builder, path_vec, outside_angle(pv[u][pv[u].size()-1], pv[u+1][0]), line_width, miter_limit, func); - //get the curves ready for the operation - Geom::Curve * cbc1 = path_builder[path_builder.size() - 1].duplicate(); - Geom::Curve * cbc2 = (*path_vec)[0] [0].duplicate(); - - //do the reflection/extrapolation: - if (extrapolate) { - extrapolate_curves(path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); - } else { - reflect_curves (path_builder, cbc1, cbc2, (*path_vec)[0].initialPoint(), miter_limit, line_width, - outside_angle ( pv[u] [pv[u].size()-1], pv[u+1] [0] )); - } - - //Now we can store it. - Geom::Path temp_path = (*path_vec)[0]; - temp_path.erase(temp_path.begin()); - - path_builder.append( temp_path ); - - if (cbc1) delete cbc1; - if (cbc2) delete cbc2; - if (path_vec) delete path_vec; + if (path_vec) + delete path_vec; + path_vec = NULL; } } @@ -497,7 +471,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double Geom::Curve * cbc2; if ( path_in[path_in.size()].isDegenerate() ) { - //handle case for last segment curved + // handle case for last segment curved outlined_result = Path(); to_outline = Path(); @@ -509,11 +483,12 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double path_vec = outlined_result.MakePathVector(); cbc1 = path_builder[path_builder.size() - 1].duplicate(); - cbc2 = (*path_vec)[0] [0].duplicate(); + cbc2 = path_vec->front()[0].duplicate(); delete path_vec; } else { - //handle case for last segment straight (since the path doesn't actually give us access to it) + // handle case for last segment straight + // since the path doesn't actually give us access to it, we'll do it ourselves outlined_result = Path(); to_outline = Path(); @@ -527,17 +502,10 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double cbc1 = path_builder[path_builder.size() - 1].duplicate(); cbc2 = (*path_vec)[0] [0].duplicate(); - //append the closing segment - - if (extrapolate) { - extrapolate_curves(path_builder, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( path_in[path_in.size() - 1], oneCurve [0] )); - } else { - reflect_curves (path_builder, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( path_in[path_in.size() - 1], oneCurve [0] )); - } - - delete cbc1; cbc1 = cbc2->duplicate(); + outlineHelper(path_builder, path_vec, outside_angle(path_in[path_in.size()-1], oneCurve[0]), line_width, miter_limit, func); + + delete cbc1; + cbc1 = cbc2->duplicate(); delete path_vec; oneCurve = Geom::Path(); oneCurve.append(path_in[0]); @@ -550,32 +518,35 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double delete path_vec; } - Geom::Path temporary; //just an accessory path, we won't need it for long + Geom::Path temporary; temporary.append(*cbc1); - const Geom::Curve& prev_curve = path_in[path_in.size()].isDegenerate() ? path_in[path_in.size() - 1] : - path_in[path_in.size()]; - - if (extrapolate) { - extrapolate_curves(temporary, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( prev_curve, path_in [0] )); - } else { - reflect_curves (temporary, cbc1, cbc2, cbc2->initialPoint(), miter_limit, line_width, - outside_angle ( prev_curve, path_in [0] )); - } - //extract the appended curves - //if (temporary[temporary.size()].initialPoint() != path_builder[0].initialPoint()) { - path_builder.erase(path_builder.begin()); - /*} else { - temporary.erase_last(); - }*/ - path_builder.erase_last(); - if (Geom::distance(path_builder.finalPoint(), temporary.initialPoint()) > 0.0000001) { - path_builder.appendNew(temporary.initialPoint()); + Geom::Curve const & prev_curve = path_in[path_in.size()].isDegenerate() ? path_in[path_in.size() - 1] : path_in[path_in.size()]; + Geom::Path isStraight; + isStraight.append(prev_curve); + isStraight.append(path_in[0]); + // does closing path require a join? + if (Geom::split_at_cusps(isStraight).size() > 1) { + bool outside = outside_angle(prev_curve, path_in[0]); + if (outside) { + func(temporary, *cbc2, miter_limit, line_width); + } else { + joinInside(temporary, *cbc2); + path_builder.erase(path_builder.begin()); + } + + // extract the appended curves + path_builder.erase_last(); + if (Geom::are_near(path_builder.finalPoint(), temporary.initialPoint())) { + path_builder.setFinal(temporary.initialPoint()); + } else { + path_builder.appendNew(temporary.initialPoint()); + } + path_builder.append(temporary); } else { - path_builder.setFinal(temporary.initialPoint()); + // closing path does not require a join + path_builder.setFinal(path_builder.initialPoint()); } - path_builder.append(temporary); path_builder.close(); if (cbc1) delete cbc1; @@ -585,8 +556,7 @@ Geom::Path doAdvHalfOutline(const Geom::Path& path_in, double line_width, double return path_builder; } -Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, - ButtTypeMod butt, double miter_lim, bool extrapolate, double start_lean, double end_lean) +Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, ButtTypeMod butt, double miter_lim, bool extrapolate, double start_lean, double end_lean) { Geom::PathVector path_out; @@ -594,16 +564,14 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, for (unsigned i = 0; i < pv_size; i++) { if (path_in[i].size() > 1) { - //since you've made it this far, hopefully all this is obvious :P Geom::Path with_direction; Geom::Path against_direction; - - with_direction = Outline::doAdvHalfOutline( path_in[i], -line_width, miter_lim, extrapolate ); - against_direction = Outline::doAdvHalfOutline( path_in[i].reverse(), -line_width, miter_lim, extrapolate ); + + with_direction = Outline::outlineHalf(path_in[i], -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves); + against_direction = Outline::outlineHalf(path_in[i].reverse(), -line_width, miter_lim, extrapolate ? extrapolate_curves : reflect_curves); Geom::PathBuilder pb; - //add in the...do I really need to say this? pb.moveTo(with_direction.initialPoint()); pb.append(with_direction); @@ -724,8 +692,7 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, return path_out; } -Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, - LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean) +Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean) { std::vector path_out = std::vector(); if (path_in.empty()) { @@ -761,21 +728,21 @@ Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line break; } } - if (linejoin_type <= 2) { + if (linejoin_type <= LINEJOIN_POINTY) { p.Outline(&outlinepath, line_width / 2, static_cast(linejoin_type), original_butt, miter_lim); - //fix memory leak + // fix memory leak std::vector *pv_p = outlinepath.MakePathVector(); path_out = *pv_p; delete pv_p; - } else if (linejoin_type == 3) { - //reflected arc join + } else if (linejoin_type == LINEJOIN_REFLECTED) { + // reflected arc join path_out = outlinePath(path_in, line_width, static_cast(linejoin_type), linecap_type , miter_lim, false, start_lean, end_lean); - } else if (linejoin_type == 4) { - //extrapolated arc join + } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) { + // extrapolated arc join path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true, start_lean, end_lean); } @@ -800,16 +767,14 @@ Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, Lin path_outline.OutsideOutline(&path_tangent, line_width / 2, static_cast(linejoin_type), butt_straight, miter_lim); pathvec = path_tangent.MakePathVector(); - path_out = pathvec[0]/* deref pointer */[0]/*actual object ref*/; + path_out = pathvec->front(); delete pathvec; return path_out; } else if (linejoin_type == LINEJOIN_REFLECTED) { - //reflected half outline - path_out = doAdvHalfOutline(path_in, line_width, miter_lim, false); + path_out = outlineHalf(path_in, line_width, miter_lim, reflect_curves); return path_out; } else if (linejoin_type == LINEJOIN_EXTRAPOLATED) { - //what the hell do you think this is? :P - path_out = doAdvHalfOutline(path_in, line_width, miter_lim, true); + path_out = outlineHalf(path_in, line_width, miter_lim, extrapolate_curves); return path_out; } #undef miter_lim @@ -827,4 +792,4 @@ Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, Lin fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8 : diff --git a/src/live_effects/pathoutlineprovider.h b/src/live_effects/pathoutlineprovider.h index 272c93a49..c17584be2 100644 --- a/src/live_effects/pathoutlineprovider.h +++ b/src/live_effects/pathoutlineprovider.h @@ -1,5 +1,13 @@ -#ifndef _SEEN_PATH_OUTLINE_H -#define _SEEN_PATH_OUTLINE_H +#ifndef SEEN_PATH_OUTLINE_H +#define SEEN_PATH_OUTLINE_H + +/* Author: + * Liam P. White + * + * Copyright (C) 2014 Author + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ #include #include @@ -18,10 +26,11 @@ enum ButtTypeMod { BUTT_POINTY, BUTT_LEANED }; + namespace Geom { - Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in); - std::vector split_at_cusps(const Geom::Path& in); + Geom::CubicBezier sbasis_to_cubicbezier(Geom::D2 const & sbasis_in); + std::vector split_at_cusps(const Geom::Path& in); } namespace Outline @@ -29,10 +38,18 @@ namespace Outline unsigned bezierOrder (const Geom::Curve* curve_in); std::vector PathVectorOutline(std::vector const & path_in, double line_width, ButtTypeMod linecap_type, LineJoinType linejoin_type, double miter_limit, double start_lean = 0, double end_lean = 0); - - /*Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, LineJoinType join, - ButtTypeMod butt, double miter_lim, bool extrapolate = false);*/ Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit); } -#endif // _SEEN_PATH_OUTLINE_H +#endif // SEEN_PATH_OUTLINE_H + +/* + 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:fileencoding=utf-8 : -- cgit v1.2.3 From 693e6eb237a6c4fbc9a9d47a30fad10b74e2157b Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 24 Jul 2014 01:20:18 +0200 Subject: Fix bug on closed nodes in fillet-chamfer LPE (bzr r13341.1.96) --- src/live_effects/lpe-fillet-chamfer.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index a24f5e60e..1c3dc645c 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -512,24 +512,27 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) if (filletChamferData[counter][Y] == 0) { time_it1 = 0; } - time_it2 = modf(fillet_chamfer_values.to_time( - counter + 1, filletChamferData[counter + 1][X]), - &intpart); - if (curve_it2 == curve_endit) { + if (path_it->closed() && curve_it2 == curve_endit) { time_it2 = modf(fillet_chamfer_values.to_time( counter - counterCurves, filletChamferData[counter - counterCurves][X]), &intpart); + } else { + time_it2 = modf(fillet_chamfer_values.to_time( + counter + 1, filletChamferData[counter + 1][X]), + &intpart); } - double resultLenght = - it1_length + fillet_chamfer_values.to_len( - counter + 1, filletChamferData[counter + 1][X]); + double resultLenght = 0; time_it1_B = 1; if (path_it->closed() && curve_it2 == curve_endit) { resultLenght = it1_length + fillet_chamfer_values.to_len( counter - counterCurves, filletChamferData[counter - counterCurves][X]); + } else { + resultLenght = + it1_length + fillet_chamfer_values.to_len( + counter + 1, filletChamferData[counter + 1][X]); } if (resultLenght > 0 && time_it2 != 0) { time_it1_B = modf(fillet_chamfer_values.to_time(counter, -resultLenght), @@ -541,7 +544,12 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) time_it1_B = gapHelper; } } - if (filletChamferData[counter + 1][Y] == 0) { + if (path_it->closed() && curve_it2 == curve_endit && + filletChamferData[counter - counterCurves][Y] == 0) { + time_it1_B = 1; + time_it2 = 0; + } else if (path_it->size() > counterCurves + 1 && + filletChamferData[counter + 1][Y] == 0) { time_it1_B = 1; time_it2 = 0; } -- cgit v1.2.3 From 590e801edf05b0063e54dbe36d785c88b65a264a Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 24 Jul 2014 02:31:02 +0200 Subject: Fix a bug on type of 'fillet' on the closing node (bzr r13341.1.97) --- src/live_effects/lpe-fillet-chamfer.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 1c3dc645c..eae37ad36 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -479,7 +479,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) Piecewise > n = rot90(unitVector(der)); fillet_chamfer_values.set_pwd2(pwd2_in, n); std::vector filletChamferData = fillet_chamfer_values.data(); - int counter = 0; + unsigned int counter = 0; //from http://launchpadlibrarian.net/12692602/rcp.svg const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); for (PathVector::const_iterator path_it = path_in.begin(); @@ -502,7 +502,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) curve_endit = path_it->end_open(); } } - int counterCurves = 0; + unsigned int counterCurves = 0; while (curve_it1 != curve_endit) { Coord it1_length = (*curve_it1).length(tolerance); double time_it1, time_it2, time_it1_B, intpart; @@ -604,7 +604,12 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) if (time_it1_B != gapHelper && time_it1_B != time_it1 + gapHelper) { path_out.append(*knotCurve1); } - int type = abs(filletChamferData[counter + 1][Y]); + int type = 0; + if(path_it->closed() && curve_it2 == curve_endit){ + type = abs(filletChamferData[counter - counterCurves][Y]); + } else { + type = abs(filletChamferData[counter + 1][Y]); + } if (type == 3 || type == 4) { if (type == 4) { Geom::Point central = middle_point(startArcPoint, endArcPoint); -- cgit v1.2.3 From ae3b6608ecb46d6a71f6de95768aa0ed72e2dc08 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 28 Jul 2014 17:30:16 -0400 Subject: Don't update path effects on document load (#1299948) Fixed bugs: - https://launchpad.net/bugs/1299948 (bzr r13479) --- src/live_effects/parameter/path.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index cdbbef1db..44d414942 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -118,6 +118,11 @@ PathParam::param_readSVGValue(const gchar * strvalue) // Now do the attaching, which emits the changed signal. try { ref.attach(Inkscape::URI(href)); + //lp:1299948 + SPItem* i = ref.getObject(); + if (i) { + linked_modified_callback(i, SP_OBJECT_MODIFIED_FLAG); + } // else: document still processing new events. Repr of the linked object not created yet. } catch (Inkscape::BadURIException &e) { g_warning("%s", e.what()); ref.detach(); -- cgit v1.2.3 From bb7b71e3af74c4270b4f67210660e33c39386f07 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 30 Jul 2014 02:13:11 +0200 Subject: Added roughen LPE (bzr r13341.1.106) --- src/live_effects/CMakeLists.txt | 2 + src/live_effects/Makefile_insert | 2 + src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 5 + src/live_effects/lpe-roughen.cpp | 389 +++++++++++++++++++++++++++++++++++++++ src/live_effects/lpe-roughen.h | 57 ++++++ 6 files changed, 456 insertions(+) create mode 100644 src/live_effects/lpe-roughen.cpp create mode 100644 src/live_effects/lpe-roughen.h (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index a4d35b339..3c64e5c8e 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -35,6 +35,7 @@ set(live_effects_SRC # lpe-skeleton.cpp lpe-sketch.cpp lpe-spiro.cpp + lpe-roughen.cpp lpe-tangent_to_curve.cpp lpe-test-doEffect-stack.cpp lpe-bspline.cpp @@ -101,6 +102,7 @@ set(live_effects_SRC lpe-skeleton.h lpe-sketch.h lpe-spiro.h + lpe-roughen.h lpe-tangent_to_curve.h lpe-test-doEffect-stack.h lpe-bspline.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 263b33b3c..91651a7c8 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -46,6 +46,8 @@ ink_common_sources += \ live_effects/lpe-lattice.h \ live_effects/lpe-lattice2.cpp \ live_effects/lpe-lattice2.h \ + live_effects/lpe-roughen.cpp \ + live_effects/lpe-roughen.h \ live_effects/lpe-simplify.cpp \ live_effects/lpe-simplify.h \ live_effects/lpe-envelope.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 942ef5891..dac44981c 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -29,6 +29,7 @@ enum EffectType { SPIRO, LATTICE, LATTICE2, + ROUGHEN, SIMPLIFY, ENVELOPE, CONSTRUCT_GRID, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index f0611785b..387dd7b8d 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -27,6 +27,7 @@ #include "live_effects/lpe-spiro.h" #include "live_effects/lpe-lattice.h" #include "live_effects/lpe-lattice2.h" +#include "live_effects/lpe-roughen.h" #include "live_effects/lpe-simplify.h" #include "live_effects/lpe-envelope.h" #include "live_effects/lpe-constructgrid.h" @@ -125,6 +126,7 @@ const Util::EnumData LPETypeData[] = { /* 0.91 */ {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, + {ROUGHEN, N_("Roughen"), "roughen"}, {BSPLINE, N_("BSpline"), "bspline"}, {SIMPLIFY, N_("Simplify"), "simplify"}, {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, @@ -269,6 +271,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case FILLET_CHAMFER: neweffect = static_cast ( new LPEFilletChamfer(lpeobj) ); break; + case ROUGHEN: + neweffect = static_cast ( new LPERoughen(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp new file mode 100644 index 000000000..803ab5844 --- /dev/null +++ b/src/live_effects/lpe-roughen.cpp @@ -0,0 +1,389 @@ +#define INKSCAPE_LPE_ROUGHEN_C +/* + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-roughen.h" +#include "display/curve.h" +#include "live_effects/parameter/parameter.h" +#include "helper/geom.h" +#include +#include +#include + +namespace Inkscape { +namespace LivePathEffect { + +static const Util::EnumData DivisionMethodData[DM_END] = { + { DM_SEGMENTS, N_("By number of segments"), "segments" }, + { DM_SIZE, N_("By max. segment size"), "size" } +}; +static const Util::EnumDataConverter + DMConverter(DivisionMethodData, DM_END); + +LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + // initialise your parameters here: + unit(_("Unit:"), _("Unit"), "unit", &wr, this), + method(_("Method:"), _("Division method"), "method", DMConverter, &wr, + this, DM_SEGMENTS), + maxSegmentSize(_("Max. segment size:"), _("Max. segment size"), + "maxSegmentSize", &wr, this, 10.), + segments(_("Number of segments:"), _("Number of segments"), "segments", + &wr, this, 2), + displaceX(_("Max. displacement in X:"), _("Max. displacement in X"), + "displaceX", &wr, this, 10.), + displaceY(_("Max. displacement in Y:"), _("Max. displacement in Y"), + "displaceY", &wr, this, 10.), + shiftNodes(_("Shift nodes"), _("Shift nodes"), "shiftNodes", &wr, this, + true), + shiftNodeHandles(_("Shift node handles"), _("Shift node handles"), + "shiftNodeHandles", &wr, this, true) { + registerParameter(dynamic_cast(&unit)); + registerParameter(dynamic_cast(&method)); + registerParameter(dynamic_cast(&maxSegmentSize)); + registerParameter(dynamic_cast(&segments)); + registerParameter(dynamic_cast(&displaceX)); + registerParameter(dynamic_cast(&displaceY)); + registerParameter(dynamic_cast(&shiftNodes)); + registerParameter(dynamic_cast(&shiftNodeHandles)); + displaceX.param_set_range(0., Geom::infinity()); + displaceY.param_set_range(0., Geom::infinity()); + maxSegmentSize.param_set_range(0., Geom::infinity()); + maxSegmentSize.param_set_increments(1, 1); + maxSegmentSize.param_set_digits(1); + segments.param_set_range(1, Geom::infinity()); + segments.param_set_increments(1, 1); + segments.param_set_digits(0); +} + +LPERoughen::~LPERoughen() {} + +void LPERoughen::doBeforeEffect(SPLPEItem const */*lpeitem*/) { + displaceX.resetRandomizer(); + displaceY.resetRandomizer(); + srand(1); +} + +Gtk::Widget *LPERoughen::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(2); + std::vector::iterator it = param_vector.begin(); + 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 == "unit") { + Gtk::Label *unitLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Roughen unit")), Gtk::ALIGN_START)); + unitLabel->set_use_markup(true); + vbox->pack_start(*unitLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } + if (param->param_key == "method") { + Gtk::Label *methodLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Add nodes Subdivide each segment")), + Gtk::ALIGN_START)); + methodLabel->set_use_markup(true); + vbox->pack_start(*methodLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } + if (param->param_key == "displaceX") { + Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Jitter nodes Move nodes/handles")), + Gtk::ALIGN_START)); + displaceXLabel->set_use_markup(true); + vbox->pack_start(*displaceXLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } + 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; + } + return dynamic_cast(vbox); +} + +double LPERoughen::sign(double randNumber) { + if (rand() % 100 < 49) { + randNumber *= -1.; + } + return randNumber; +} + +Geom::Point LPERoughen::randomize() { + double displaceXParsed = Inkscape::Util::Quantity::convert( + displaceX, unit.get_abbreviation(), "px"); + double displaceYParsed = Inkscape::Util::Quantity::convert( + displaceY, unit.get_abbreviation(), "px"); + //maybe is better divide this point by 2... + Geom::Point output = + Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); + return output; +} + +void LPERoughen::doEffect(SPCurve *curve) { + Geom::PathVector const original_pathv = + pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); + curve->reset(); + + //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el + //penúltimo + 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 + + 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 + //Creamos las lineas rectas que unen todos los puntos del trazado y donde se + //calcularán + //los puntos clave para los manejadores. + //Esto hace que la curva BSpline no pierda su condición aunque se trasladen + //dichos manejadores + SPCurve *nCurve = new SPCurve(); + 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(); + } + } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline + Geom::Point initialMove(0, 0); + if (shiftNodes) { + initialMove = randomize(); + } + Geom::Point initialPoint = curve_it1->initialPoint() + initialMove; + nCurve->moveto(initialPoint); + Geom::Point A0(0, 0); + Geom::Point A1(0, 0); + Geom::Point A2(0, 0); + Geom::Point A3(0, 0); + while (curve_it2 != curve_endit) { + //aumentamos los valores para el siguiente paso en el bucle + //Recorremos todos los segmentos menos el último + Geom::CubicBezier const *cubic = NULL; + A0 = curve_it1->initialPoint(); + A1 = curve_it1->initialPoint(); + A2 = curve_it1->finalPoint(); + A3 = curve_it1->finalPoint(); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + A1 = (*cubic)[1]; + if (shiftNodes) { + A1 = (*cubic)[1] + initialMove; + } + A2 = (*cubic)[2]; + nCurve->curveto(A1, A2, A3); + } else { + nCurve->lineto(A3); + } + double length = Inkscape::Util::Quantity::convert( + curve_it1->length(0.001), "px", unit.get_abbreviation()); + unsigned int splits = 0; + if (method == DM_SEGMENTS) { + splits = segments; + } else { + splits = ceil(length / maxSegmentSize); + } + for (unsigned int t = splits; t >= 1; t--) { + if (t == 1 && splits != 1) { + continue; + } + const SPCurve *tmp; + if (splits == 1) { + tmp = jitter(nCurve->last_segment()); + } else { + tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); + } + if (nCurve->get_segment_count() > 1) { + nCurve->backspace(); + nCurve->append_continuous(tmp, 0.001); + } else { + nCurve = tmp->copy(); + } + delete tmp; + } + ++curve_it1; + ++curve_it2; + } + Geom::CubicBezier const *cubic = NULL; + A0 = curve_it1->initialPoint(); + A1 = curve_it1->initialPoint(); + A2 = curve_it1->finalPoint(); + A3 = curve_it1->finalPoint(); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + A1 = (*cubic)[1]; + A2 = (*cubic)[2]; + if (path_it->closed()) { + A2 = A2 + initialMove; + A3 = initialPoint; + } + nCurve->curveto(A1, A2, A3); + } else { + if (path_it->closed()) { + A3 = initialPoint; + } + nCurve->lineto(A3); + } + double length = Inkscape::Util::Quantity::convert( + curve_it1->length(0.001), "px", unit.get_abbreviation()); + unsigned int splits = 0; + if (method == DM_SEGMENTS) { + splits = segments; + } else { + splits = ceil(length / maxSegmentSize); + } + for (unsigned int t = splits; t >= 1; t--) { + if (t == 1 && splits != 1) { + continue; + } + const SPCurve *tmp; + if (splits == 1) { + tmp = jitter(nCurve->last_segment()); + } else { + tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); + } + if (nCurve->get_segment_count() > 1) { + nCurve->backspace(); + nCurve->append_continuous(tmp, 0.001); + } else { + nCurve = tmp->copy(); + } + delete tmp; + } + //y cerramos la curva + if (path_it->closed()) { + nCurve->closepath_current(); + } + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; + } +} + +SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) { + SPCurve *out = new SPCurve(); + Geom::CubicBezier const *cubic = dynamic_cast(&*A); + Geom::Point A1(0, 0); + Geom::Point A2(0, 0); + Geom::Point A3(0, 0); + Geom::Point B1(0, 0); + Geom::Point B2(0, 0); + Geom::Point B3(0, 0); + if (shiftNodes) { + A3 = randomize(); + B3 = randomize(); + } + if (shiftNodeHandles) { + A1 = randomize(); + A2 = randomize(); + B1 = randomize(); + B2 = randomize(); + } else { + A2 = A3; + B1 = A3; + B2 = B3; + } + if (cubic) { + std::pair div = cubic->subdivide(t); + std::vector seg1 = div.first.points(), + seg2 = div.second.points(); + out->moveto(seg1[0]); + out->curveto(seg1[1] + A1, seg1[2] + A2, seg1[3] + A3); + out->curveto(seg2[1] + B1, seg2[2], seg2[3]); + } else if (shiftNodeHandles) { + out->moveto(A->initialPoint()); + out->curveto(A->pointAt(t / 3) + A1, A->pointAt((t / 3) * 2) + A2, + A->pointAt(t) + A3); + out->curveto(A->pointAt(t + (t / 3)) + B1, A->pointAt(t + ((t / 3) * 2)), + A->finalPoint()); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->pointAt(t) + A3); + out->lineto(A->finalPoint()); + } + return out; +} + +SPCurve *LPERoughen::jitter(const Geom::Curve *A) { + SPCurve *out = new SPCurve(); + Geom::CubicBezier const *cubic = dynamic_cast(&*A); + Geom::Point A1(0, 0); + Geom::Point A2(0, 0); + Geom::Point A3(0, 0); + if (shiftNodes) { + A3 = randomize(); + } + if (shiftNodeHandles) { + A1 = randomize(); + A2 = randomize(); + } else { + A2 = A3; + } + if (cubic) { + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1] + A1, (*cubic)[2] + A2, (*cubic)[3] + A3); + } else if (shiftNodeHandles) { + out->moveto(A->initialPoint()); + out->curveto(A->pointAt(0.3333) + A1, A->pointAt(0.6666) + A2, + A->finalPoint() + A3); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->finalPoint() + A3); + } + return out; +} + +Geom::Point LPERoughen::tpoint(Geom::Point A, Geom::Point B, double t) { + using Geom::X; + using Geom::Y; + return Geom::Point(A[X] + t * (B[X] - A[X]), A[Y] + t * (B[Y] - A[Y])); +} + +}; //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-roughen.h b/src/live_effects/lpe-roughen.h new file mode 100644 index 000000000..cc7784dc0 --- /dev/null +++ b/src/live_effects/lpe-roughen.h @@ -0,0 +1,57 @@ +#ifndef INKSCAPE_LPE_ROUGHEN_H +#define INKSCAPE_LPE_ROUGHEN_H + +/* + * Inkscape::LPERoughen + * + * 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/parameter.h" +#include "live_effects/parameter/path.h" +#include "live_effects/parameter/bool.h" +#include "live_effects/parameter/unit.h" +#include "live_effects/parameter/random.h" + +namespace Inkscape { +namespace LivePathEffect { + +enum DivisionMethod { + DM_SEGMENTS, + DM_SIZE, + DM_END +}; + +class LPERoughen : public Effect { + +public: + LPERoughen(LivePathEffectObject *lpeobject); + virtual ~LPERoughen(); + + virtual void doEffect(SPCurve *curve); + virtual double sign(double randNumber); + virtual Geom::Point randomize(); + virtual void doBeforeEffect(SPLPEItem const */*lpeitem*/); + virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t); + virtual SPCurve *jitter(const Geom::Curve *A); + virtual Geom::Point tpoint(Geom::Point A, Geom::Point B, double t = 0.5); + virtual Gtk::Widget *newWidget(); + +private: + UnitParam unit; + EnumParam method; + ScalarParam maxSegmentSize; + ScalarParam segments; + RandomParam displaceX; + RandomParam displaceY; + BoolParam shiftNodes; + BoolParam shiftNodeHandles; + LPERoughen(const LPERoughen &); + LPERoughen &operator=(const LPERoughen &); + +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape +#endif -- cgit v1.2.3 From 6303e158736b41c75bf93afc0f07a27c4a41ae8e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 30 Jul 2014 02:22:33 +0200 Subject: Fix a bug pointed by LiamW (bzr r13341.1.107) --- src/live_effects/lpe-roughen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 803ab5844..9af849530 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -1,14 +1,14 @@ -#define INKSCAPE_LPE_ROUGHEN_C /* * Released under GNU GPL, read the file 'COPYING' for more information */ +#include + #include "live_effects/lpe-roughen.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" #include "helper/geom.h" #include -#include #include namespace Inkscape { -- cgit v1.2.3 From ebdfe1ab7d7a3b73346885c635e98b2021921010 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 30 Jul 2014 02:36:53 +0200 Subject: Fix a bug pointed by su_v on fillet-chamfer open paths (bzr r13341.1.109) --- src/live_effects/lpe-fillet-chamfer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index eae37ad36..1dffba1bf 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -517,6 +517,8 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) counter - counterCurves, filletChamferData[counter - counterCurves][X]), &intpart); + } else if (!path_it->closed() && curve_it2 == curve_endit){ + time_it2 = 0; } else { time_it2 = modf(fillet_chamfer_values.to_time( counter + 1, filletChamferData[counter + 1][X]), @@ -529,6 +531,8 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) it1_length + fillet_chamfer_values.to_len( counter - counterCurves, filletChamferData[counter - counterCurves][X]); + } else if (!path_it->closed() && curve_it2 == curve_endit){ + resultLenght = 0; } else { resultLenght = it1_length + fillet_chamfer_values.to_len( @@ -607,6 +611,8 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) int type = 0; if(path_it->closed() && curve_it2 == curve_endit){ type = abs(filletChamferData[counter - counterCurves][Y]); + } else if (!path_it->closed() && curve_it2 == curve_endit){ + //0 } else { type = abs(filletChamferData[counter + 1][Y]); } -- cgit v1.2.3 From 5ff454abb53a13499cce928b94cf7538d5ded631 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 6 Aug 2014 17:29:56 +0200 Subject: Fix bug #1241501, improve tooltip text on path parameter (bzr r13494) --- src/live_effects/parameter/path.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 44d414942..8095056b7 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -197,7 +197,7 @@ PathParam::param_newWidget() pButton->show(); pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click)); static_cast(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Link to path")); + pButton->set_tooltip_text(_("Link to path on clipboard")); static_cast(_widget)->show_all_children(); -- cgit v1.2.3 From 8622d1b422ae5305c54174e3e62fdfce9206ef38 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 6 Aug 2014 17:33:21 +0200 Subject: Fix bug #1241501, improve tooltip text on path parameter (bzr r13341.1.118) --- src/live_effects/parameter/path.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 44d414942..8095056b7 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -197,7 +197,7 @@ PathParam::param_newWidget() pButton->show(); pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click)); static_cast(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Link to path")); + pButton->set_tooltip_text(_("Link to path on clipboard")); static_cast(_widget)->show_all_children(); -- cgit v1.2.3 From df69f3dfcda3daf6007802719b1d393fcdce4c13 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 11 Aug 2014 00:12:33 +0200 Subject: Better helper paths in simplify LPE sugested by suv (bzr r13341.1.132) --- src/live_effects/lpe-simplify.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 1a02375cd..7334c8588 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -209,7 +209,7 @@ LPESimplify::generateHelperPath(Geom::PathVector result) drawHandle((*cubic)[1]); drawHandle((*cubic)[2]); drawHandleLine((*cubic)[0],(*cubic)[1]); - drawHandleLine((*cubic)[2],(*cubic)[3]); + drawHandleLine((*cubic)[3],(*cubic)[2]); } } if(nodes){ @@ -224,7 +224,7 @@ LPESimplify::generateHelperPath(Geom::PathVector result) drawHandle((*cubic)[1]); drawHandle((*cubic)[2]); drawHandleLine((*cubic)[0],(*cubic)[1]); - drawHandleLine((*cubic)[2],(*cubic)[3]); + drawHandleLine((*cubic)[3],(*cubic)[2]); } } if(nodes){ @@ -238,13 +238,12 @@ LPESimplify::drawNode(Geom::Point p) { double r = helper_size/0.67; char const * svgd; - svgd = "M 0.999993,0.5 C 1.000065,0.7757576 0.7761859,1 0.4999926,1 0.2237994,1 -7.933901e-5,0.7757576 -7.339015e-6,0.5 -7.933901e-5,0.2242424 0.2237994,0 0.4999926,0 0.7761859,0 1.000065,0.2242424 0.999993,0.5 Z m -0.058561,0 C 0.9414949,0.74327 0.7438375,0.9416286 0.4999928,0.9416286 0.2561481,0.9416286 0.0584908,0.74327 0.0585543,0.5 0.0584908,0.25673 0.2561481,0.0583714 0.4999928,0.0583714 0.7438375,0.0583714 0.9414949,0.25673 0.9414313,0.5 Z m -0.3828447,0 c 8.5e-6,0.030303 -0.026228,0.060606 -0.058593,0.060606 -0.032366,0 -0.058603,-0.030303 -0.058593,-0.060606 -8.5e-6,-0.030303 0.026227,-0.060606 0.058593,-0.060606 0.032366,0 0.058603,0.030303 0.058593,0.060606 z"; + svgd = "M 0,-4.270368e-5 1,-4.270368e-5 1,0.9999573 0,0.9999573 Z M 0.5585873,0.5 C 0.5585958,0.530303 0.5323593,0.560606 0.4999943,0.560606 0.4676283,0.560606 0.4413913,0.530303 0.4414013,0.5 0.4413928,0.469697 0.4676283,0.439394 0.4999943,0.439394 0.5323603,0.439394 0.5585973,0.469697 0.5585873,0.5 Z""; Geom::PathVector pathv = sp_svg_read_pathv(svgd); pathv *= Geom::Affine(r,0,0,r,0,0); pathv += p - Geom::Point(0.5*r,0.5*r); hp.push_back(pathv[0]); hp.push_back(pathv[1]); - hp.push_back(pathv[2]); } void @@ -265,6 +264,11 @@ LPESimplify::drawHandleLine(Geom::Point p,Geom::Point p2) { Geom::Path path; path.start( p ); + if(helper_size > 0.0){ + double diameter = helper_size/0.67; + Geom::Ray ray2(p, p2); + p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35)); + } path.appendNew( p2 ); hp.push_back(path); } -- cgit v1.2.3 From e4b4e65a3ef6341de82cb314a1339167df2dec19 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 11 Aug 2014 00:31:26 +0200 Subject: fix bug pointed by suv (bzr r13341.1.133) --- src/live_effects/lpe-simplify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 7334c8588..a001069b9 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -238,7 +238,7 @@ LPESimplify::drawNode(Geom::Point p) { double r = helper_size/0.67; char const * svgd; - svgd = "M 0,-4.270368e-5 1,-4.270368e-5 1,0.9999573 0,0.9999573 Z M 0.5585873,0.5 C 0.5585958,0.530303 0.5323593,0.560606 0.4999943,0.560606 0.4676283,0.560606 0.4413913,0.530303 0.4414013,0.5 0.4413928,0.469697 0.4676283,0.439394 0.4999943,0.439394 0.5323603,0.439394 0.5585973,0.469697 0.5585873,0.5 Z""; + svgd = "M 0,-4.270368e-5 1,-4.270368e-5 1,0.9999573 0,0.9999573 Z M 0.5585873,0.5 C 0.5585958,0.530303 0.5323593,0.560606 0.4999943,0.560606 0.4676283,0.560606 0.4413913,0.530303 0.4414013,0.5 0.4413928,0.469697 0.4676283,0.439394 0.4999943,0.439394 0.5323603,0.439394 0.5585973,0.469697 0.5585873,0.5 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); pathv *= Geom::Affine(r,0,0,r,0,0); pathv += p - Geom::Point(0.5*r,0.5*r); -- cgit v1.2.3 From 34efde17371ebac38ad634b81496fc578357fc1e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 11 Aug 2014 03:38:48 +0200 Subject: Simplify original paths on helper paths pointed by Liam. Also used arcs for handles pointed by suv (bzr r13341.1.134) --- src/live_effects/lpe-simplify.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index a001069b9..c4c2d449b 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -238,7 +238,7 @@ LPESimplify::drawNode(Geom::Point p) { double r = helper_size/0.67; char const * svgd; - svgd = "M 0,-4.270368e-5 1,-4.270368e-5 1,0.9999573 0,0.9999573 Z M 0.5585873,0.5 C 0.5585958,0.530303 0.5323593,0.560606 0.4999943,0.560606 0.4676283,0.560606 0.4413913,0.530303 0.4414013,0.5 0.4413928,0.469697 0.4676283,0.439394 0.4999943,0.439394 0.5323603,0.439394 0.5585973,0.469697 0.5585873,0.5 Z"; + svgd = "M 0.55,0.5 A 0.05,0.05 0 0 1 0.5,0.55 0.05,0.05 0 0 1 0.45,0.5 0.05,0.05 0 0 1 0.5,0.45 0.05,0.05 0 0 1 0.55,0.5 Z M 0,0 1,0 1,1 0,1 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); pathv *= Geom::Affine(r,0,0,r,0,0); pathv += p - Geom::Point(0.5*r,0.5*r); @@ -251,7 +251,7 @@ LPESimplify::drawHandle(Geom::Point p) { double r = helper_size/0.67; char const * svgd; - svgd = "M 0.6999623,0.35 C 0.7000128,0.5430303 0.5433044,0.7 0.3499775,0.7 0.1566506,0.7 -5.778776e-5,0.5430303 -7.344202e-6,0.35 -5.778776e-5,0.1569697 0.1566506,0 0.3499775,0 0.5433044,0 0.7000128,0.1569697 0.6999623,0.35 Z"; + svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); pathv *= Geom::Affine(r,0,0,r,0,0); pathv += p - Geom::Point(0.35*r,0.35*r); -- cgit v1.2.3 From 4d30762a61aa6975fd6ad2d0a3c97e41e0e8c1b7 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 11 Aug 2014 04:42:02 +0200 Subject: Added reset modifier to knot in fillet chamfer (bzr r13341.1.135) --- .../parameter/filletchamferpointarray.cpp | 78 +++++++++++++--------- 1 file changed, 46 insertions(+), 32 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 457b68dd2..e9d1c0cd0 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -552,31 +552,40 @@ Point FilletChamferPointArrayParamKnotHolderEntity::knot_get() const void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) { if (state & GDK_CONTROL_MASK) { - using namespace Geom; - double type = _pparam->_vector.at(_index)[Y] + 1; - if (type > 4) { - type = 1; - } - _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type); - _pparam->param_set_and_write_new_value(_pparam->_vector); - sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); - const gchar *tip; - if (type == 3) { - tip = _("Chamfer: Ctrl+click toogle type, " - "Shift+click open dialog"); - } else if (type == 2) { - tip = _("Inverse Fillet: Ctrl+click toogle type, " - "Shift+click open dialog"); - } else if (type == 1) { - tip = _("Fillet: Ctrl+click toogle type, " - "Shift+click open dialog"); - } else { - tip = _("Double Chamfer: Ctrl+click toogle type, " - "Shift+click open dialog"); + if (state & GDK_MOD1_MASK) { + _pparam->_vector.at(_index) = Point(_index, _pparam->_vector.at(_index)[Y]); + _pparam->param_set_and_write_new_value(_pparam->_vector); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + }else{ + using namespace Geom; + double type = _pparam->_vector.at(_index)[Y] + 1; + if (type > 4) { + type = 1; + } + _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type); + _pparam->param_set_and_write_new_value(_pparam->_vector); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + const gchar *tip; + if (type == 3) { + tip = _("Chamfer: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); + } else if (type == 2) { + tip = _("Inverse Fillet: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); + } else if (type == 1) { + tip = _("Fillet: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); + } else { + tip = _("Double Chamfer: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); + } + this->knot->tip = g_strdup(tip); + this->knot->show(); } - this->knot->tip = g_strdup(tip); - this->knot->show(); - //} } else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) { Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), _pparam->_vector.at(_index).y()); @@ -619,18 +628,23 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, } const gchar *tip; if (_vector[i][Y] == 3) { - tip = _("Chamfer: Ctrl+click toogle type, " - "Shift+click open dialog"); + tip = _("Chamfer: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); } else if (_vector[i][Y] == 2) { - tip = _("Inverse Fillet: Ctrl+click toogle type, " - "Shift+click open dialog"); + tip = _("Inverse Fillet: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); } else if (_vector[i][Y] == 1) { - tip = _("Fillet: Ctrl+click toogle type, " - "Shift+click open dialog"); + tip = _("Fillet: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); } else { - tip = _("Double Chamfer: Ctrl+click toogle type, " - "Shift+click open dialog"); + tip = _("Double Chamfer: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); } + FilletChamferPointArrayParamKnotHolderEntity *e = new FilletChamferPointArrayParamKnotHolderEntity(this, i); e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip), -- cgit v1.2.3 From 50ab28bfaaf986c4dd0cc363cc3c9cd0f15b82c2 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 11 Aug 2014 05:11:03 +0200 Subject: Code refactor: now helper paths draw ok when handle is degenerate or cirle handle is biger then the distance to node. also remove code duplication at loop (bzr r13341.1.136) --- src/live_effects/lpe-simplify.cpp | 50 +++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 28 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index c4c2d449b..a817f30f1 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -202,33 +202,27 @@ LPESimplify::generateHelperPath(Geom::PathVector result) if(nodes){ drawNode(curve_it1->initialPoint()); } - while (curve_it2 != curve_endit) { - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - if(handles){ - drawHandle((*cubic)[1]); - drawHandle((*cubic)[2]); - drawHandleLine((*cubic)[0],(*cubic)[1]); - drawHandleLine((*cubic)[3],(*cubic)[2]); + while (curve_it1 != curve_endit) { + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + if(handles) { + if(!are_near((*cubic)[0],(*cubic)[1])){ + drawHandle((*cubic)[1]); + drawHandleLine((*cubic)[0],(*cubic)[1]); + } + if(!are_near((*cubic)[3],(*cubic)[2])){ + drawHandle((*cubic)[2]); + drawHandleLine((*cubic)[3],(*cubic)[2]); + } + } + } + if(nodes) { + drawNode(curve_it1->finalPoint()); + } + ++curve_it1; + if(curve_it2 != curve_endit){ + ++curve_it2; } - } - if(nodes){ - drawNode(curve_it1->finalPoint()); - } - ++curve_it1; - ++curve_it2; - } - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - if(handles){ - drawHandle((*cubic)[1]); - drawHandle((*cubic)[2]); - drawHandleLine((*cubic)[0],(*cubic)[1]); - drawHandleLine((*cubic)[3],(*cubic)[2]); - } - } - if(nodes){ - drawNode(curve_it1->finalPoint()); } } } @@ -264,8 +258,8 @@ LPESimplify::drawHandleLine(Geom::Point p,Geom::Point p2) { Geom::Path path; path.start( p ); - if(helper_size > 0.0){ - double diameter = helper_size/0.67; + double diameter = helper_size/0.67; + if(helper_size > 0.0 && Geom::distance(p,p2) > (diameter * 0.35)){ Geom::Ray ray2(p, p2); p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35)); } -- cgit v1.2.3 From 348b712e3fe2fff56c42b5571fc52503744cbb86 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 12 Aug 2014 01:31:31 +0200 Subject: fix a bug knots resetting in fillet-chamfer (bzr r13341.1.137) --- src/live_effects/parameter/filletchamferpointarray.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index e9d1c0cd0..147d6baa2 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -332,10 +332,10 @@ void FilletChamferPointArrayParam::recalculate_knots( result.push_back(Point(xPos, 0)); } ++curve_it1; - ++curve_it2; if (curve_it2 != curve_endit) { - counter++; + ++curve_it2; } + counter++; counterCurves++; } } -- cgit v1.2.3 From 96126a3b2946c788d4701e35becfb22a4c38012e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 13 Aug 2014 00:30:34 +0200 Subject: Add 'Show handles' LPE (bzr r13341.1.139) --- src/live_effects/CMakeLists.txt | 2 + src/live_effects/Makefile_insert | 2 + src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 7 +- src/live_effects/lpe-show_handles.cpp | 211 ++++++++++++++++++++++++++++++++++ src/live_effects/lpe-show_handles.h | 61 ++++++++++ 6 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 src/live_effects/lpe-show_handles.cpp create mode 100644 src/live_effects/lpe-show_handles.h (limited to 'src/live_effects') diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 3c64e5c8e..d126aca9f 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -31,6 +31,7 @@ set(live_effects_SRC lpe-recursiveskeleton.cpp lpe-rough-hatches.cpp lpe-ruler.cpp + lpe-show_handles.cpp lpe-simplify.cpp # lpe-skeleton.cpp lpe-sketch.cpp @@ -99,6 +100,7 @@ set(live_effects_SRC lpe-rough-hatches.h lpe-ruler.h lpe-simplify.h + lpe-show_handles.h lpe-skeleton.h lpe-sketch.h lpe-spiro.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 91651a7c8..e9609a4aa 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -48,6 +48,8 @@ ink_common_sources += \ live_effects/lpe-lattice2.h \ live_effects/lpe-roughen.cpp \ live_effects/lpe-roughen.h \ + live_effects/lpe-show_handles.cpp \ + live_effects/lpe-show_handles.h \ live_effects/lpe-simplify.cpp \ live_effects/lpe-simplify.h \ live_effects/lpe-envelope.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index dac44981c..bc77d65c3 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -30,6 +30,7 @@ enum EffectType { LATTICE, LATTICE2, ROUGHEN, + SHOW_HANDLES, SIMPLIFY, ENVELOPE, CONSTRUCT_GRID, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 387dd7b8d..dc61701df 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -28,6 +28,7 @@ #include "live_effects/lpe-lattice.h" #include "live_effects/lpe-lattice2.h" #include "live_effects/lpe-roughen.h" +#include "live_effects/lpe-show_handles.h" #include "live_effects/lpe-simplify.h" #include "live_effects/lpe-envelope.h" #include "live_effects/lpe-constructgrid.h" @@ -126,7 +127,8 @@ const Util::EnumData LPETypeData[] = { /* 0.91 */ {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, - {ROUGHEN, N_("Roughen"), "roughen"}, + {SHOW_HANDLES, N_("Show handles"), "show_handles"}, + {ROUGHEN, N_("Roughen"), "roughen"}, {BSPLINE, N_("BSpline"), "bspline"}, {SIMPLIFY, N_("Simplify"), "simplify"}, {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, @@ -274,6 +276,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case ROUGHEN: neweffect = static_cast ( new LPERoughen(lpeobj) ); break; + case SHOW_HANDLES: + neweffect = static_cast ( new LPEShowHandles(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp new file mode 100644 index 000000000..7b2b445b7 --- /dev/null +++ b/src/live_effects/lpe-show_handles.cpp @@ -0,0 +1,211 @@ +/* + * Authors: + * Jabier Arraiza Cenoz +* +* Copyright (C) Jabier Arraiza Cenoz 2014 + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include "live_effects/lpe-show_handles.h" +#include "live_effects/parameter/parameter.h" +#include <2geom/sbasis-to-bezier.h> +#include <2geom/svg-path-parser.h> +#include "helper/geom.h" +#include "desktop-style.h" +#include "style.h" +#include "svg/svg.h" + +namespace Inkscape { +namespace LivePathEffect { + +LPEShowHandles::LPEShowHandles(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + nodes(_("Show nodes"), _("Show nodes"), "nodes", &wr, this, true), + handles(_("Show handles"), _("Show handles"), "handles", &wr, this, true), + originalPath(_("Show path"), _("Show path"), "originalPath", &wr, this, true), + scaleNodesAndHandles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scaleNodesAndHandles", &wr, this, 10) +{ + registerParameter(dynamic_cast(&nodes)); + registerParameter(dynamic_cast(&handles)); + registerParameter(dynamic_cast(&originalPath)); + registerParameter(dynamic_cast(&scaleNodesAndHandles)); + scaleNodesAndHandles.param_set_range(0, 500.); + scaleNodesAndHandles.param_set_increments(1, 1); + scaleNodesAndHandles.param_set_digits(2); + strokeWidth = 1.0; +} + +bool LPEShowHandles::alertsOff = false; + +/** + * Sets default styles to element + * this permanently remove.some styles of the element + */ + +void LPEShowHandles::doOnApply(SPLPEItem const* lpeitem) +{ + if(!alertsOff) { + char *msg = _("The \"show handles\" path effect will remove any custom style on the object you are applying it to. If this is not what you want, click Cancel."); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true); + gint response = dialog.run(); + alertsOff = true; + if(response == GTK_RESPONSE_CANCEL) { + SPLPEItem* item = const_cast(lpeitem); + item->removeCurrentPathEffect(false); + return; + } + } + SPLPEItem* item = const_cast(lpeitem); + SPCSSAttr *css = sp_repr_css_attr_new (); + sp_repr_css_set_property (css, "stroke", "black"); + sp_repr_css_set_property (css, "stroke-width", "1"); + sp_repr_css_set_property (css, "stroke-linecap", "butt"); + sp_repr_css_set_property(css, "fill", "none"); + + sp_desktop_apply_css_recursive(item, css, true); + sp_repr_css_attr_unref (css); +} + +void LPEShowHandles::doBeforeEffect (SPLPEItem const* lpeitem) +{ + SPItem const* item = SP_ITEM(lpeitem); + strokeWidth = item->style->stroke_width.computed; +} + +std::vector LPEShowHandles::doEffect_path (std::vector const & path_in) +{ + std::vector path_out; + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in); + if(originalPath) { + for (unsigned int i=0; i < path_in.size(); i++) { + path_out.push_back(path_in[i]); + } + } + if(!outlinepath.empty()) { + outlinepath.clear(); + } + generateHelperPath(original_pathv); + for (unsigned int i=0; i < outlinepath.size(); i++) { + path_out.push_back(outlinepath[i]); + } + return path_out; +} + +void +LPEShowHandles::generateHelperPath(Geom::PathVector result) +{ + if(!handles && !nodes) { + return; + } + + Geom::CubicBezier const *cubic = NULL; + for (Geom::PathVector::iterator path_it = result.begin(); path_it != result.end(); ++path_it) { + //Si está vacío... + if (path_it->empty()) { + continue; + } + //Itreadores + 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(nodes) { + drawNode(curve_it1->initialPoint()); + } + while (curve_it1 != curve_endit) { + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + if(handles) { + if(!are_near((*cubic)[0],(*cubic)[1])){ + drawHandle((*cubic)[1]); + drawHandleLine((*cubic)[0],(*cubic)[1]); + } + if(!are_near((*cubic)[3],(*cubic)[2])){ + drawHandle((*cubic)[2]); + drawHandleLine((*cubic)[3],(*cubic)[2]); + } + } + } + if(nodes) { + drawNode(curve_it1->finalPoint()); + } + ++curve_it1; + if(curve_it2 != curve_endit){ + ++curve_it2; + } + } + } +} + +void +LPEShowHandles::drawNode(Geom::Point p) +{ + if(strokeWidth * scaleNodesAndHandles > 0.0) { + double diameter = strokeWidth * scaleNodesAndHandles; + char const * svgd; + svgd = "M 0.55,0.5 A 0.05,0.05 0 0 1 0.5,0.55 0.05,0.05 0 0 1 0.45,0.5 0.05,0.05 0 0 1 0.5,0.45 0.05,0.05 0 0 1 0.55,0.5 Z M 0,0 1,0 1,1 0,1 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(diameter,0,0,diameter,0,0); + pathv += p - Geom::Point(diameter/2,diameter/2); + outlinepath.push_back(pathv[0]); + outlinepath.push_back(pathv[1]); + } +} + +void +LPEShowHandles::drawHandle(Geom::Point p) +{ + if(strokeWidth * scaleNodesAndHandles > 0.0) { + double diameter = strokeWidth * scaleNodesAndHandles; + char const * svgd; + svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(diameter,0,0,diameter,0,0); + pathv += p - Geom::Point(diameter * 0.35,diameter * 0.35); + outlinepath.push_back(pathv[0]); + } +} + + +void +LPEShowHandles::drawHandleLine(Geom::Point p,Geom::Point p2) +{ + Geom::Path path; + double diameter = strokeWidth * scaleNodesAndHandles; + if(diameter > 0.0 && Geom::distance(p,p2) > (diameter * 0.35)){ + Geom::Ray ray2(p, p2); + p2 = p2 - Geom::Point::polar(ray2.angle(),(diameter * 0.35)); + } + path.start( p ); + path.appendNew( p2 ); + outlinepath.push_back(path); +} + +}; //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-show_handles.h b/src/live_effects/lpe-show_handles.h new file mode 100644 index 000000000..278908bb5 --- /dev/null +++ b/src/live_effects/lpe-show_handles.h @@ -0,0 +1,61 @@ +#ifndef INKSCAPE_LPE_SHOW_HANDLES_H +#define INKSCAPE_LPE_SHOW_HANDLES_H + +/* + * Authors: + * Jabier Arraiza Cenoz +* +* Copyright (C) Jabier Arraiza Cenoz 2014 + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/lpegroupbbox.h" +#include "live_effects/parameter/bool.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEShowHandles : public Effect , GroupBBoxEffect { + +public: + LPEShowHandles(LivePathEffectObject *lpeobject); + virtual ~LPEShowHandles(){} + + virtual void doOnApply(SPLPEItem const* lpeitem); + + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + + virtual void generateHelperPath(Geom::PathVector result); + + virtual void drawNode(Geom::Point p); + + virtual void drawHandle(Geom::Point p); + + virtual void drawHandleLine(Geom::Point p,Geom::Point p2); + +protected: + + virtual std::vector doEffect_path (std::vector const & path_in); + +private: + + BoolParam nodes; + BoolParam handles; + BoolParam originalPath; + ScalarParam scaleNodesAndHandles; + double strokeWidth; + static bool alertsOff; + + Geom::PathVector outlinepath; + + LPEShowHandles(const LPEShowHandles &); + LPEShowHandles &operator=(const LPEShowHandles &); + +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape +#endif + +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : -- cgit v1.2.3 From ab9df1bf462c32d785e0b146228d5711a0599114 Mon Sep 17 00:00:00 2001 From: Kris De Gussem Date: Fri, 15 Aug 2014 15:14:32 +0200 Subject: memleak fix (Bug #1293827: LivePathEffect memory leak ) (bzr r13520) --- src/live_effects/parameter/parameter.cpp | 8 +++++++- src/live_effects/parameter/parameter.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index a5de2169e..ad2960cd9 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -36,13 +36,19 @@ Parameter::Parameter( const Glib::ustring& label, const Glib::ustring& tip, { } - void Parameter::param_write_to_repr(const char * svgd) { param_effect->getRepr()->setAttribute(param_key.c_str(), svgd); } +void Parameter::write_to_SVG(void) +{ + gchar * str = param_getSVGValue(); + param_write_to_repr(str); + g_free(str); +} + /*########################################### * REAL PARAM */ diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index 785ada92e..2e6cae49f 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -49,7 +49,7 @@ public: virtual bool param_readSVGValue(const gchar * strvalue) = 0; // returns true if new value is valid / accepted. virtual gchar * param_getSVGValue() const = 0; - void write_to_SVG() { param_write_to_repr(param_getSVGValue()); } + void write_to_SVG(); virtual void param_set_default() = 0; -- cgit v1.2.3 From ea13ae28b62fc00c08ff2bb74e849e7964bf8467 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 20 Aug 2014 23:53:23 +0200 Subject: Fix bug #1068987 LPE prespective_path crash inkscape (bzr r13529) --- src/live_effects/lpe-perspective_path.cpp | 102 +++++++++++++++++++++++++++++- src/live_effects/lpe-perspective_path.h | 3 + 2 files changed, 102 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index c255f8665..a2372131c 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -10,17 +10,18 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include #include #include "persp3d.h" //#include "transf_mat_3x4.h" #include "document.h" - +#include "document-private.h" #include "live_effects/lpe-perspective_path.h" #include "sp-item-group.h" #include "knot-holder-entity.h" #include "knotholder.h" +#include "desktop.h" #include "inkscape.h" @@ -41,6 +42,7 @@ public: } // namespace PP +static Glib::ustring perspectiveID = _("First perspective"); LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: @@ -59,9 +61,18 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; - + unapply = false; Persp3D *persp = persp3d_document_first_persp(inkscape_active_document()); + if(persp == 0 ){ + char *msg = _("You need a BOX 3D object"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + unapply = true; + return; + } Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; + pmat = pmat * inkscape_active_desktop()->doc2dt(); pmat.copy_tmat(tmat); } @@ -74,8 +85,50 @@ void LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem, true); + if(unapply){ + SP_LPE_ITEM(lpeitem)->removeCurrentPathEffect(false); + return; + } } +void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { + perspectiveID = perspective->get_text(); + Persp3D *first = 0; + Persp3D *persp = 0; + for ( SPObject *child = inkscape_active_document()->getDefs()->firstChild(); child && !persp; child = child->getNext() ) { + if (SP_IS_PERSP3D(child) && first == 0) { + first = SP_PERSP3D(child); + } + if (SP_IS_PERSP3D(child) && strcmp(child->getId(), const_cast(perspectiveID.c_str())) == 0) { + persp = SP_PERSP3D(child); + break; + } + } + if(first == 0 ){ + char *msg = _("You need a BOX 3D object"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + return; + } + if(persp == 0){ + persp = first; + char *msg = _("First perspective selected"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + perspectiveID = _("First perspective"); + }else{ + char *msg = _("Perspective changed"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + } + Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; + pmat = pmat * inkscape_active_desktop()->doc2dt(); + pmat.copy_tmat(tmat); +}; + Geom::Piecewise > LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) { @@ -139,6 +192,49 @@ LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise > cons return output; } +Gtk::Widget * +LPEPerspectivePath::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); + std::vector::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter * param = *it; + Gtk::Widget * widg = dynamic_cast(param->param_newWidget()); + 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; + } + Gtk::HBox * perspectiveId = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::Label* labelPerspective = Gtk::manage(new Gtk::Label("Perspective ID:", 0., 0.)); + Gtk::Entry* perspective = Gtk::manage(new Gtk::Entry()); + perspective->set_text(perspectiveID); + perspective->set_tooltip_text("Set the perspective ID to apply"); + perspectiveId->pack_start(*labelPerspective, true, true, 2); + perspectiveId->pack_start(*perspective, true, true, 2); + vbox->pack_start(*perspectiveId, true, true, 2); + Gtk::Button* apply3D = Gtk::manage(new Gtk::Button(Glib::ustring(_("Refresh perspective")))); + apply3D->set_alignment(0.0, 0.5); + apply3D->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,&LPEPerspectivePath::refresh),perspective)); + Gtk::Widget* apply3DWidget = dynamic_cast(apply3D); + apply3DWidget->set_tooltip_text("Refresh perspective"); + vbox->pack_start(*apply3DWidget, true, true,2); + return dynamic_cast(vbox); +} + void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { KnotHolderEntity *e = new PP::KnotHolderEntityOffset(this); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h index a9ee004f9..6ccac4a51 100644 --- a/src/live_effects/lpe-perspective_path.h +++ b/src/live_effects/lpe-perspective_path.h @@ -38,6 +38,8 @@ public: virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); + virtual void refresh(Gtk::Entry* perspective); + virtual Gtk::Widget * newWidget(); /* the knotholder entity classes must be declared friends */ friend class PP::KnotHolderEntityOffset; void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); @@ -52,6 +54,7 @@ private: BoolParam uses_plane_xy; // there are all kinds of parameters. Check the /live_effects/parameter directory which types exist! + bool unapply; Geom::Point orig; LPEPerspectivePath(const LPEPerspectivePath&); -- cgit v1.2.3 From dc57a722e203077e92d6b51c4721145dd8b3b5ec Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 20 Aug 2014 23:56:55 +0200 Subject: Fix bug #1068987 LPE prespective_path crash inkscape (bzr r13341.1.149) --- src/live_effects/lpe-perspective_path.cpp | 102 +++++++++++++++++++++++++++++- src/live_effects/lpe-perspective_path.h | 3 + 2 files changed, 102 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index c255f8665..a2372131c 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -10,17 +10,18 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include #include #include "persp3d.h" //#include "transf_mat_3x4.h" #include "document.h" - +#include "document-private.h" #include "live_effects/lpe-perspective_path.h" #include "sp-item-group.h" #include "knot-holder-entity.h" #include "knotholder.h" +#include "desktop.h" #include "inkscape.h" @@ -41,6 +42,7 @@ public: } // namespace PP +static Glib::ustring perspectiveID = _("First perspective"); LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: @@ -59,9 +61,18 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; - + unapply = false; Persp3D *persp = persp3d_document_first_persp(inkscape_active_document()); + if(persp == 0 ){ + char *msg = _("You need a BOX 3D object"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + unapply = true; + return; + } Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; + pmat = pmat * inkscape_active_desktop()->doc2dt(); pmat.copy_tmat(tmat); } @@ -74,8 +85,50 @@ void LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem, true); + if(unapply){ + SP_LPE_ITEM(lpeitem)->removeCurrentPathEffect(false); + return; + } } +void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { + perspectiveID = perspective->get_text(); + Persp3D *first = 0; + Persp3D *persp = 0; + for ( SPObject *child = inkscape_active_document()->getDefs()->firstChild(); child && !persp; child = child->getNext() ) { + if (SP_IS_PERSP3D(child) && first == 0) { + first = SP_PERSP3D(child); + } + if (SP_IS_PERSP3D(child) && strcmp(child->getId(), const_cast(perspectiveID.c_str())) == 0) { + persp = SP_PERSP3D(child); + break; + } + } + if(first == 0 ){ + char *msg = _("You need a BOX 3D object"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + return; + } + if(persp == 0){ + persp = first; + char *msg = _("First perspective selected"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + perspectiveID = _("First perspective"); + }else{ + char *msg = _("Perspective changed"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); + } + Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; + pmat = pmat * inkscape_active_desktop()->doc2dt(); + pmat.copy_tmat(tmat); +}; + Geom::Piecewise > LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) { @@ -139,6 +192,49 @@ LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise > cons return output; } +Gtk::Widget * +LPEPerspectivePath::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); + std::vector::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter * param = *it; + Gtk::Widget * widg = dynamic_cast(param->param_newWidget()); + 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; + } + Gtk::HBox * perspectiveId = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::Label* labelPerspective = Gtk::manage(new Gtk::Label("Perspective ID:", 0., 0.)); + Gtk::Entry* perspective = Gtk::manage(new Gtk::Entry()); + perspective->set_text(perspectiveID); + perspective->set_tooltip_text("Set the perspective ID to apply"); + perspectiveId->pack_start(*labelPerspective, true, true, 2); + perspectiveId->pack_start(*perspective, true, true, 2); + vbox->pack_start(*perspectiveId, true, true, 2); + Gtk::Button* apply3D = Gtk::manage(new Gtk::Button(Glib::ustring(_("Refresh perspective")))); + apply3D->set_alignment(0.0, 0.5); + apply3D->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,&LPEPerspectivePath::refresh),perspective)); + Gtk::Widget* apply3DWidget = dynamic_cast(apply3D); + apply3DWidget->set_tooltip_text("Refresh perspective"); + vbox->pack_start(*apply3DWidget, true, true,2); + return dynamic_cast(vbox); +} + void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { KnotHolderEntity *e = new PP::KnotHolderEntityOffset(this); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h index a9ee004f9..6ccac4a51 100644 --- a/src/live_effects/lpe-perspective_path.h +++ b/src/live_effects/lpe-perspective_path.h @@ -38,6 +38,8 @@ public: virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); + virtual void refresh(Gtk::Entry* perspective); + virtual Gtk::Widget * newWidget(); /* the knotholder entity classes must be declared friends */ friend class PP::KnotHolderEntityOffset; void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); @@ -52,6 +54,7 @@ private: BoolParam uses_plane_xy; // there are all kinds of parameters. Check the /live_effects/parameter directory which types exist! + bool unapply; Geom::Point orig; LPEPerspectivePath(const LPEPerspectivePath&); -- cgit v1.2.3 From a8d5997ca58774796bff56a69dad64260cbbc36a Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 23 Aug 2014 18:39:36 +0200 Subject: To help the SVG WG discussion on powerstroke, a quick code-up of centripetal Catmull-Rom interpolation. The code probably needs a clean up pass, and more generally, the interpolation functions should move into 2geom or at least into a .cpp file. - Add Catmull-Rom interpolation to powerstroke interpolation options - Add LPE Interpolate points (bzr r13341.1.156) --- src/live_effects/Makefile_insert | 2 + src/live_effects/effect-enum.h | 1 + src/live_effects/effect.cpp | 6 ++ src/live_effects/lpe-powerstroke-interpolators.h | 81 +++++++++++++++++++++++- src/live_effects/lpe-powerstroke.cpp | 3 +- 5 files changed, 90 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index e9609a4aa..1b8f587e1 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -38,6 +38,8 @@ ink_common_sources += \ live_effects/lpe-gears.h \ live_effects/lpe-interpolate.cpp \ live_effects/lpe-interpolate.h \ + live_effects/lpe-interpolate_points.cpp \ + live_effects/lpe-interpolate_points.h \ live_effects/lpe-test-doEffect-stack.cpp \ live_effects/lpe-test-doEffect-stack.h \ live_effects/lpe-bspline.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index bc77d65c3..30dbf4092 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -45,6 +45,7 @@ enum EffectType { RULER, BOOLOPS, INTERPOLATE, + INTERPOLATE_POINTS, TEXT_LABEL, PATH_LENGTH, LINE_SEGMENT, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index dc61701df..540eb99d4 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -43,6 +43,7 @@ #include "live_effects/lpe-ruler.h" #include "live_effects/lpe-boolops.h" #include "live_effects/lpe-interpolate.h" +#include "live_effects/lpe-interpolate_points.h" #include "live_effects/lpe-text_label.h" #include "live_effects/lpe-path_length.h" #include "live_effects/lpe-line_segment.h" @@ -127,6 +128,7 @@ const Util::EnumData LPETypeData[] = { /* 0.91 */ {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, +/* EXPERIMENTAL */ {SHOW_HANDLES, N_("Show handles"), "show_handles"}, {ROUGHEN, N_("Roughen"), "roughen"}, {BSPLINE, N_("BSpline"), "bspline"}, @@ -135,6 +137,7 @@ const Util::EnumData LPETypeData[] = { // TRANSLATORS: "Envelope Perspective" should be equivalent to "perspective transformation" {ENVELOPE_PERSPECTIVE, N_("Envelope Perspective"), "envelope-perspective"}, {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, + {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, }; const Util::EnumDataConverter LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -231,6 +234,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case INTERPOLATE: neweffect = static_cast ( new LPEInterpolate(lpeobj) ); break; + case INTERPOLATE_POINTS: + neweffect = static_cast ( new LPEInterpolatePoints(lpeobj) ); + break; case TEXT_LABEL: neweffect = static_cast ( new LPETextLabel(lpeobj) ); break; diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index 6f5b75af8..f08259eb3 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -27,7 +27,8 @@ enum InterpolatorType { INTERP_LINEAR, INTERP_CUBICBEZIER, INTERP_CUBICBEZIER_JOHAN, - INTERP_SPIRO + INTERP_SPIRO, + INTERP_CENTRIPETAL_CATMULLROM }; class Interpolator { @@ -168,7 +169,81 @@ private: }; -Interpolator* +// Quick mockup for testing the behavior for powerstroke controlpoint interpolation +class CentripetalCatmullRomInterpolator : public Interpolator { +public: + CentripetalCatmullRomInterpolator() {}; + virtual ~CentripetalCatmullRomInterpolator() {}; + + virtual Path interpolateToPath(std::vector const &points) const { + unsigned int n_points = points.size(); + + Geom::Path fit(points.front()); + + if (n_points < 3) return fit; // TODO special cases for 0,1 and 2 input points + + // return n_points-1 cubic segments + + // duplicate first point + fit.append(calc_bezier(points[0],points[0],points[1],points[2])); + + for (std::size_t i = 0; i < n_points-2; ++i) { + Point p0 = points[i]; + Point p1 = points[i+1]; + Point p2 = points[i+2]; + Point p3 = (i < n_points-3) ? points[i+3] : points[i+2]; + + fit.append(calc_bezier(p0, p1, p2, p3)); + } + + return fit; + }; + +private: + CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const { + // create interpolating bezier between p1 and p2 + + // calculate time coords (deltas) of points + double dt0 = powf(distanceSq(p0, p1), 0.25); + double dt1 = powf(distanceSq(p1, p2), 0.25); + double dt2 = powf(distanceSq(p2, p3), 0.25); + + // safety check for repeated points + double eps = Geom::EPSILON; + if (dt1 < eps) + dt1 = 1.0; + if (dt0 < eps) + dt0 = dt1; + if (dt2 < eps) + dt2 = dt1; + + // compute tangents when parameterized in [t1,t2] + Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1; + Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2; + // rescale tangents for parametrization in [0,1] + tan1 *= dt1; + tan2 *= dt1; + + // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it) + // the tangent of a bezier curve is: B'(t) = 3(1-t)^2 (b1 - b0) + 6(1-t)t(b2-b1) + 3t^2(b3-b2) + // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2 + // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1 + // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2 + + Point b0 = p1; + Point b1 = p1 + tan1 / 3; + Point b2 = p2 - tan2 / 3; + Point b3 = p2; + + return CubicBezier(b0, b1, b2, b3); + } + + CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator&); + CentripetalCatmullRomInterpolator& operator=(const CentripetalCatmullRomInterpolator&); +}; + + +inline Interpolator* Interpolator::create(InterpolatorType type) { switch (type) { case INTERP_LINEAR: @@ -179,6 +254,8 @@ Interpolator::create(InterpolatorType type) { return new Geom::Interpolate::CubicBezierJohan(); case INTERP_SPIRO: return new Geom::Interpolate::SpiroInterpolator(); + case INTERP_CENTRIPETAL_CATMULLROM: + return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); default: return new Geom::Interpolate::Linear(); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 90b01aaa4..5bfe88ed1 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -188,7 +188,8 @@ static const Util::EnumData InterpolatorTypeData[] = { {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, - {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"} + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM, N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} }; static const Util::EnumDataConverter InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); -- cgit v1.2.3 From 3e213be1dff6514f965efce4604e47866eecf9f5 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 23 Aug 2014 18:42:02 +0200 Subject: add missing files from last commit (bzr r13341.1.157) --- src/live_effects/lpe-interpolate_points.cpp | 94 +++++++++++++++++++++++++++++ src/live_effects/lpe-interpolate_points.h | 51 ++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/live_effects/lpe-interpolate_points.cpp create mode 100644 src/live_effects/lpe-interpolate_points.h (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp new file mode 100644 index 000000000..865b46ca7 --- /dev/null +++ b/src/live_effects/lpe-interpolate_points.cpp @@ -0,0 +1,94 @@ +/** \file + * LPE interpolate_points implementation + * Interpolates between knots of the input path. + */ +/* + * Authors: + * Johan Engelen + * + * Copyright (C) Johan Engelen 2014 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-interpolate_points.h" + +#include <2geom/path.h> + +#include "live_effects/lpe-powerstroke-interpolators.h" + +namespace Inkscape { +namespace LivePathEffect { + + +static const Util::EnumData InterpolatorTypeData[] = { + {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, + {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, + {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM, N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} +}; +static const Util::EnumDataConverter InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); + + +LPEInterpolatePoints::LPEInterpolatePoints(LivePathEffectObject *lpeobject) + : Effect(lpeobject) + , interpolator_type( + _("Interpolator type:"), + _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), + "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM) +{ + show_orig_path = false; + + registerParameter( dynamic_cast(&interpolator_type) ); +} + +LPEInterpolatePoints::~LPEInterpolatePoints() +{ +} + + +Geom::PathVector +LPEInterpolatePoints::doEffect_path (Geom::PathVector const & path_in) +{ + Geom::PathVector path_out; + + std::auto_ptr interpolator( Geom::Interpolate::Interpolator::create(static_cast(interpolator_type.get_value())) ); + + for(Geom::PathVector::const_iterator path_it = path_in.begin(); path_it != path_in.end(); ++path_it) { + if (path_it->empty()) + continue; + + if (path_it->closed()) { + g_warning("Interpolate points LPE currently ignores whether path is closed or not."); + } + + std::vector pts; + pts.push_back(path_it->initialPoint()); + + for (Geom::Path::const_iterator it = path_it->begin(), e = path_it->end_default(); it != e; ++it) { + pts.push_back((*it).finalPoint()); + } + + Geom::Path path = interpolator->interpolateToPath(pts); + + path_out.push_back(path); + } + + return path_out; +} + + +} //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-interpolate_points.h b/src/live_effects/lpe-interpolate_points.h new file mode 100644 index 000000000..7a3364747 --- /dev/null +++ b/src/live_effects/lpe-interpolate_points.h @@ -0,0 +1,51 @@ +#ifndef INKSCAPE_LPE_INTERPOLATEPOINTS_H +#define INKSCAPE_LPE_INTERPOLATEPOINTS_H + +/** \file + * LPE interpolate_points implementation, see lpe-interpolate_points.cpp. + */ + +/* + * Authors: + * Johan Engelen + * + * Copyright (C) Johan Engelen 2014 + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/enum.h" +#include "live_effects/effect.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEInterpolatePoints : public Effect { +public: + LPEInterpolatePoints(LivePathEffectObject *lpeobject); + virtual ~LPEInterpolatePoints(); + + virtual std::vector doEffect_path (std::vector const & path_in); + +private: + EnumParam interpolator_type; + + LPEInterpolatePoints(const LPEInterpolatePoints&); + LPEInterpolatePoints& operator=(const LPEInterpolatePoints&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif // INKSCAPE_LPE_INTERPOLATEPOINTS_H + +/* + 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 : -- cgit v1.2.3 From 9b86de418e536b38bdf0d95e75413d57fd8f76b5 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 23 Aug 2014 19:14:02 +0200 Subject: properly attribute code (bzr r13341.1.158) --- src/live_effects/lpe-powerstroke-interpolators.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index f08259eb3..986bd3544 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -203,11 +203,18 @@ private: CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const { // create interpolating bezier between p1 and p2 + // Part of the code comes from StackOverflow user eriatarka84 + // http://stackoverflow.com/a/23980479/2929337 + // calculate time coords (deltas) of points + // the factor 0.25 can be generalized for other Catmull-Rom interpolation types + // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves", + // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf double dt0 = powf(distanceSq(p0, p1), 0.25); double dt1 = powf(distanceSq(p1, p2), 0.25); double dt2 = powf(distanceSq(p2, p3), 0.25); + // safety check for repeated points double eps = Geom::EPSILON; if (dt1 < eps) -- cgit v1.2.3 From 15e0c3e9f564677c12add77f7eec01e4e419b300 Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Sat, 23 Aug 2014 21:39:20 +0100 Subject: Fix deprecated GtkHBox use (bzr r13341.1.167) --- src/live_effects/parameter/togglebutton.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index 5658d238f..c5da8b858 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -5,10 +5,9 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#include "ui/widget/registered-widget.h" #include -#include "ui/widget/registered-widget.h" #include "live_effects/parameter/togglebutton.h" #include "live_effects/effect.h" #include "svg/svg.h" @@ -75,7 +74,12 @@ ToggleButtonParam::param_newWidget() false, param_effect->getRepr(), param_effect->getSPDoc()) ); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget * boxButton = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous(GTK_BOX(boxButton), false); +#else GtkWidget * boxButton = gtk_hbox_new (false, 0); +#endif GtkWidget * labelButton = gtk_label_new (""); if (!param_label.empty()) { if(value || inactiveLabel.empty()){ -- cgit v1.2.3 From c94e03f5c17249c7ef2ebcbe96b2a353aef6d186 Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Sat, 23 Aug 2014 22:03:16 +0100 Subject: Fix orientable Gtkmm widgets (bzr r13341.1.168) --- src/live_effects/lpe-envelope-perspective.cpp | 15 ++++++++++++++- src/live_effects/lpe-roughen.cpp | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp index 02cb67db3..5ada7a792 100644 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ b/src/live_effects/lpe-envelope-perspective.cpp @@ -286,12 +286,20 @@ LPEEnvelopePerspective::newWidget() 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); } @@ -320,8 +328,13 @@ LPEEnvelopePerspective::newWidget() } 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)); @@ -422,4 +435,4 @@ LPEEnvelopePerspective::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v fill-column:99 End: */ -// vim: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 9af849530..5f6acd6f4 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -2,9 +2,9 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include - #include "live_effects/lpe-roughen.h" +#include + #include "display/curve.h" #include "live_effects/parameter/parameter.h" #include "helper/geom.h" @@ -82,7 +82,11 @@ Gtk::Widget *LPERoughen::newWidget() { Glib::ustring(_("Roughen unit")), Gtk::ALIGN_START)); unitLabel->set_use_markup(true); vbox->pack_start(*unitLabel, false, false, 2); +#if WITH_GTKMM_3_0 + vbox->pack_start(*Gtk::manage(new Gtk::Separator()), +#else vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), +#endif Gtk::PACK_EXPAND_WIDGET); } if (param->param_key == "method") { @@ -91,7 +95,11 @@ Gtk::Widget *LPERoughen::newWidget() { Gtk::ALIGN_START)); methodLabel->set_use_markup(true); vbox->pack_start(*methodLabel, false, false, 2); +#if WITH_GTKMM_3_0 + vbox->pack_start(*Gtk::manage(new Gtk::Separator()), +#else vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), +#endif Gtk::PACK_EXPAND_WIDGET); } if (param->param_key == "displaceX") { @@ -100,7 +108,11 @@ Gtk::Widget *LPERoughen::newWidget() { Gtk::ALIGN_START)); displaceXLabel->set_use_markup(true); vbox->pack_start(*displaceXLabel, false, false, 2); +#if WITH_GTKMM_3_0 + vbox->pack_start(*Gtk::manage(new Gtk::Separator()), +#else vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), +#endif Gtk::PACK_EXPAND_WIDGET); } Glib::ustring *tip = param->param_getTooltip(); -- cgit v1.2.3 From a3e1d94ae50f769d2b1539307cf182ce5801e647 Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Sun, 24 Aug 2014 11:37:18 +0100 Subject: Fix Gtk+ 2 build (bzr r13341.1.171) --- src/live_effects/parameter/filletchamferpointarray.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 147d6baa2..a89a6279b 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -8,12 +8,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/filletchamferpointarray.h" #include <2geom/piecewise.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/sbasis-geometric.h> -#include "ui/dialog/lpe-fillet-chamfer-properties.h" -#include "live_effects/parameter/filletchamferpointarray.h" #include "live_effects/effect.h" #include "svg/svg.h" #include "svg/stringstream.h" -- cgit v1.2.3 From 02cc21e061a2862123ef4be7e7ad8aa35fbbbfd5 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 26 Aug 2014 02:27:45 +0200 Subject: remove gtkmm sub-headers (bzr r13341.1.177) --- src/live_effects/lpe-bspline.cpp | 21 +++++++-------------- src/live_effects/lpe-envelope-perspective.cpp | 3 +-- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index a004b8490..433696aab 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -1,5 +1,3 @@ -#define INKSCAPE_LPE_BSPLINE_C - /* * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -8,23 +6,19 @@ # include #endif -#if WITH_GLIBMM_2_32 && HAVE_GLIBMM_THREADS_H +#include + +#if WITH_GLIBMM_2_32 # include #endif -#include <2geom/bezier-curve.h> -#include <2geom/point.h> - -#include -#include -#include -#include -#include - #include #include + #include "display/curve.h" +#include <2geom/bezier-curve.h> +#include <2geom/point.h> #include "helper/geom-curves.h" #include "live_effects/lpe-bspline.h" #include "live_effects/lpeobject.h" @@ -48,8 +42,7 @@ #include "display/sp-canvas.h" #include #include - -// For handling non-contiguous paths: +// For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" #include "desktop.h" diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp index 5ada7a792..3b91eb183 100644 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ b/src/live_effects/lpe-envelope-perspective.cpp @@ -14,12 +14,11 @@ * 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 -#include #include #include #include "desktop.h" -- cgit v1.2.3 From bb1fa6bf07ac6a00eaced3f60400a86cbcb6be0d Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 30 Aug 2014 11:31:41 -0400 Subject: Fix SP_ACTIVE_DOCUMENT usage (document can be determined from context) (bzr r13341.1.185) --- src/live_effects/lpe-perspective_path.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index a2372131c..9e21f5d25 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -18,6 +18,7 @@ #include "document.h" #include "document-private.h" #include "live_effects/lpe-perspective_path.h" +#include "live_effects/lpeobject.h" #include "sp-item-group.h" #include "knot-holder-entity.h" #include "knotholder.h" @@ -62,7 +63,7 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; unapply = false; - Persp3D *persp = persp3d_document_first_persp(inkscape_active_document()); + Persp3D *persp = persp3d_document_first_persp(lpeobject->document); if(persp == 0 ){ char *msg = _("You need a BOX 3D object"); Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, @@ -72,7 +73,7 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : return; } Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; - pmat = pmat * inkscape_active_desktop()->doc2dt(); + pmat = pmat * SP_ACTIVE_DESKTOP->doc2dt(); pmat.copy_tmat(tmat); } @@ -95,7 +96,7 @@ void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { perspectiveID = perspective->get_text(); Persp3D *first = 0; Persp3D *persp = 0; - for ( SPObject *child = inkscape_active_document()->getDefs()->firstChild(); child && !persp; child = child->getNext() ) { + for ( SPObject *child = this->lpeobj->document->getDefs()->firstChild(); child && !persp; child = child->getNext() ) { if (SP_IS_PERSP3D(child) && first == 0) { first = SP_PERSP3D(child); } @@ -125,7 +126,7 @@ void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { dialog.run(); } Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; - pmat = pmat * inkscape_active_desktop()->doc2dt(); + pmat = pmat * SP_ACTIVE_DESKTOP->doc2dt(); pmat.copy_tmat(tmat); }; @@ -144,7 +145,7 @@ LPEPerspectivePath::doEffect_pwd2 (Geom::Piecewise > cons Piecewise preimage[4]; //Geom::Point orig = Geom::Point(bounds_X.min(), bounds_Y.middle()); - //orig = Geom::Point(orig[X], sp_document_height(inkscape_active_document()) - orig[Y]); + //orig = Geom::Point(orig[X], sp_document_height(this->lpeobj->document) - orig[Y]); //double offset = uses_plane_xy ? boundingbox_X.extent() : 0.0; -- cgit v1.2.3 From 1f2d8bc4ce99e970cead4ca96c1859c383a9c043 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 31 Aug 2014 14:17:26 -0400 Subject: Header cleanup: stop using Glib types where they aren't truly needed. Eases GThread deprecation errors. (bzr r13341.1.190) --- src/live_effects/lpe-copy_rotate.cpp | 1 + src/live_effects/lpe-knot.cpp | 1 + src/live_effects/lpeobject-reference.h | 6 +++--- src/live_effects/lpeobject.h | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 65bbcdad1..e466093d3 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -12,6 +12,7 @@ */ #include +#include #include "live_effects/lpe-copy_rotate.h" #include "sp-shape.h" diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index cac3a9347..938287c22 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -22,6 +22,7 @@ #include "knotholder.h" #include +#include #include <2geom/sbasis-to-bezier.h> #include <2geom/sbasis.h> diff --git a/src/live_effects/lpeobject-reference.h b/src/live_effects/lpeobject-reference.h index b1ba1ee4e..374e715ec 100644 --- a/src/live_effects/lpeobject-reference.h +++ b/src/live_effects/lpeobject-reference.h @@ -9,10 +9,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information. */ -#include -#include #include +#include "uri-references.h" + namespace Inkscape { namespace XML { class Node; @@ -33,7 +33,7 @@ public: SPObject *owner; // concerning the LPEObject that is refered to: - gchar *lpeobject_href; + char *lpeobject_href; Inkscape::XML::Node *lpeobject_repr; LivePathEffectObject *lpeobject; diff --git a/src/live_effects/lpeobject.h b/src/live_effects/lpeobject.h index 9700024fe..2e62707e3 100644 --- a/src/live_effects/lpeobject.h +++ b/src/live_effects/lpeobject.h @@ -47,9 +47,9 @@ protected: virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); virtual void release(); - virtual void set(unsigned int key, const gchar* value); + virtual void set(unsigned int key, char const* value); - virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, guint flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags); }; #endif -- cgit v1.2.3 From 119a8120749499e85981f4a7fff44e51f17f0b10 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 2 Sep 2014 16:17:01 -0400 Subject: Fix gtk3 build (bzr r13090.1.107) --- src/live_effects/parameter/filletchamferpointarray.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 1a32e04e7..fc1f6a427 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -8,6 +8,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include + #include "ui/dialog/lpe-fillet-chamfer-properties.h" #include "live_effects/parameter/filletchamferpointarray.h" #include <2geom/piecewise.h> -- cgit v1.2.3 From 55225aa5fd39e2b20d7dd0e70a725306a6500a15 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Thu, 4 Sep 2014 23:59:28 +0200 Subject: lpe interpolate points: small code style fix-up. should be done for all LPEs (bzr r13341.1.197) --- src/live_effects/lpe-interpolate_points.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp index 865b46ca7..4ac139752 100644 --- a/src/live_effects/lpe-interpolate_points.cpp +++ b/src/live_effects/lpe-interpolate_points.cpp @@ -40,7 +40,7 @@ LPEInterpolatePoints::LPEInterpolatePoints(LivePathEffectObject *lpeobject) { show_orig_path = false; - registerParameter( dynamic_cast(&interpolator_type) ); + registerParameter( &interpolator_type ); } LPEInterpolatePoints::~LPEInterpolatePoints() -- cgit v1.2.3 From d685d3f417cbecaf96e2acb55918283f36f21cd3 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 5 Sep 2014 00:02:09 +0200 Subject: LPE Powerstroke: add Centripetal Catmull-Rom interpolator (bzr r13545) --- src/live_effects/lpe-powerstroke-interpolators.h | 90 +++++++++++++++++++++++- src/live_effects/lpe-powerstroke.cpp | 3 +- 2 files changed, 91 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index 6f5b75af8..ee4951882 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -27,7 +27,8 @@ enum InterpolatorType { INTERP_LINEAR, INTERP_CUBICBEZIER, INTERP_CUBICBEZIER_JOHAN, - INTERP_SPIRO + INTERP_SPIRO, + INTERP_CENTRIPETAL_CATMULLROM }; class Interpolator { @@ -167,6 +168,91 @@ private: SpiroInterpolator& operator=(const SpiroInterpolator&); }; +class CentripetalCatmullRomInterpolator : public Interpolator { +// the code in this class can certainly be optimized and made more terse, feel free +public: + CentripetalCatmullRomInterpolator() {}; + virtual ~CentripetalCatmullRomInterpolator() {}; + + virtual Path interpolateToPath(std::vector const &points) const { + unsigned int n_points = points.size(); + + Geom::Path fit(points.front()); + + if (n_points < 2) return fit; + if (n_points < 3) { + // if only 2 points, return linear segment + fit.appendNew(points[1]); + return fit; + } + + // return n_points-1 cubic segments + + // duplicate first point + fit.append(calc_bezier(points[0],points[0],points[1],points[2])); + + for (std::size_t i = 0; i < n_points-2; ++i) { + Point p0 = points[i]; + Point p1 = points[i+1]; + Point p2 = points[i+2]; + Point p3 = (i < n_points-3) ? points[i+3] : points[i+2]; + + fit.append(calc_bezier(p0, p1, p2, p3)); + // this is quite wasteful: the distances between the same points are repeatedly calculated by calc_bezier + } + + return fit; + }; + +private: + CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const { + // create interpolating bezier between p1 and p2 + + // Part of the code comes from StackOverflow user eriatarka84 + // http://stackoverflow.com/a/23980479/2929337 + + // calculate time coords (deltas) of points + // the factor 0.25 can be generalized for other Catmull-Rom interpolation types + // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves", + // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + double dt0 = powf(distanceSq(p0, p1), 0.25); + double dt1 = powf(distanceSq(p1, p2), 0.25); + double dt2 = powf(distanceSq(p2, p3), 0.25); + + + // safety check for repeated points + double eps = Geom::EPSILON; + if (dt1 < eps) + dt1 = 1.0; + if (dt0 < eps) + dt0 = dt1; + if (dt2 < eps) + dt2 = dt1; + + // compute tangents when parameterized in [t1,t2] + Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1; + Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2; + // rescale tangents for parametrization in [0,1] + tan1 *= dt1; + tan2 *= dt1; + + // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it) + // the tangent of a bezier curve is: B'(t) = 3(1-t)^2 (b1 - b0) + 6(1-t)t(b2-b1) + 3t^2(b3-b2) + // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2 + // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1 + // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2 + + Point b0 = p1; + Point b1 = p1 + tan1 / 3; + Point b2 = p2 - tan2 / 3; + Point b3 = p2; + + return CubicBezier(b0, b1, b2, b3); + } + + CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator&); + CentripetalCatmullRomInterpolator& operator=(const CentripetalCatmullRomInterpolator&); +}; Interpolator* Interpolator::create(InterpolatorType type) { @@ -179,6 +265,8 @@ Interpolator::create(InterpolatorType type) { return new Geom::Interpolate::CubicBezierJohan(); case INTERP_SPIRO: return new Geom::Interpolate::SpiroInterpolator(); + case INTERP_CENTRIPETAL_CATMULLROM: + return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); default: return new Geom::Interpolate::Linear(); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 90b01aaa4..eed564b20 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -188,7 +188,8 @@ static const Util::EnumData InterpolatorTypeData[] = { {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, - {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"} + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM , N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} }; static const Util::EnumDataConverter InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); -- cgit v1.2.3 From e043dcd131751f2a0d29068f178fc008dc8c73d7 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 5 Sep 2014 20:30:18 +0200 Subject: LPE Powerstroke: enable Extrapolated arc, remove Extrapolated (mirroring) The code to deal with Extrapolated mirroring is still working (if someone has an old file with that type of extrapolation), but perhaps that should also be removed. (bzr r13546) --- src/live_effects/lpe-powerstroke.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index eed564b20..b8657e165 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -220,12 +220,10 @@ enum LineJoinType { static const Util::EnumData LineJoinTypeData[] = { {LINEJOIN_BEVEL, N_("Beveled"), "bevel"}, {LINEJOIN_ROUND, N_("Rounded"), "round"}, - {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, +// {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, // disabled because doesn't work well + {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, {LINEJOIN_MITER, N_("Miter"), "miter"}, {LINEJOIN_SPIRO, N_("Spiro"), "spiro"}, -#ifdef LPE_ENABLE_TEST_EFFECTS - {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, -#endif }; static const Util::EnumDataConverter LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData)); @@ -407,8 +405,9 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise Date: Sun, 7 Sep 2014 12:34:04 -0400 Subject: Add "HAVE_GLIBMM_THREADS_H" check to fillet-chamfer (bzr r13341.1.200) --- src/live_effects/lpe-fillet-chamfer.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 420425650..2c1d83b2b 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -15,7 +15,13 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#if defined(GLIBMM_DISABLE_DEPRECATED) && defined(HAVE_GLIBMM_THREADS_H) +# include +#endif #include "live_effects/parameter/enum.h" #include "live_effects/parameter/bool.h" -- cgit v1.2.3 From 0d0958e3b2aff0ed5f3ad7a98b4035213475c7f1 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 7 Sep 2014 13:02:01 -0400 Subject: Update to experimental r13543 (bzr r13090.1.108) --- src/live_effects/lpe-interpolate_points.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp index 865b46ca7..4ac139752 100644 --- a/src/live_effects/lpe-interpolate_points.cpp +++ b/src/live_effects/lpe-interpolate_points.cpp @@ -40,7 +40,7 @@ LPEInterpolatePoints::LPEInterpolatePoints(LivePathEffectObject *lpeobject) { show_orig_path = false; - registerParameter( dynamic_cast(&interpolator_type) ); + registerParameter( &interpolator_type ); } LPEInterpolatePoints::~LPEInterpolatePoints() -- cgit v1.2.3 From 24166b289293a2b706a55f6605f06f436fa1d9bc Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 10 Sep 2014 15:12:07 -0400 Subject: Fix bug #1367520 (crash regression) Fixed bugs: - https://launchpad.net/bugs/1367520 (bzr r13551) --- src/live_effects/parameter/path.cpp | 2 +- src/live_effects/parameter/text.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 8095056b7..89947034d 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -143,7 +143,7 @@ gchar * PathParam::param_getSVGValue() const { if (href) { - return href; + return g_strdup(href); } else { gchar * svgd = sp_svg_write_path( _pathvector ); return svgd; diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp index fcb2fc9fc..956a001ad 100644 --- a/src/live_effects/parameter/text.cpp +++ b/src/live_effects/parameter/text.cpp @@ -85,7 +85,7 @@ TextParam::param_readSVGValue(const gchar * strvalue) gchar * TextParam::param_getSVGValue() const { - return (gchar *) value.c_str(); + return g_strdup(value.c_str()); } Gtk::Widget * -- cgit v1.2.3 From 39d4d238a04162c559f83011999cc16feb6da88f Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 11 Sep 2014 05:30:09 +0200 Subject: add radius support to fillet-chamfer, bugfixes (bzr r13341.1.203) --- src/live_effects/lpe-fillet-chamfer.cpp | 163 ++++++------- src/live_effects/lpe-fillet-chamfer.h | 2 + .../parameter/filletchamferpointarray.cpp | 262 ++++++++++++++++++--- .../parameter/filletchamferpointarray.h | 8 +- 4 files changed, 313 insertions(+), 122 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 1dffba1bf..0ad21a284 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -22,6 +22,9 @@ #include "desktop.h" #include "display/curve.h" #include "helper/geom-nodetype.h" +#include "helper/geom-curves.h" +#include "helper/geom.h" + #include "live_effects/parameter/filletchamferpointarray.h" // for programmatically updating knots @@ -49,6 +52,8 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false), only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), + force_arcs(_("Use arcs in cubic curves"), _("Use arcs in cubic curves"), "force_arcs", &wr, this, false), + use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false), unit(_("Unit"), _("Unit"), "unit", &wr, this), radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) @@ -58,9 +63,11 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : registerParameter(&radius); registerParameter(&helper_size); registerParameter(&flexible); + registerParameter(&use_knot_distance); registerParameter(&ignore_radius_0); registerParameter(&only_selected); registerParameter(&hide_knots); + registerParameter(&force_arcs); radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); @@ -270,10 +277,10 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa } std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; + std::vector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); int counter = 0; - for (PathVector::const_iterator path_it = original_pathv.begin(); - path_it != original_pathv.end(); ++path_it) { - int pathCounter = 0; + for (PathVector::const_iterator path_it = original_pathv_processed.begin(); + path_it != original_pathv_processed.end(); ++path_it) { if (path_it->empty()) continue; @@ -289,6 +296,9 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa double powerend = 0; while (curve_it1 != curve_endit) { powerend = power; + if (power < 0 && !use_knot_distance) { + powerend = fillet_chamfer_values.rad_to_len(counter,powerend); + } if (power > 0) { powerend = counter + (power / 100); } @@ -306,7 +316,6 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa ++curve_it1; ++curve_it2; counter++; - pathCounter++; } } fillet_chamfer_values.param_set_and_write_new_value(result); @@ -334,8 +343,9 @@ void LPEFilletChamfer::doChangeType(std::vector const& original_path } std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; + std::vector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); int counter = 0; - for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) { int pathCounter = 0; if (path_it->empty()) continue; @@ -378,7 +388,7 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) { if (SP_IS_SHAPE(lpeItem)) { std::vector point; - PathVector const &original_pathv = SP_SHAPE(lpeItem)->_curve->get_pathvector(); + PathVector const &original_pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeItem)->_curve->get_pathvector()); Piecewise > pwd2_in = paths_to_pw(original_pathv); for (PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -401,10 +411,15 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) } int counter = 0; while (curve_it1 != curve_endit) { + std::pair positions = fillet_chamfer_values.get_positions(counter, original_pathv); Geom::NodeType nodetype; - if (counter == 0) { + if (positions.second == 0) { if (path_it->closed()) { - nodetype = get_nodetype(path_it->back_default(), *curve_it1); + Piecewise > u; + u.push_cut(0); + u.push(pwd2_in[fillet_chamfer_values.last_index(counter, original_pathv)], 1); + Geom::Curve const * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); + nodetype = get_nodetype(*A, *curve_it1); } else { nodetype = NODE_NONE; } @@ -433,12 +448,15 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) { if (SP_IS_SHAPE(lpeItem)) { fillet_chamfer_values.set_helper_size(helper_size); + fillet_chamfer_values.set_use_distance(use_knot_distance); fillet_chamfer_values.set_unit(unit.get_abbreviation()); - SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem)->get_original_curve() : SP_SHAPE(lpeItem)->getCurve(); + SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem) + ->get_original_curve() + : SP_SHAPE(lpeItem)->getCurve(); std::vector filletChamferData = fillet_chamfer_values.data(); if (!filletChamferData.empty() && getKnotsNumber(c) != (int) filletChamferData.size()) { - PathVector const original_pathv = c->get_pathvector(); + PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); Piecewise > pwd2_in = paths_to_pw(original_pathv); fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pwd2_in); } @@ -450,7 +468,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) { int nKnots = c->nodes_in_path(); - PathVector const pv = c->get_pathvector(); + PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); for (std::vector::const_iterator path_it = pv.begin(); path_it != pv.end(); ++path_it) { if (!(*path_it).closed()) { @@ -464,8 +482,7 @@ void LPEFilletChamfer::adjustForNewPath(std::vector const &path_in) { if (!path_in.empty()) { - fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(path_in[0] - .toPwSb()); + fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); } } @@ -473,17 +490,17 @@ std::vector LPEFilletChamfer::doEffect_path(std::vector const &path_in) { std::vector pathvector_out; - Piecewise > pwd2_in = paths_to_pw(path_in); + Piecewise > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in)); pwd2_in = remove_short_cuts(pwd2_in, .01); Piecewise > der = derivative(pwd2_in); Piecewise > n = rot90(unitVector(der)); fillet_chamfer_values.set_pwd2(pwd2_in, n); std::vector filletChamferData = fillet_chamfer_values.data(); unsigned int counter = 0; - //from http://launchpadlibrarian.net/12692602/rcp.svg const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); - for (PathVector::const_iterator path_it = path_in.begin(); - path_it != path_in.end(); ++path_it) { + std::vector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in); + for (PathVector::const_iterator path_it = path_in_processed.begin(); + path_it != path_in_processed.end(); ++path_it) { if (path_it->empty()) continue; Geom::Path path_out; @@ -504,81 +521,24 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } unsigned int counterCurves = 0; while (curve_it1 != curve_endit) { - Coord it1_length = (*curve_it1).length(tolerance); - double time_it1, time_it2, time_it1_B, intpart; - time_it1 = modf( - fillet_chamfer_values.to_time(counter, filletChamferData[counter][X]), - &intpart); - if (filletChamferData[counter][Y] == 0) { - time_it1 = 0; - } - if (path_it->closed() && curve_it2 == curve_endit) { - time_it2 = modf(fillet_chamfer_values.to_time( - counter - counterCurves, - filletChamferData[counter - counterCurves][X]), - &intpart); - } else if (!path_it->closed() && curve_it2 == curve_endit){ - time_it2 = 0; - } else { - time_it2 = modf(fillet_chamfer_values.to_time( - counter + 1, filletChamferData[counter + 1][X]), - &intpart); - } - double resultLenght = 0; - time_it1_B = 1; - if (path_it->closed() && curve_it2 == curve_endit) { - resultLenght = - it1_length + fillet_chamfer_values.to_len( - counter - counterCurves, - filletChamferData[counter - counterCurves][X]); - } else if (!path_it->closed() && curve_it2 == curve_endit){ - resultLenght = 0; - } else { - resultLenght = - it1_length + fillet_chamfer_values.to_len( - counter + 1, filletChamferData[counter + 1][X]); - } - if (resultLenght > 0 && time_it2 != 0) { - time_it1_B = modf(fillet_chamfer_values.to_time(counter, -resultLenght), - &intpart); - } else { - if (time_it2 == 0) { - time_it1_B = 1; - } else { - time_it1_B = gapHelper; - } - } - if (path_it->closed() && curve_it2 == curve_endit && - filletChamferData[counter - counterCurves][Y] == 0) { - time_it1_B = 1; - time_it2 = 0; - } else if (path_it->size() > counterCurves + 1 && - filletChamferData[counter + 1][Y] == 0) { - time_it1_B = 1; - time_it2 = 0; + Curve *curve_it2Fixed = (*path_it->begin()).duplicate(); + if(!path_it->closed() || curve_it2 != curve_endit){ + curve_it2Fixed = (*curve_it2).duplicate(); } - if (time_it1_B < time_it1) { - time_it1_B = time_it1 + gapHelper; - } - Curve *knotCurve1 = curve_it1->portion(time_it1, time_it1_B); + bool last = curve_it2 == curve_endit; + std::vector times = fillet_chamfer_values.get_times(counter, path_in, last); + Curve *knotCurve1 = curve_it1->portion(times[0], times[1]); if (counterCurves > 0) { knotCurve1->setInitial(path_out.finalPoint()); } else { - path_out.start((*curve_it1).pointAt(time_it1)); - } - Curve *knotCurve2 = (*path_it).front().portion(time_it2, 1); - if (curve_it2 != curve_endit) { - knotCurve2 = (*curve_it2).portion(time_it2, 1); + path_out.start((*curve_it1).pointAt(times[0])); } + Curve *knotCurve2 = curve_it2Fixed->portion(times[2], 1); Point startArcPoint = knotCurve1->finalPoint(); - Point endArcPoint = (*path_it).front().pointAt(time_it2); - if (curve_it2 != curve_endit) { - endArcPoint = (*curve_it2).pointAt(time_it2); - } + Point endArcPoint = curve_it2Fixed->pointAt(times[2]); double k1 = distance(startArcPoint, curve_it1->finalPoint()) * K; double k2 = distance(endArcPoint, curve_it1->finalPoint()) * K; - Geom::CubicBezier const *cubic1 = - dynamic_cast(&*knotCurve1); + Geom::CubicBezier const *cubic1 = dynamic_cast(&*knotCurve1); Ray ray1(startArcPoint, curve_it1->finalPoint()); if (cubic1) { ray1.setPoints((*cubic1)[2], startArcPoint); @@ -591,8 +551,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) ray2.setPoints(endArcPoint, (*cubic2)[1]); } Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); - bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, - endArcPoint - startArcPoint) < 0; + bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; double angle = angle_between(ray1, ray2, ccwToggle); double handleAngle = ray1.angle() - angle; if (ccwToggle) { @@ -604,14 +563,22 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) handleAngle = ray2.angle() - angle; } Point inverseHandle2 = endArcPoint - Point::polar(handleAngle,k2); - if (time_it1_B != 1) { - if (time_it1_B != gapHelper && time_it1_B != time_it1 + gapHelper) { + //straigth lines arc based + Line const x_line(Geom::Point(0,0),Geom::Point(1,0)); + Line const angled_line(startArcPoint,endArcPoint); + double angleArc = Geom::angle_between( x_line,angled_line); + double radius = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint))/sin(angle/2.0); + Coord rx = radius; + Coord ry = rx; + + if (times[1] != 1) { + if (times[1] != gapHelper && times[1] != times[0] + gapHelper) { path_out.append(*knotCurve1); } int type = 0; - if(path_it->closed() && curve_it2 == curve_endit){ + if(path_it->closed() && last){ type = abs(filletChamferData[counter - counterCurves][Y]); - } else if (!path_it->closed() && curve_it2 == curve_endit){ + } else if (!path_it->closed() && last){ //0 } else { type = abs(filletChamferData[counter + 1][Y]); @@ -624,15 +591,23 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } path_out.appendNew(endArcPoint); } else if (type == 2) { - path_out.appendNew(inverseHandle1, inverseHandle2, - endArcPoint); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed)) || force_arcs){ + ccwToggle = ccwToggle?0:1; + path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + }else{ + path_out.appendNew(inverseHandle1, inverseHandle2, endArcPoint); + } } else { - path_out.appendNew(handle1, handle2, endArcPoint); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed)) || force_arcs){ + path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + } else { + path_out.appendNew(handle1, handle2, endArcPoint); + } } } else { path_out.append(*knotCurve1); } - if (path_it->closed() && curve_it2 == curve_endit) { + if (path_it->closed() && last) { path_out.close(); } ++curve_it1; diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 2c1d83b2b..49b407b71 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -67,6 +67,8 @@ private: BoolParam ignore_radius_0; BoolParam only_selected; BoolParam flexible; + BoolParam force_arcs; + BoolParam use_knot_distance; UnitParam unit; ScalarParam radius; ScalarParam helper_size; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index a89a6279b..cfc0ebcf1 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -8,12 +8,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/dialog/lpe-fillet-chamfer-properties.h" -#include "live_effects/parameter/filletchamferpointarray.h" #include <2geom/piecewise.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/sbasis-geometric.h> +#include <2geom/svg-elliptical-arc.h> +#include <2geom/line.h> +#include <2geom/path-intersection.h> +#include "ui/dialog/lpe-fillet-chamfer-properties.h" +#include "live_effects/parameter/filletchamferpointarray.h" #include "live_effects/effect.h" #include "svg/svg.h" #include "svg/stringstream.h" @@ -32,6 +35,7 @@ // this has to be included last. #include + using namespace Geom; namespace Inkscape { @@ -165,11 +169,12 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( } } if (last_pathv.size() > pathv.size() || - (last_pathv[counterPaths].size() > counter - offset && + (last_pathv.size() > counterPaths && + last_pathv[counterPaths].size() > counter - offset && !are_near(curve_it1->initialPoint(), last_pathv[counterPaths][counter - offset].initialPoint(), 0.1))) { - if (last_pathv.size() > counterPaths && curve_it2 == curve_endit) { + if ( curve_it2 == curve_endit) { if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) { offset = abs(last_pathv[counterPaths].size() - pathv[counterPaths].size()); @@ -332,10 +337,10 @@ void FilletChamferPointArrayParam::recalculate_knots( result.push_back(Point(xPos, 0)); } ++curve_it1; + counter++; if (curve_it2 != curve_endit) { ++curve_it2; } - counter++; counterCurves++; } } @@ -359,6 +364,11 @@ void FilletChamferPointArrayParam::set_helper_size(int hs) helper_size = hs; } +void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) +{ + use_distance = use_knot_distance; +} + void FilletChamferPointArrayParam::set_unit(const gchar *abbr) { unit = abbr; @@ -398,6 +408,205 @@ void FilletChamferPointArrayParam::addCanvasIndicators( hp_vec.push_back(hp); } +double FilletChamferPointArrayParam::rad_to_len(int index, double rad) +{ + double len = 0; + std::vector subpaths = path_from_piecewise(last_pwd2, 0.1); + std::pair positions = get_positions(index, subpaths); + D2 A = last_pwd2[last_index(index, subpaths)]; + if(positions.second != 0){ + A = last_pwd2[index-1]; + }else{ + if(!subpaths[positions.first].closed()){ + return len; + } + } + D2 B = last_pwd2[index]; + Piecewise > offset_curve0 = Piecewise >(A)+rot90(unitVector(derivative(A)))*(rad); + Piecewise > offset_curve1 = Piecewise >(B)+rot90(unitVector(derivative(B)))*(rad); + Geom::Path p0 = path_from_piecewise(offset_curve0, 0.1)[0]; + Geom::Path p1 = path_from_piecewise(offset_curve1, 0.1)[0]; + Geom::Crossings cs = Geom::crossings(p0, p1); + if(cs.size() > 0){ + Point cp =p0(cs[0].ta); + double p0pt = nearest_point(cp, B); + len = time_to_len(index,p0pt); + } else { + if(rad < 0){ + len = rad_to_len(index, rad * -1); + } + } + return len; +} + +double FilletChamferPointArrayParam::len_to_rad(int index, double len) +{ + double rad = 0; + double tmp_len = _vector[index][X]; + _vector[index] = Geom::Point(len,_vector[index][Y]); + std::vector subpaths = path_from_piecewise(last_pwd2, 0.1); + std::pair positions = get_positions(index, subpaths); + Piecewise > u; + u.push_cut(0); + u.push(last_pwd2[last_index(index, subpaths)], 1); + Geom::Curve * A = path_from_piecewise(u, 0.1)[0][0].duplicate(); + Geom::Curve * B = subpaths[positions.first][positions.second].duplicate(); + std::vector times; + if(positions.second != 0){ + A = subpaths[positions.first][positions.second-1].duplicate(); + times = get_times(index-1, subpaths, false); + }else{ + if(!subpaths[positions.first].closed()){ + return rad; + } + times = get_times(last_index(index, subpaths), subpaths, true); + } + _vector[index] = Geom::Point(tmp_len,_vector[index][Y]); + Geom::Point startArcPoint = A->toSBasis().valueAt(times[1]); + Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]); + Curve *knotCurve1 = A->portion(times[0], times[1]); + Curve *knotCurve2 = B->portion(times[2], 1); + Geom::CubicBezier const *cubic1 = dynamic_cast(&*knotCurve1); + Ray ray1(startArcPoint, A->finalPoint()); + if (cubic1) { + ray1.setPoints((*cubic1)[2], startArcPoint); + } + Geom::CubicBezier const *cubic2 = dynamic_cast(&*knotCurve2); + Ray ray2(B->initialPoint(), endArcPoint); + if (cubic2) { + ray2.setPoints(endArcPoint, (*cubic2)[1]); + } + bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; + double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint)); + double angleBetween = angle_between(ray1, ray2, ccwToggle); + rad = distanceArc/sin(angleBetween/2.0); + return rad * -1; +} + +std::vector FilletChamferPointArrayParam::get_times(int index, std::vector subpaths, bool last) +{ + const double tolerance = 0.001; + const double gapHelper = 0.00001; + std::pair positions = get_positions(index, subpaths); + Curve *curve_it1; + curve_it1 = subpaths[positions.first][positions.second].duplicate(); + Coord it1_length = (*curve_it1).length(tolerance); + double time_it1, time_it2, time_it1_B, intpart; + time_it1 = modf(to_time(index, _vector[index][X]), &intpart); + if (_vector[index][Y] == 0) { + time_it1 = 0; + } + double resultLenght = 0; + time_it1_B = 1; + if (subpaths[positions.first].closed() && last) { + time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart); + resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]); + } else if (!subpaths[positions.first].closed() && last){ + time_it2 = 0; + resultLenght = 0; + } else { + time_it2 = modf(to_time(index + 1, _vector[index + 1][X]), &intpart); + resultLenght = it1_length + to_len( index + 1, _vector[index + 1][X]); + } + if (resultLenght > 0 && time_it2 != 0) { + time_it1_B = modf(to_time(index, -resultLenght), &intpart); + } else { + if (time_it2 == 0) { + time_it1_B = 1; + } else { + time_it1_B = gapHelper; + } + } + + if ((subpaths[positions.first].closed() && last && _vector[index - positions.second][Y] == 0) || (subpaths[positions.first].size() > positions.second + 1 && _vector[index + 1][Y] == 0)) { + time_it1_B = 1; + time_it2 = 0; + } + if (time_it1_B < time_it1) { + time_it1_B = time_it1 + gapHelper; + } + std::vector out; + out.push_back(time_it1); + out.push_back(time_it1_B); + out.push_back(time_it2); + return out; +} + +std::pair FilletChamferPointArrayParam::get_positions(int index, std::vector subpaths) +{ + int counter = -1; + std::size_t first = 0; + std::size_t second = 0; + for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) { + if (path_it->empty()) + continue; + Geom::Path::const_iterator curve_it1 = 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(); + // 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(); + } + } + first++; + second = 0; + while (curve_it1 != curve_endit) { + counter++; + second++; + if(counter == index){ + break; + } + ++curve_it1; + } + if(counter == index){ + break; + } + } + first--; + second--; + std::pair out(first, second); + return out; +} + +int FilletChamferPointArrayParam::last_index(int index, std::vector subpaths) +{ + int counter = -1; + bool inSubpath = false; + for (PathVector::const_iterator path_it = subpaths.begin(); path_it != subpaths.end(); ++path_it) { + if (path_it->empty()) + continue; + Geom::Path::const_iterator curve_it1 = 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(); + } + } + while (curve_it1 != curve_endit) { + counter++; + if(counter == index){ + inSubpath = true; + } + ++curve_it1; + } + if(inSubpath){ + break; + } + } + if(!inSubpath){ + counter = -1; + } + return counter; +} + + double FilletChamferPointArrayParam::len_to_time(int index, double len) { double t = 0; @@ -405,7 +614,7 @@ double FilletChamferPointArrayParam::len_to_time(int index, double len) if (len != 0) { if (last_pwd2[index][0].degreesOfFreedom() != 2) { Piecewise > u; - u.push_cut(0); + u.push_cut(0); u.push(last_pwd2[index], 1); std::vector t_roots = roots(arcLengthSb(u) - std::abs(len)); if (t_roots.size() > 0) { @@ -586,34 +795,34 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) this->knot->tip = g_strdup(tip); this->knot->show(); } - } else if ((state & GDK_MOD1_MASK) || (state & GDK_SHIFT_MASK)) { - Geom::Point offset = Geom::Point(_pparam->_vector.at(_index).x(), - _pparam->_vector.at(_index).y()); + } else if (state & GDK_SHIFT_MASK) { + double xModified = _pparam->_vector.at(_index).x(); + if(xModified < 0 && !_pparam->use_distance){ + xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x()); + } + std::vector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1); + std::pair positions = _pparam->get_positions(_index, subpaths); + D2 A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)]; + if(positions.second != 0){ + A = _pparam->last_pwd2[_index-1]; + } + D2 B = _pparam->last_pwd2[_index]; + bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false; + Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y()); Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( - this->desktop, offset, this, _pparam->unit); + this->desktop, offset, this, _pparam->unit, _pparam->use_distance, aprox); } } -void -FilletChamferPointArrayParamKnotHolderEntity::knot_doubleclicked(guint state) -{ - //todo: fill the double click dialog whith this parameters in the added file - //src/ui/dialog/lpe-fillet-chamfer-properties.cpp(.h) - //My idea for when have enought time is: - //label whith radius in percent - //label whith radius in size -maybe handle units- - //entry whith actual radius -in flexible % mode or fixed -?px- - //2 radio options to switch entry from fixed or flexible, also update the - //entry - //Checkbox or two radios to swith fillet or chamfer - -} - void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset( Geom::Point offset) { - _pparam->_vector.at(_index) = Geom::Point(offset.x(), offset.y()); + double xModified = offset.x(); + if(xModified < 0 && !_pparam->use_distance){ + xModified = _pparam->rad_to_len(_index, offset.x()); + } + _pparam->_vector.at(_index) = Geom::Point(xModified, offset.y()); this->parent_holder->knot_ungrabbed_handler(this->knot, 0); } @@ -644,7 +853,6 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); } - FilletChamferPointArrayParamKnotHolderEntity *e = new FilletChamferPointArrayParamKnotHolderEntity(this, i); e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip), diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 93d6e9f4c..a1fa698ae 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -43,9 +43,15 @@ public: guint32 color); virtual double to_time(int index, double A); virtual double to_len(int index, double A); + virtual double rad_to_len(int index, double rad); + virtual double len_to_rad(int index, double len); virtual double len_to_time(int index, double len); virtual double time_to_len(int index, double time); + virtual std::pair get_positions(int index, std::vector subpaths); + virtual int last_index(int index, std::vector subpaths); + std::vector get_times(int index, std::vector subpaths, bool last); virtual void set_helper_size(int hs); + virtual void set_use_distance(bool use_knot_distance); virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); @@ -79,6 +85,7 @@ private: SPKnotModeType knot_mode; guint32 knot_color; int helper_size; + bool use_distance; const gchar *unit; Geom::PathVector hp; @@ -96,7 +103,6 @@ public: guint state); virtual Geom::Point knot_get() const; virtual void knot_click(guint state); - virtual void knot_doubleclicked(guint state); virtual void knot_set_offset(Geom::Point offset); /*Checks whether the index falls within the size of the parameter's vector*/ -- cgit v1.2.3 From 2cdb481d0d449bed3a914883d0b84a9481a5f6f2 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 14 Sep 2014 13:29:48 -0400 Subject: Small cleanup (bzr r13341.1.205) --- src/live_effects/lpe-attach-path.cpp | 2 +- src/live_effects/lpe-jointype.cpp | 40 ++++++++++++++---------- src/live_effects/lpe-jointype.h | 12 +++++++ src/live_effects/lpe-taperstroke.cpp | 5 +-- src/live_effects/lpe-taperstroke.h | 2 +- src/live_effects/parameter/originalpatharray.cpp | 7 +---- src/live_effects/parameter/originalpatharray.h | 2 +- src/live_effects/parameter/transformedpoint.h | 5 --- 8 files changed, 40 insertions(+), 35 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index 96372892e..2880cbc37 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) Johan Engelen 2012 + * Copyright (C) Theodore Janeczko 2012 * * Released under GNU GPL, read the file 'COPYING' for more information */ diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index b0a6e845b..7c7581d9e 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -1,6 +1,3 @@ -/** \file - * LPE "Join Type" implementation - */ /* Authors: * * Liam P White @@ -10,8 +7,6 @@ * Released under GNU GPL v2, read the file 'COPYING' for more information */ -#include - #include "live_effects/parameter/enum.h" #include "live_effects/pathoutlineprovider.h" @@ -62,13 +57,13 @@ LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) { show_orig_path = true; - registerParameter( dynamic_cast(&linecap_type) ); - registerParameter( dynamic_cast(&line_width) ); - registerParameter( dynamic_cast(&linejoin_type) ); - registerParameter( dynamic_cast(&start_lean) ); - registerParameter( dynamic_cast(&end_lean) ); - registerParameter( dynamic_cast(&miter_limit) ); - registerParameter( dynamic_cast(&attempt_force_join) ); + registerParameter(&linecap_type); + registerParameter(&line_width); + registerParameter(&linejoin_type); + registerParameter(&start_lean); + registerParameter(&end_lean); + registerParameter(&miter_limit); + registerParameter(&attempt_force_join); was_initialized = false; start_lean.param_set_range(-1,1); start_lean.param_set_increments(0.1, 0.1); @@ -169,9 +164,9 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) } } -//NOTE: I originally had all the outliner functions defined in here, but they were actually useful -//enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a -//wrapper around it. +// NOTE: I originally had all the outliner functions defined in here, but they were actually useful +// enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a +// wrapper around it. std::vector LPEJoinType::doEffect_path(std::vector const & path_in) { return Outline::PathVectorOutline(path_in, line_width, static_cast(linecap_type.get_value()), @@ -180,5 +175,16 @@ std::vector LPEJoinType::doEffect_path(std::vector const start_lean/2 ,end_lean/2); } -} //namespace LivePathEffect -} //namespace Inkscape +} // 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:fileencoding=utf-8 : diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h index 7ebce1c7e..d20640b74 100644 --- a/src/live_effects/lpe-jointype.h +++ b/src/live_effects/lpe-jointype.h @@ -5,6 +5,7 @@ * * Released under GNU GPL v2, read the file COPYING for more information */ + #ifndef INKSCAPE_LPE_JOINTYPE_H #define INKSCAPE_LPE_JOINTYPE_H @@ -43,3 +44,14 @@ private: } //namespace Inkscape #endif + +/* + 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:fileencoding=utf-8 : diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 5564a3b2c..db7e47f2b 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -612,9 +612,6 @@ Geom::Point KnotHolderEntityAttachEnd::knot_get() const } } - -/* ######################## */ - } //namespace LivePathEffect } /* namespace Inkscape */ @@ -627,4 +624,4 @@ Geom::Point KnotHolderEntityAttachEnd::knot_get() const fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h index 997209543..4719d1a46 100644 --- a/src/live_effects/lpe-taperstroke.h +++ b/src/live_effects/lpe-taperstroke.h @@ -69,4 +69,4 @@ private: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 514c9e23e..7b0b073ee 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) Johan Engelen 2008 + * Copyright (C) Theodore Janeczko 2012 * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -420,11 +420,6 @@ void OriginalPathArrayParam::linked_modified(SPObject *linked_obj, guint flags, _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); } -//void PathParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *moved_item) -//{ -// linked_transformed_callback(rel_transf, moved_item); -//} - bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue) { if (strvalue) { diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h index 865a3f8e5..1c60da409 100644 --- a/src/live_effects/parameter/originalpatharray.h +++ b/src/live_effects/parameter/originalpatharray.h @@ -4,7 +4,7 @@ /* * Inkscape::LivePathEffectParameters * -* Copyright (C) Johan Engelen 2008 + * Copyright (C) Theodore Janeczko 2012 * * Released under GNU GPL, read the file 'COPYING' for more information */ diff --git a/src/live_effects/parameter/transformedpoint.h b/src/live_effects/parameter/transformedpoint.h index 37af8b98f..c96bedb53 100644 --- a/src/live_effects/parameter/transformedpoint.h +++ b/src/live_effects/parameter/transformedpoint.h @@ -50,7 +50,6 @@ public: virtual void param_transform_multiply(Geom::Affine const &postmul, bool set); void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); - //void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_oncanvas_color(guint32 color); virtual bool providesKnotHolderEntities() const { return true; } @@ -71,11 +70,7 @@ private: SPKnotShapeType vec_knot_shape; SPKnotModeType vec_knot_mode; guint32 vec_knot_color; -// SPKnotShapeType ori_knot_shape; -// SPKnotModeType ori_knot_mode; -// guint32 ori_knot_color; -// friend class VectorParamKnotHolderEntity_Origin; friend class TransformedPointParamKnotHolderEntity_Vector; }; -- cgit v1.2.3 From ea9f5f43ee77d3b0483c583fb1ddbc3e28a77a13 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 14 Sep 2014 13:46:13 -0400 Subject: Warnings cleanup; formatting (bzr r13341.1.206) --- src/live_effects/effect.cpp | 4 +- src/live_effects/lpe-attach-path.cpp | 18 ++-- src/live_effects/lpe-jointype.cpp | 108 +++++++++++------------ src/live_effects/lpe-jointype.h | 40 ++++----- src/live_effects/lpe-taperstroke.cpp | 10 +-- src/live_effects/parameter/originalpatharray.cpp | 9 +- src/live_effects/parameter/originalpatharray.h | 3 +- 7 files changed, 93 insertions(+), 99 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 895408707..3e3f8540a 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -407,11 +407,11 @@ Effect::doBeforeEffect (SPLPEItem const*/*lpeitem*/) //Do nothing for simple effects } -void Effect::doAfterEffect (SPLPEItem const* lpeitem) +void Effect::doAfterEffect (SPLPEItem const* /*lpeitem*/) { } -void Effect::doOnRemove (SPLPEItem const* lpeitem) +void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) { } diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index 2880cbc37..768c66ee2 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -35,15 +35,15 @@ LPEAttachPath::LPEAttachPath(LivePathEffectObject *lpeobject) : end_path_curve_start(_("End path curve start:"), _("Starting curve"), "endcurvestart", &wr, this, Geom::Point(20,0)/*, true*/), end_path_curve_end(_("End path curve end:"), _("Ending curve"), "endcurveend", &wr, this, Geom::Point(20,0)/*, true*/) { - registerParameter( dynamic_cast(&start_path) ); - registerParameter( dynamic_cast(&start_path_position) ); - registerParameter( dynamic_cast(&start_path_curve_start) ); - registerParameter( dynamic_cast(&start_path_curve_end) ); + registerParameter(&start_path); + registerParameter(&start_path_position); + registerParameter(&start_path_curve_start); + registerParameter(&start_path_curve_end); - registerParameter( dynamic_cast(&end_path) ); - registerParameter( dynamic_cast(&end_path_position) ); - registerParameter( dynamic_cast(&end_path_curve_start) ); - registerParameter( dynamic_cast(&end_path_curve_end) ); + registerParameter(&end_path); + registerParameter(&end_path_position); + registerParameter(&end_path_curve_start); + registerParameter(&end_path_curve_end); //perceived_path = true; show_orig_path = true; @@ -56,7 +56,7 @@ LPEAttachPath::~LPEAttachPath() } -void LPEAttachPath::resetDefaults(SPItem const * item) +void LPEAttachPath::resetDefaults(SPItem const * /*item*/) { curve_start_previous_origin = start_path_curve_end.getOrigin(); curve_end_previous_origin = end_path_curve_end.getOrigin(); diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 7c7581d9e..bf2526986 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -1,11 +1,11 @@ - /* Authors: - * - * Liam P White - * - * Copyright (C) 2014 Authors - * - * Released under GNU GPL v2, read the file 'COPYING' for more information - */ +/* Authors: +* +* Liam P White +* +* Copyright (C) 2014 Authors +* +* Released under GNU GPL v2, read the file 'COPYING' for more information +*/ #include "live_effects/parameter/enum.h" #include "live_effects/pathoutlineprovider.h" @@ -28,49 +28,49 @@ namespace Inkscape { namespace LivePathEffect { static const Util::EnumData JoinTypeData[] = { - {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, + {LINEJOIN_STRAIGHT, N_("Beveled"), "bevel"}, {LINEJOIN_ROUND, N_("Rounded"), "round"}, {LINEJOIN_POINTY, N_("Miter"), "miter"}, - {LINEJOIN_REFLECTED, N_("Reflected"), "extrapolated"}, + {LINEJOIN_REFLECTED, N_("Reflected"), "extrapolated"}, {LINEJOIN_EXTRAPOLATED, N_("Extrapolated arc"), "extrp_arc"} }; static const Util::EnumData CapTypeData[] = { - {BUTT_STRAIGHT, N_("Butt"), "butt"}, - {BUTT_ROUND, N_("Rounded"), "round"}, - {BUTT_SQUARE, N_("Square"), "square"}, - {BUTT_POINTY, N_("Peak"), "peak"}, - {BUTT_LEANED, N_("Leaned"), "leaned"} + {BUTT_STRAIGHT, N_("Butt"), "butt"}, + {BUTT_ROUND, N_("Rounded"), "round"}, + {BUTT_SQUARE, N_("Square"), "square"}, + {BUTT_POINTY, N_("Peak"), "peak"}, + {BUTT_LEANED, N_("Leaned"), "leaned"} }; static const Util::EnumDataConverter CapTypeConverter(CapTypeData, sizeof(CapTypeData)/sizeof(*CapTypeData)); static const Util::EnumDataConverter JoinTypeConverter(JoinTypeData, sizeof(JoinTypeData)/sizeof(*JoinTypeData)); LPEJoinType::LPEJoinType(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.), - linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), - linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), - start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.), - end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.), - miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), - attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) + Effect(lpeobject), + line_width(_("Line width"), _("Thickness of the stroke"), "line_width", &wr, this, 1.), + linecap_type(_("Line cap"), _("The end shape of the stroke"), "linecap_type", CapTypeConverter, &wr, this, butt_straight), + linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", JoinTypeConverter, &wr, this, LINEJOIN_EXTRAPOLATED), + start_lean(_("Start path lean"), _("Start path lean"), "start_lean", &wr, this, 0.), + end_lean(_("End path lean"), _("End path lean"), "end_lean", &wr, this, 0.), + miter_limit(_("Miter limit:"), _("Maximum length of the miter join (in units of stroke width)"), "miter_limit", &wr, this, 100.), + attempt_force_join(_("Force miter"), _("Overrides the miter limit and forces a join."), "attempt_force_join", &wr, this, true) { - show_orig_path = true; - registerParameter(&linecap_type); - registerParameter(&line_width); - registerParameter(&linejoin_type); - registerParameter(&start_lean); - registerParameter(&end_lean); - registerParameter(&miter_limit); - registerParameter(&attempt_force_join); - was_initialized = false; - start_lean.param_set_range(-1,1); - start_lean.param_set_increments(0.1, 0.1); - start_lean.param_set_digits(4); - end_lean.param_set_range(-1,1); - end_lean.param_set_increments(0.1, 0.1); - end_lean.param_set_digits(4); + show_orig_path = true; + registerParameter(&linecap_type); + registerParameter(&line_width); + registerParameter(&linejoin_type); + registerParameter(&start_lean); + registerParameter(&end_lean); + registerParameter(&miter_limit); + registerParameter(&attempt_force_join); + was_initialized = false; + start_lean.param_set_range(-1,1); + start_lean.param_set_increments(0.1, 0.1); + start_lean.param_set_digits(4); + end_lean.param_set_range(-1,1); + end_lean.param_set_increments(0.1, 0.1); + end_lean.param_set_digits(4); } LPEJoinType::~LPEJoinType() @@ -82,10 +82,10 @@ LPEJoinType::~LPEJoinType() void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) { - if (SP_IS_SHAPE(lpeitem)) { + if (SP_IS_SHAPE(lpeitem)) { SPLPEItem* item = const_cast(lpeitem); double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.; - + SPCSSAttr *css = sp_repr_css_attr_new (); if (true) { if (lpeitem->style->stroke.isPaintserver()) { @@ -107,16 +107,16 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) } else { sp_repr_css_unset_property (css, "fill"); } - + sp_repr_css_set_property(css, "stroke", "none"); - + sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); - if (!was_initialized) - { - was_initialized = true; - line_width.param_set_value(width); - } + if (!was_initialized) + { + was_initialized = true; + line_width.param_set_value(width); + } } else { g_warning("LPE Join Type can only be applied to paths (not groups)."); } @@ -126,8 +126,8 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) { - - if (SP_IS_SHAPE(lpeitem)) { + + if (SP_IS_SHAPE(lpeitem)) { SPLPEItem *item = const_cast(lpeitem); SPCSSAttr *css = sp_repr_css_attr_new (); @@ -152,7 +152,7 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) sp_repr_css_unset_property (css, "stroke"); } - Inkscape::CSSOStringStream os; + Inkscape::CSSOStringStream os; os << fabs(line_width); sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); @@ -165,13 +165,13 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) } // NOTE: I originally had all the outliner functions defined in here, but they were actually useful -// enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a +// enough for other LPEs so I moved them all into pathoutlineprovider.cpp. The code here is just a // wrapper around it. std::vector LPEJoinType::doEffect_path(std::vector const & path_in) -{ - return Outline::PathVectorOutline(path_in, line_width, static_cast(linecap_type.get_value()), +{ + return Outline::PathVectorOutline(path_in, line_width, static_cast(linecap_type.get_value()), static_cast(linejoin_type.get_value()), - (attempt_force_join ? std::numeric_limits::max() : miter_limit), + (attempt_force_join ? std::numeric_limits::max() : miter_limit), start_lean/2 ,end_lean/2); } diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h index d20640b74..73705666d 100644 --- a/src/live_effects/lpe-jointype.h +++ b/src/live_effects/lpe-jointype.h @@ -5,10 +5,10 @@ * * Released under GNU GPL v2, read the file COPYING for more information */ - + #ifndef INKSCAPE_LPE_JOINTYPE_H #define INKSCAPE_LPE_JOINTYPE_H - + #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/point.h" @@ -16,28 +16,28 @@ namespace Inkscape { namespace LivePathEffect { - + class LPEJoinType : public Effect { public: - LPEJoinType(LivePathEffectObject *lpeobject); - virtual ~LPEJoinType(); - - virtual void doOnApply(SPLPEItem const* lpeitem); - virtual void doOnRemove(SPLPEItem const* lpeitem); - virtual std::vector doEffect_path (std::vector const & path_in); + LPEJoinType(LivePathEffectObject *lpeobject); + virtual ~LPEJoinType(); + + virtual void doOnApply(SPLPEItem const* lpeitem); + virtual void doOnRemove(SPLPEItem const* lpeitem); + virtual std::vector doEffect_path (std::vector const & path_in); private: - LPEJoinType(const LPEJoinType&); - LPEJoinType& operator=(const LPEJoinType&); - - ScalarParam line_width; - EnumParam linecap_type; - EnumParam linejoin_type; - ScalarParam start_lean; - ScalarParam end_lean; - ScalarParam miter_limit; - BoolParam attempt_force_join; - bool was_initialized; + LPEJoinType(const LPEJoinType&); + LPEJoinType& operator=(const LPEJoinType&); + + ScalarParam line_width; + EnumParam linecap_type; + EnumParam linejoin_type; + ScalarParam start_lean; + ScalarParam end_lean; + ScalarParam miter_limit; + BoolParam attempt_force_join; + bool was_initialized; }; } //namespace LivePathEffect diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index db7e47f2b..9c43b6671 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -211,7 +211,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) //if so, reset the end offset, but still allow the start offset. if ( attach_start >= (size - attach_end) ) { attach_end.param_set_value( size - attach_start ); - metInMiddle = true; + metInMiddle = true; } } @@ -525,14 +525,14 @@ void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *de { { KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); knotholder->add(e); } { KnotHolderEntity *e = new TpS::KnotHolderEntityAttachEnd(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); knotholder->add(e); } } diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 7b0b073ee..7706dbdf8 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -344,7 +344,7 @@ void OriginalPathArrayParam::remove_link(PathAndDirection* to) } } -void OriginalPathArrayParam::linked_delete(SPObject */*deleted*/, PathAndDirection* to) +void OriginalPathArrayParam::linked_delete(SPObject */*deleted*/, PathAndDirection* /*to*/) { //remove_link(to); @@ -383,12 +383,7 @@ void OriginalPathArrayParam::linked_changed(SPObject */*old_obj*/, SPObject *new } } -void OriginalPathArrayParam::linked_transformed(Geom::Affine const *mp, SPItem* original, PathAndDirection* to) -{ - -} - -void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint flags, PathAndDirection* to) +void OriginalPathArrayParam::setPathVector(SPObject *linked_obj, guint /*flags*/, PathAndDirection* to) { if (!to) { return; diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h index 1c60da409..6c792613f 100644 --- a/src/live_effects/parameter/originalpatharray.h +++ b/src/live_effects/parameter/originalpatharray.h @@ -40,7 +40,6 @@ public: } gchar *href; URIReference ref; - //SPItem *obj; std::vector _pathvector; bool reversed; @@ -83,7 +82,7 @@ protected: void linked_changed(SPObject *old_obj, SPObject *new_obj, PathAndDirection* to); void linked_modified(SPObject *linked_obj, guint flags, PathAndDirection* to); - void linked_transformed(Geom::Affine const *mp, SPItem *original, PathAndDirection* to); + void linked_transformed(Geom::Affine const *, SPItem *, PathAndDirection*) {} void linked_delete(SPObject *deleted, PathAndDirection* to); ModelColumns *_model; -- cgit v1.2.3 From 92089c17de58981ed91537402a93e17ce2d2ec26 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 14 Sep 2014 13:55:34 -0400 Subject: More formatting (bzr r13341.1.207) --- src/live_effects/pathoutlineprovider.cpp | 48 +++++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/pathoutlineprovider.cpp b/src/live_effects/pathoutlineprovider.cpp index 482f1f5e0..21a0fb809 100644 --- a/src/live_effects/pathoutlineprovider.cpp +++ b/src/live_effects/pathoutlineprovider.cpp @@ -1,7 +1,11 @@ -#include //g_critical +/* Author: + * Liam P. White + * + * Copyright (C) 2014 Author + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ -#include "pathoutlineprovider.h" -#include "livarot/path-description.h" #include <2geom/angle.h> #include <2geom/path.h> #include <2geom/circle.h> @@ -9,8 +13,12 @@ #include <2geom/shape.h> #include <2geom/transforms.h> #include <2geom/path-sink.h> +#include + +#include "pathoutlineprovider.h" +#include "livarot/path-description.h" #include "helper/geom-nodetype.h" -#include +#include "svg/svg.h" namespace Geom { /** @@ -22,8 +30,7 @@ namespace Geom { * @return 1 if one circle is contained in the other * @return 2 if intersections are found (they are written to p0 and p1) */ -static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, - Point & p0, Point & p1) +static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, Point & p0, Point & p1) { Point X0 = circle0.center(); double r0 = circle0.ray(); @@ -163,7 +170,7 @@ bool outside_angle (const Geom::Curve& cbc1, const Geom::Curve& cbc2) Geom::Point end_point; if (cross_point != cbc2.initialPoint()) { - g_warning("Non-contiguous path in Outline::outside_angle()"); + printf("WARNING: Non-contiguous path in Outline::outside_angle()"); return false; } @@ -210,7 +217,8 @@ typedef Geom::BezierCurveN<1u> BezierLine; * @param path_builder Contains the incoming segment; result is appended to this * @param outgoing The outgoing segment */ -void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing) { +void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing) +{ Geom::Curve const& incoming = path_builder.back(); // Using Geom::crossings to find intersections between two curves @@ -243,7 +251,8 @@ void joinInside(Geom::Path& path_builder, Geom::Curve const& outgoing) { * @param miter_limit When mitering, don't exceed this length * @param line_width The thickness of the line. */ -void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { +void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) +{ using namespace Geom; Curve const& incoming = path_builder.back(); Point tang1 = unitTangentAt(Geom::reverse(incoming.toSBasis()), 0.); @@ -269,7 +278,8 @@ void miter_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double * @param miter_limit When mitering, don't exceed this length * @param line_width The thickness of the line. Used for miter fallback. */ -void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) { +void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, double miter_limit, double line_width) +{ Geom::Curve const& incoming = path_builder.back(); Geom::Point endPt = outgoing.initialPoint(); @@ -318,7 +328,7 @@ void extrapolate_curves(Geom::Path& path_builder, Geom::Curve const& outgoing, d } } catch (std::exception const & ex) { - g_warning("Error extrapolating line join: %s\n", ex.what()); + printf("WARNING: Error extrapolating line join: %s\n", ex.what()); path_builder.appendNew(endPt); } } else { @@ -378,7 +388,8 @@ typedef void JoinFunc(Geom::Path& /*path_builder*/, Geom::Curve const& /*outgoin /** * Helper function for repeated logic in outlineHalf. */ -static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, bool outside, double width, double miter, JoinFunc func) { +static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, bool outside, double width, double miter, JoinFunc func) +{ Geom::Curve * cbc2 = path_vec->front()[0].duplicate(); if (outside) { @@ -411,7 +422,8 @@ static void outlineHelper(Geom::Path& path_builder, Geom::PathVector* path_vec, * @param func Join function to apply at each join. */ -Geom::Path outlineHalf(const Geom::Path& path_in, double line_width, double miter_limit, JoinFunc func) { +Geom::Path outlineHalf(const Geom::Path& path_in, double line_width, double miter_limit, JoinFunc func) +{ // NOTE: it is important to notice the distinction between a Geom::Path and a livarot ::Path here! // if you do not see "Geom::" there is a different function set! @@ -692,6 +704,8 @@ Geom::PathVector outlinePath(const Geom::PathVector& path_in, double line_width, return path_out; } +#define miter_lim fabs(line_width * miter_limit) + Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line_width, ButtTypeMod linecap_type, LineJoinType linejoin_type, double miter_limit, double start_lean, double end_lean) { std::vector path_out = std::vector(); @@ -704,9 +718,7 @@ Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line p.LoadPath(path_in[i], Geom::Affine(), false, ( (i==0) ? false : true)); } -#define miter_lim fabs(line_width * miter_limit) - - //magic! + // magic! ButtType original_butt; switch (linecap_type) { case BUTT_STRAIGHT: @@ -746,15 +758,12 @@ Geom::PathVector PathVectorOutline(Geom::PathVector const & path_in, double line path_out = outlinePath(path_in, line_width, LINEJOIN_STRAIGHT, linecap_type, miter_lim, true, start_lean, end_lean); } -#undef miter_lim return path_out; } Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, LineJoinType linejoin_type, double miter_limit) { -#define miter_lim fabs(line_width * miter_limit) - Geom::Path path_out; if (linejoin_type <= LINEJOIN_POINTY || path_in.size() <= 1) { @@ -777,7 +786,6 @@ Geom::Path PathOutsideOutline(Geom::Path const & path_in, double line_width, Lin path_out = outlineHalf(path_in, line_width, miter_lim, extrapolate_curves); return path_out; } -#undef miter_lim return path_out; } -- cgit v1.2.3 From d4e5309ab79434f518ab55fe6b47ff185ca80e62 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 15 Sep 2014 18:50:10 +0200 Subject: Roughen LPE: cleanup, improvements in code -loop part thanks Nathan-, credits and license fixed (bzr r13341.1.208) --- src/live_effects/lpe-roughen.cpp | 595 +++++++++++++++++---------------------- src/live_effects/lpe-roughen.h | 64 +++-- 2 files changed, 300 insertions(+), 359 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 5f6acd6f4..b9d575e06 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -1,10 +1,21 @@ -/* +/** + * @file + * Roughen LPE implementation. Creates roughen paths. + */ +/* Authors: + * Jabier Arraiza Cenoz + * + * Thanks to all people involved specialy to Josh Andler for the idea and to the + * original extensions authors. + * + * Copyright (C) 2014 Authors + * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "live_effects/lpe-roughen.h" -#include +#include +#include "live_effects/lpe-roughen.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" #include "helper/geom.h" @@ -15,375 +26,299 @@ namespace Inkscape { namespace LivePathEffect { static const Util::EnumData DivisionMethodData[DM_END] = { - { DM_SEGMENTS, N_("By number of segments"), "segments" }, - { DM_SIZE, N_("By max. segment size"), "size" } + { DM_SEGMENTS, N_("By number of segments"), "segments" }, + { DM_SIZE, N_("By max. segment size"), "size" } }; static const Util::EnumDataConverter - DMConverter(DivisionMethodData, DM_END); +DMConverter(DivisionMethodData, DM_END); LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: - unit(_("Unit:"), _("Unit"), "unit", &wr, this), - method(_("Method:"), _("Division method"), "method", DMConverter, &wr, + unit(_("Unit"), _("Unit"), "unit", &wr, this), + method(_("Method"), _("Division method"), "method", DMConverter, &wr, this, DM_SEGMENTS), - maxSegmentSize(_("Max. segment size:"), _("Max. segment size"), + maxSegmentSize(_("Max. segment size"), _("Max. segment size"), "maxSegmentSize", &wr, this, 10.), - segments(_("Number of segments:"), _("Number of segments"), "segments", + segments(_("Number of segments"), _("Number of segments"), "segments", &wr, this, 2), - displaceX(_("Max. displacement in X:"), _("Max. displacement in X"), + displaceX(_("Max. displacement in X"), _("Max. displacement in X"), "displaceX", &wr, this, 10.), - displaceY(_("Max. displacement in Y:"), _("Max. displacement in Y"), + displaceY(_("Max. displacement in Y"), _("Max. displacement in Y"), "displaceY", &wr, this, 10.), shiftNodes(_("Shift nodes"), _("Shift nodes"), "shiftNodes", &wr, this, true), shiftNodeHandles(_("Shift node handles"), _("Shift node handles"), - "shiftNodeHandles", &wr, this, true) { - registerParameter(dynamic_cast(&unit)); - registerParameter(dynamic_cast(&method)); - registerParameter(dynamic_cast(&maxSegmentSize)); - registerParameter(dynamic_cast(&segments)); - registerParameter(dynamic_cast(&displaceX)); - registerParameter(dynamic_cast(&displaceY)); - registerParameter(dynamic_cast(&shiftNodes)); - registerParameter(dynamic_cast(&shiftNodeHandles)); - displaceX.param_set_range(0., Geom::infinity()); - displaceY.param_set_range(0., Geom::infinity()); - maxSegmentSize.param_set_range(0., Geom::infinity()); - maxSegmentSize.param_set_increments(1, 1); - maxSegmentSize.param_set_digits(1); - segments.param_set_range(1, Geom::infinity()); - segments.param_set_increments(1, 1); - segments.param_set_digits(0); + "shiftNodeHandles", &wr, this, true) +{ + registerParameter(&unit); + registerParameter(&method); + registerParameter(&maxSegmentSize); + registerParameter(&segments); + registerParameter(&displaceX); + registerParameter(&displaceY); + registerParameter(&shiftNodes); + registerParameter(&shiftNodeHandles); + displaceX.param_set_range(0., Geom::infinity()); + displaceY.param_set_range(0., Geom::infinity()); + maxSegmentSize.param_set_range(0., Geom::infinity()); + maxSegmentSize.param_set_increments(1, 1); + maxSegmentSize.param_set_digits(1); + segments.param_set_range(1, Geom::infinity()); + segments.param_set_increments(1, 1); + segments.param_set_digits(0); } LPERoughen::~LPERoughen() {} -void LPERoughen::doBeforeEffect(SPLPEItem const */*lpeitem*/) { - displaceX.resetRandomizer(); - displaceY.resetRandomizer(); - srand(1); +void LPERoughen::doBeforeEffect(SPLPEItem const */*lpeitem*/) +{ + displaceX.resetRandomizer(); + displaceY.resetRandomizer(); + srand(1); } -Gtk::Widget *LPERoughen::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(2); - std::vector::iterator it = param_vector.begin(); - 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 == "unit") { - Gtk::Label *unitLabel = Gtk::manage(new Gtk::Label( - Glib::ustring(_("Roughen unit")), Gtk::ALIGN_START)); - unitLabel->set_use_markup(true); - vbox->pack_start(*unitLabel, false, false, 2); -#if WITH_GTKMM_3_0 - vbox->pack_start(*Gtk::manage(new Gtk::Separator()), -#else - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), -#endif - Gtk::PACK_EXPAND_WIDGET); - } - if (param->param_key == "method") { - Gtk::Label *methodLabel = Gtk::manage(new Gtk::Label( - Glib::ustring(_("Add nodes Subdivide each segment")), - Gtk::ALIGN_START)); - methodLabel->set_use_markup(true); - vbox->pack_start(*methodLabel, false, false, 2); -#if WITH_GTKMM_3_0 - vbox->pack_start(*Gtk::manage(new Gtk::Separator()), -#else - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), -#endif - Gtk::PACK_EXPAND_WIDGET); - } - if (param->param_key == "displaceX") { - Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( - Glib::ustring(_("Jitter nodes Move nodes/handles")), - Gtk::ALIGN_START)); - displaceXLabel->set_use_markup(true); - vbox->pack_start(*displaceXLabel, false, false, 2); -#if WITH_GTKMM_3_0 - vbox->pack_start(*Gtk::manage(new Gtk::Separator()), -#else - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), -#endif - Gtk::PACK_EXPAND_WIDGET); - } - 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); +Gtk::Widget *LPERoughen::newWidget() +{ + Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); + vbox->set_border_width(5); + vbox->set_homogeneous(false); + vbox->set_spacing(2); + std::vector::iterator it = param_vector.begin(); + 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 == "unit") { + Gtk::Label *unitLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Roughen unit")), Gtk::ALIGN_START)); + unitLabel->set_use_markup(true); + vbox->pack_start(*unitLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } + if (param->param_key == "method") { + Gtk::Label *methodLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Add nodes Subdivide each segment")), + Gtk::ALIGN_START)); + methodLabel->set_use_markup(true); + vbox->pack_start(*methodLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } + if (param->param_key == "displaceX") { + Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Jitter nodes Move nodes/handles")), + Gtk::ALIGN_START)); + displaceXLabel->set_use_markup(true); + vbox->pack_start(*displaceXLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } + 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; - } - return dynamic_cast(vbox); + ++it; + } + return dynamic_cast(vbox); } -double LPERoughen::sign(double randNumber) { - if (rand() % 100 < 49) { - randNumber *= -1.; - } - return randNumber; +double LPERoughen::sign(double randNumber) +{ + if (rand() % 100 < 49) { + randNumber *= -1.; + } + return randNumber; } -Geom::Point LPERoughen::randomize() { - double displaceXParsed = Inkscape::Util::Quantity::convert( - displaceX, unit.get_abbreviation(), "px"); - double displaceYParsed = Inkscape::Util::Quantity::convert( - displaceY, unit.get_abbreviation(), "px"); - //maybe is better divide this point by 2... - Geom::Point output = - Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); - return output; -} +Geom::Point LPERoughen::randomize() +{ + double displaceXParsed = Inkscape::Util::Quantity::convert( + displaceX, unit.get_abbreviation(), "px"); + double displaceYParsed = Inkscape::Util::Quantity::convert( + displaceY, unit.get_abbreviation(), "px"); -void LPERoughen::doEffect(SPCurve *curve) { - Geom::PathVector const original_pathv = - pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); - curve->reset(); + Geom::Point output = Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); + return output; +} - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo - 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 +void LPERoughen::doEffect(SPCurve *curve) +{ + Geom::PathVector const original_pathv = + pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); + curve->reset(); + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) { + if (path_it->empty()) + continue; - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores - SPCurve *nCurve = new SPCurve(); - 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(); - } - } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline - Geom::Point initialMove(0, 0); - if (shiftNodes) { - initialMove = randomize(); - } - Geom::Point initialPoint = curve_it1->initialPoint() + initialMove; - nCurve->moveto(initialPoint); - Geom::Point A0(0, 0); - Geom::Point A1(0, 0); - Geom::Point A2(0, 0); - Geom::Point A3(0, 0); - while (curve_it2 != curve_endit) { - //aumentamos los valores para el siguiente paso en el bucle - //Recorremos todos los segmentos menos el último - Geom::CubicBezier const *cubic = NULL; - A0 = curve_it1->initialPoint(); - A1 = curve_it1->initialPoint(); - A2 = curve_it1->finalPoint(); - A3 = curve_it1->finalPoint(); - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - A1 = (*cubic)[1]; - if (shiftNodes) { - A1 = (*cubic)[1] + initialMove; + 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(); + SPCurve *nCurve = new SPCurve(); + 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(); + } } - A2 = (*cubic)[2]; - nCurve->curveto(A1, A2, A3); - } else { - nCurve->lineto(A3); - } - double length = Inkscape::Util::Quantity::convert( - curve_it1->length(0.001), "px", unit.get_abbreviation()); - unsigned int splits = 0; - if (method == DM_SEGMENTS) { - splits = segments; - } else { - splits = ceil(length / maxSegmentSize); - } - for (unsigned int t = splits; t >= 1; t--) { - if (t == 1 && splits != 1) { - continue; + Geom::Point initialMove(0, 0); + if (shiftNodes) { + initialMove = randomize(); } - const SPCurve *tmp; - if (splits == 1) { - tmp = jitter(nCurve->last_segment()); - } else { - tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); + Geom::Point initialPoint = curve_it1->initialPoint() + initialMove; + nCurve->moveto(initialPoint); + Geom::Point A0(0, 0); + Geom::Point A1(0, 0); + Geom::Point A2(0, 0); + Geom::Point A3(0, 0); + while (curve_it1 != curve_endit) { + Geom::CubicBezier const *cubic = NULL; + A0 = curve_it1->initialPoint(); + A1 = curve_it1->initialPoint(); + A2 = curve_it1->finalPoint(); + A3 = curve_it1->finalPoint(); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + A1 = (*cubic)[1]; + if (shiftNodes) { + A1 = (*cubic)[1] + initialMove; + } + A2 = (*cubic)[2]; + nCurve->curveto(A1, A2, A3); + } else { + nCurve->lineto(A3); + } + double length = Inkscape::Util::Quantity::convert( + curve_it1->length(0.001), "px", unit.get_abbreviation()); + std::size_t splits = 0; + if (method == DM_SEGMENTS) { + splits = segments; + } else { + splits = ceil(length / maxSegmentSize); + } + for (unsigned int t = splits; t >= 1; t--) { + if (t == 1 && splits != 1) { + continue; + } + const SPCurve *tmp; + if (splits == 1) { + tmp = jitter(nCurve->last_segment()); + } else { + tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); + } + if (nCurve->get_segment_count() > 1) { + nCurve->backspace(); + nCurve->append_continuous(tmp, 0.001); + } else { + nCurve = tmp->copy(); + } + delete tmp; + } + ++curve_it1; + if(curve_it2 != curve_endit) { + ++curve_it2; + } } - if (nCurve->get_segment_count() > 1) { - nCurve->backspace(); - nCurve->append_continuous(tmp, 0.001); - } else { - nCurve = tmp->copy(); + if (path_it->closed()) { + nCurve->closepath_current(); } - delete tmp; - } - ++curve_it1; - ++curve_it2; + curve->append(nCurve, false); + nCurve->reset(); + delete nCurve; } - Geom::CubicBezier const *cubic = NULL; - A0 = curve_it1->initialPoint(); - A1 = curve_it1->initialPoint(); - A2 = curve_it1->finalPoint(); - A3 = curve_it1->finalPoint(); - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - A1 = (*cubic)[1]; - A2 = (*cubic)[2]; - if (path_it->closed()) { - A2 = A2 + initialMove; - A3 = initialPoint; - } - nCurve->curveto(A1, A2, A3); - } else { - if (path_it->closed()) { - A3 = initialPoint; - } - nCurve->lineto(A3); +} + +SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) +{ + SPCurve *out = new SPCurve(); + Geom::CubicBezier const *cubic = dynamic_cast(&*A); + Geom::Point A1(0, 0); + Geom::Point A2(0, 0); + Geom::Point A3(0, 0); + Geom::Point B1(0, 0); + Geom::Point B2(0, 0); + Geom::Point B3(0, 0); + if (shiftNodes) { + A3 = randomize(); + B3 = randomize(); } - double length = Inkscape::Util::Quantity::convert( - curve_it1->length(0.001), "px", unit.get_abbreviation()); - unsigned int splits = 0; - if (method == DM_SEGMENTS) { - splits = segments; + if (shiftNodeHandles) { + A1 = randomize(); + A2 = randomize(); + B1 = randomize(); + B2 = randomize(); } else { - splits = ceil(length / maxSegmentSize); + A2 = A3; + B1 = A3; + B2 = B3; } - for (unsigned int t = splits; t >= 1; t--) { - if (t == 1 && splits != 1) { - continue; - } - const SPCurve *tmp; - if (splits == 1) { - tmp = jitter(nCurve->last_segment()); - } else { - tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); - } - if (nCurve->get_segment_count() > 1) { - nCurve->backspace(); - nCurve->append_continuous(tmp, 0.001); - } else { - nCurve = tmp->copy(); - } - delete tmp; - } - //y cerramos la curva - if (path_it->closed()) { - nCurve->closepath_current(); + if (cubic) { + std::pair div = cubic->subdivide(t); + std::vector seg1 = div.first.points(), + seg2 = div.second.points(); + out->moveto(seg1[0]); + out->curveto(seg1[1] + A1, seg1[2] + A2, seg1[3] + A3); + out->curveto(seg2[1] + B1, seg2[2], seg2[3]); + } else if (shiftNodeHandles) { + out->moveto(A->initialPoint()); + out->curveto(A->pointAt(t / 3) + A1, A->pointAt((t / 3) * 2) + A2, + A->pointAt(t) + A3); + out->curveto(A->pointAt(t + (t / 3)) + B1, A->pointAt(t + ((t / 3) * 2)), + A->finalPoint()); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->pointAt(t) + A3); + out->lineto(A->finalPoint()); } - curve->append(nCurve, false); - nCurve->reset(); - delete nCurve; - } -} - -SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) { - SPCurve *out = new SPCurve(); - Geom::CubicBezier const *cubic = dynamic_cast(&*A); - Geom::Point A1(0, 0); - Geom::Point A2(0, 0); - Geom::Point A3(0, 0); - Geom::Point B1(0, 0); - Geom::Point B2(0, 0); - Geom::Point B3(0, 0); - if (shiftNodes) { - A3 = randomize(); - B3 = randomize(); - } - if (shiftNodeHandles) { - A1 = randomize(); - A2 = randomize(); - B1 = randomize(); - B2 = randomize(); - } else { - A2 = A3; - B1 = A3; - B2 = B3; - } - if (cubic) { - std::pair div = cubic->subdivide(t); - std::vector seg1 = div.first.points(), - seg2 = div.second.points(); - out->moveto(seg1[0]); - out->curveto(seg1[1] + A1, seg1[2] + A2, seg1[3] + A3); - out->curveto(seg2[1] + B1, seg2[2], seg2[3]); - } else if (shiftNodeHandles) { - out->moveto(A->initialPoint()); - out->curveto(A->pointAt(t / 3) + A1, A->pointAt((t / 3) * 2) + A2, - A->pointAt(t) + A3); - out->curveto(A->pointAt(t + (t / 3)) + B1, A->pointAt(t + ((t / 3) * 2)), - A->finalPoint()); - } else { - out->moveto(A->initialPoint()); - out->lineto(A->pointAt(t) + A3); - out->lineto(A->finalPoint()); - } - return out; + return out; } -SPCurve *LPERoughen::jitter(const Geom::Curve *A) { - SPCurve *out = new SPCurve(); - Geom::CubicBezier const *cubic = dynamic_cast(&*A); - Geom::Point A1(0, 0); - Geom::Point A2(0, 0); - Geom::Point A3(0, 0); - if (shiftNodes) { - A3 = randomize(); - } - if (shiftNodeHandles) { - A1 = randomize(); - A2 = randomize(); - } else { - A2 = A3; - } - if (cubic) { - out->moveto((*cubic)[0]); - out->curveto((*cubic)[1] + A1, (*cubic)[2] + A2, (*cubic)[3] + A3); - } else if (shiftNodeHandles) { - out->moveto(A->initialPoint()); - out->curveto(A->pointAt(0.3333) + A1, A->pointAt(0.6666) + A2, - A->finalPoint() + A3); - } else { - out->moveto(A->initialPoint()); - out->lineto(A->finalPoint() + A3); - } - return out; +SPCurve *LPERoughen::jitter(const Geom::Curve *A) +{ + SPCurve *out = new SPCurve(); + Geom::CubicBezier const *cubic = dynamic_cast(&*A); + Geom::Point A1(0, 0); + Geom::Point A2(0, 0); + Geom::Point A3(0, 0); + if (shiftNodes) { + A3 = randomize(); + } + if (shiftNodeHandles) { + A1 = randomize(); + A2 = randomize(); + } else { + A2 = A3; + } + if (cubic) { + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1] + A1, (*cubic)[2] + A2, (*cubic)[3] + A3); + } else if (shiftNodeHandles) { + out->moveto(A->initialPoint()); + out->curveto(A->pointAt(0.3333) + A1, A->pointAt(0.6666) + A2, + A->finalPoint() + A3); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->finalPoint() + A3); + } + return out; } -Geom::Point LPERoughen::tpoint(Geom::Point A, Geom::Point B, double t) { - using Geom::X; - using Geom::Y; - return Geom::Point(A[X] + t * (B[X] - A[X]), A[Y] + t * (B[Y] - A[Y])); +Geom::Point LPERoughen::tpoint(Geom::Point A, Geom::Point B, double t) +{ + using Geom::X; + using Geom::Y; + return Geom::Point(A[X] + t * (B[X] - A[X]), A[Y] + t * (B[Y] - A[Y])); } }; //namespace LivePathEffect diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index cc7784dc0..7e99b47bf 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -1,11 +1,17 @@ -#ifndef INKSCAPE_LPE_ROUGHEN_H -#define INKSCAPE_LPE_ROUGHEN_H - -/* - * Inkscape::LPERoughen +/** @file + * @brief Roughen LPE effect, see lpe-roughen.cpp. + */ +/* Authors: + * Jabier Arraiza Cenoz + * + * Copyright (C) 2014 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ + +#ifndef INKSCAPE_LPE_ROUGHEN_H +#define INKSCAPE_LPE_ROUGHEN_H + #include "live_effects/parameter/enum.h" #include "live_effects/effect.h" #include "live_effects/parameter/parameter.h" @@ -18,37 +24,37 @@ namespace Inkscape { namespace LivePathEffect { enum DivisionMethod { - DM_SEGMENTS, - DM_SIZE, - DM_END + DM_SEGMENTS, + DM_SIZE, + DM_END }; class LPERoughen : public Effect { public: - LPERoughen(LivePathEffectObject *lpeobject); - virtual ~LPERoughen(); - - virtual void doEffect(SPCurve *curve); - virtual double sign(double randNumber); - virtual Geom::Point randomize(); - virtual void doBeforeEffect(SPLPEItem const */*lpeitem*/); - virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t); - virtual SPCurve *jitter(const Geom::Curve *A); - virtual Geom::Point tpoint(Geom::Point A, Geom::Point B, double t = 0.5); - virtual Gtk::Widget *newWidget(); + LPERoughen(LivePathEffectObject *lpeobject); + virtual ~LPERoughen(); + + virtual void doEffect(SPCurve *curve); + virtual double sign(double randNumber); + virtual Geom::Point randomize(); + virtual void doBeforeEffect(SPLPEItem const */*lpeitem*/); + virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t); + virtual SPCurve *jitter(const Geom::Curve *A); + virtual Geom::Point tpoint(Geom::Point A, Geom::Point B, double t = 0.5); + virtual Gtk::Widget *newWidget(); private: - UnitParam unit; - EnumParam method; - ScalarParam maxSegmentSize; - ScalarParam segments; - RandomParam displaceX; - RandomParam displaceY; - BoolParam shiftNodes; - BoolParam shiftNodeHandles; - LPERoughen(const LPERoughen &); - LPERoughen &operator=(const LPERoughen &); + UnitParam unit; + EnumParam method; + ScalarParam maxSegmentSize; + ScalarParam segments; + RandomParam displaceX; + RandomParam displaceY; + BoolParam shiftNodes; + BoolParam shiftNodeHandles; + LPERoughen(const LPERoughen &); + LPERoughen &operator=(const LPERoughen &); }; -- cgit v1.2.3 From 653e9d6d88598ca21cd3b469e534890d2a9d5a64 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 16 Sep 2014 16:44:51 -0400 Subject: Refactor LPETaperStroke a little bit (bzr r13341.1.211) --- src/live_effects/lpe-taperstroke.cpp | 215 ++++++++++++++++++----------------- src/live_effects/lpe-taperstroke.h | 2 +- 2 files changed, 111 insertions(+), 106 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 9c43b6671..b595b8d55 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -18,6 +18,7 @@ #include <2geom/path.h> #include <2geom/circle.h> #include <2geom/sbasis-to-bezier.h> + #include "pathoutlineprovider.h" #include "display/curve.h" #include "sp-shape.h" @@ -29,11 +30,11 @@ #include "svg/css-ostringstream.h" #include "svg/svg.h" -//#include - #include "knot-holder-entity.h" #include "knotholder.h" +#include + template inline bool withinRange(T value, T low, T high) { return (value > low && value < high); @@ -83,22 +84,16 @@ LPETaperStroke::LPETaperStroke(LivePathEffectObject *lpeobject) : attach_start.param_set_digits(3); attach_end.param_set_digits(3); - - registerParameter( dynamic_cast(&line_width) ); - registerParameter( dynamic_cast(&attach_start) ); - registerParameter( dynamic_cast(&attach_end) ); - registerParameter( dynamic_cast(&smoothing) ); - registerParameter( dynamic_cast(&join_type) ); - registerParameter( dynamic_cast(&miter_limit) ); -} - -LPETaperStroke::~LPETaperStroke() -{ - + registerParameter(&line_width); + registerParameter(&attach_start); + registerParameter(&attach_end); + registerParameter(&smoothing); + registerParameter(&join_type); + registerParameter(&miter_limit); } -//from LPEPowerStroke -- sets fill if stroke color because we will -//be converting to a fill to make the new join. +// from LPEPowerStroke -- sets fill if stroke color because we will +// be converting to a fill to make the new join. void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) { @@ -135,15 +130,14 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) line_width.param_set_value(width); } else { - g_warning("LPE Join Type can only be applied to paths (not groups)."); + printf("WARNING: It only makes sense to apply Join Type to paths (not groups).\n"); } } -//from LPEPowerStroke -- sets stroke color from existing fill color +// from LPEPowerStroke -- sets stroke color from existing fill color void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) { - if (SP_IS_SHAPE(lpeitem)) { SPLPEItem *item = const_cast(lpeitem); @@ -177,41 +171,44 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem) sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref (css); - item->updateRepr(); } } -//actual effect impl here +using Geom::Piecewise; +using Geom::D2; +using Geom::SBasis; +// leave Geom::Path -Geom::Path return_at_first_cusp (Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) -{ +Geom::Path return_at_first_cusp(Geom::Path const & path_in, double /*smooth_tolerance*/ = 0.05) { return Geom::split_at_cusps(path_in)[0]; } -Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double width); +Piecewise > stretch_along(Piecewise > pwd2_in, Geom::Path pattern, double width); -//references to pointers, because magic +// references to pointers void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_first, Geom::Curve *& val_second); +// actual effect + Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) { Geom::Path first_cusp = return_at_first_cusp(path_in[0]); Geom::Path last_cusp = return_at_first_cusp(path_in[0].reverse()); - bool zeroStart = false; - bool zeroEnd = false; - bool metInMiddle = false; + bool zeroStart = false; // [distance from start taper knot -> start of path] == 0 + bool zeroEnd = false; // [distance from end taper knot -> end of path] == 0 + bool metInMiddle = false; // knots are touching - //there is a pretty good chance that people will try to drag the knots - //on top of each other, so block it + // there is a pretty good chance that people will try to drag the knots + // on top of each other, so block it unsigned size = path_in[0].size(); if (size == first_cusp.size()) { - //check to see if the knots were dragged over each other - //if so, reset the end offset, but still allow the start offset. + // check to see if the knots were dragged over each other + // if so, reset the end offset, but still allow the start offset. if ( attach_start >= (size - attach_end) ) { attach_end.param_set_value( size - attach_start ); - metInMiddle = true; + metInMiddle = true; } } @@ -222,7 +219,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) metInMiddle = true; } - //don't let it be integer + // don't let it be integer (TODO this is stupid!) { if (double(unsigned(attach_start)) == attach_start) { attach_start.param_set_value(attach_start - 0.00001); @@ -235,7 +232,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) unsigned allowed_start = first_cusp.size(); unsigned allowed_end = last_cusp.size(); - //don't let the knots be farther than they are allowed to be + // don't let the knots be farther than they are allowed to be { if ((unsigned)attach_start >= allowed_start) { attach_start.param_set_value((double)allowed_start - 0.00001); @@ -245,7 +242,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) } } - //don't let it be zero + // don't let it be zero (this is stupid too!) if (attach_start < 0.0000001 || withinRange(double(attach_start), 0.00000001, 0.000001)) { attach_start.param_set_value( 0.0000001 ); zeroStart = true; @@ -255,25 +252,26 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) zeroEnd = true; } - //remember, Path::operator () means get point at time t + // Path::operator () means get point at time t start_attach_point = first_cusp(attach_start); end_attach_point = last_cusp(attach_end); Geom::PathVector pathv_out; - //the following function just splits it up into three pieces. + // the following function just splits it up into three pieces. pathv_out = doEffect_simplePath(path_in); - //now for the actual tapering. We use the stretch_along method to get this done. + // now for the actual tapering. the stretch_along method (stolen from PaP) is used to accomplish this Geom::PathVector real_pathv; Geom::Path real_path; Geom::PathVector pat_vec; - Geom::Piecewise > pwd2; + Piecewise > pwd2; Geom::Path throwaway_path; if (!zeroStart) { - //Construct the pattern (pat_str stands for pattern string) (and yes, this is easier, trust me) + // Construct the pattern std::stringstream pat_str; + pat_str.imbue(std::locale::classic()); pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); @@ -283,12 +281,13 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) real_path.append(throwaway_path); } + // if this condition happens to evaluate false, i.e. there was no space for a path to be drawn, it is simply skipped. + // although this seems obvious, it can probably lead to bugs. if (!metInMiddle) { - //append the outside outline of the path (with direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1], - -fabs(line_width), static_cast(join_type.get_value()), miter_limit); + // append the outside outline of the path (goes with the direction of the path) + throwaway_path = Outline::PathOutsideOutline(pathv_out[1], -fabs(line_width), static_cast(join_type.get_value()), miter_limit); if (!zeroStart && real_path.size() >= 1 && throwaway_path.size() >= 1) { - if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001) { + if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint())) { real_path.appendNew(throwaway_path.initialPoint()); } else { real_path.setFinal(throwaway_path.initialPoint()); @@ -298,16 +297,17 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) } if (!zeroEnd) { - //append the ending taper + // append the ending taper std::stringstream pat_str_1; + pat_str_1.imbue(std::locale::classic()); pat_str_1 << "M 0,1 C " << (double)smoothing << ",1 1,0.5 1,0.5 1,0.5 " << double(smoothing) << ",0 0,0"; pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); - pwd2 = Geom::Piecewise > (); + pwd2 = Piecewise >(); pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; - if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001 && real_path.size() >= 1) { + if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { real_path.appendNew(throwaway_path.initialPoint()); } else { real_path.setFinal(throwaway_path.initialPoint()); @@ -316,11 +316,10 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) } if (!metInMiddle) { - //append the inside outline of the path (against direction) - throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), - -fabs(line_width), static_cast(join_type.get_value()), miter_limit); + // append the inside outline of the path (against direction) + throwaway_path = Outline::PathOutsideOutline(pathv_out[1].reverse(), -fabs(line_width), static_cast(join_type.get_value()), miter_limit); - if (Geom::distance(real_path.finalPoint(), throwaway_path.initialPoint()) > 0.0000001 && real_path.size() >= 1) { + if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { real_path.appendNew(throwaway_path.initialPoint()); } else { real_path.setFinal(throwaway_path.initialPoint()); @@ -328,7 +327,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) real_path.append(throwaway_path); } - if (Geom::distance(real_path.finalPoint(), real_path.initialPoint()) > 0.0000001) { + if (!Geom::are_near(real_path.finalPoint(), real_path.initialPoint())) { real_path.appendNew(real_path.initialPoint()); } else { real_path.setFinal(real_path.initialPoint()); @@ -340,12 +339,16 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) return real_pathv; } -//in all cases, this should return a PathVector with three elements. +/** + * @return Always returns a PathVector with three elements. + * + * The positions of the effect knots are accessed to determine + * where exactly the input path should be split. + */ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & path_in) { - unsigned size = path_in[0].size(); + size_t size = path_in[0].size(); - //do subdivision and get out unsigned loc = (unsigned)attach_start; Geom::Curve * curve_start = path_in[0] [loc].duplicate(); @@ -355,7 +358,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa Geom::Path trimmed_start = Geom::Path(); Geom::Path trimmed_end = Geom::Path(); - for (unsigned i = 0; i < loc; i++) { + for (size_t i = 0; i < loc; ++i) { trimmed_start.append(path_in[0] [i]); } @@ -364,20 +367,23 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa trimmed_start.append(*temp); if (temp) delete temp; temp = 0; - //special case: path is one segment long - //special case: what if the two knots occupy the same segment? + // special case: path is one segment long + // special case: what if the two knots occupy the same segment? if ((size == 1) || ( size - unsigned(attach_end) - 1 == loc )) { + + // If you look into it, I don't actually think there is a working way to do this + // with only point math. So we use nearest_point instead. Geom::Coord t = Geom::nearest_point(end_attach_point, *curve_start); - //it is just a dumb segment - //we have to do some shifting here because the value changed when we reduced the length - //of the previous segment. + // it is just a dumb segment + // we have to do some shifting here because the value changed when we reduced the length + // of the previous segment. subdivideCurve(curve_start, t, curve_start, temp); trimmed_end.append(*temp); if (temp) delete temp; temp = 0; - for (unsigned j = (size - attach_end) + 1; j < size; j++) { + for (size_t j = (size - attach_end) + 1; j < size; ++j) { trimmed_end.append(path_in[0] [j]); } @@ -390,14 +396,14 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa pathv_out.push_back(trimmed_start); - //append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) + // append almost all of the rest of the path, ignore the curves that the knot is past (we'll get to it in a minute) path_out.append(*curve_start); - for (unsigned k = loc + 1; k < (size - unsigned(attach_end)) - 1; k++) { + for (size_t k = loc + 1; k < (size - unsigned(attach_end)) - 1; ++k) { path_out.append(path_in[0] [k]); } - //deal with the last segment in a very similar fashion to the first + // deal with the last segment in a very similar fashion to the first loc = size - attach_end; Geom::Curve * curve_end = path_in[0] [loc].duplicate(); @@ -408,7 +414,7 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa trimmed_end.append(*temp); if (temp) delete temp; temp = 0; - for (unsigned j = (size - attach_end) + 1; j < size; j++) { + for (size_t j = (size - attach_end) + 1; j < size; ++j) { trimmed_end.append(path_in[0] [j]); } @@ -423,9 +429,12 @@ Geom::PathVector LPETaperStroke::doEffect_simplePath(Geom::PathVector const & pa } -//most of the below code is verbatim from Pattern Along Path. However, it needed a little -//tweaking to get it to work right in this case. -Geom::Piecewise > stretch_along(Geom::Piecewise > pwd2_in, Geom::Path pattern, double prop_scale) +/** + * Most of the below function is verbatim from Pattern Along Path. However, it needed a little + * tweaking to get it to work right in this case. Also, large portions of the effect have been + * stripped out as I deemed them unnecessary for the relative simplicity of this effect. + */ +Piecewise > stretch_along(Piecewise > pwd2_in, Geom::Path pattern, double prop_scale) { using namespace Geom; @@ -436,7 +445,7 @@ Geom::Piecewise > stretch_along(Geom::Piecewise > output; - std::vector > > pre_output; + std::vector > > pre_output; D2 > patternd2 = make_cuts_independent(pattern.toPwSb()); Piecewise x0 = Piecewise(patternd2[0]); @@ -450,18 +459,18 @@ Geom::Piecewise > stretch_along(Geom::Piecewiseextent()*.9) { xspace = -pattBndsX->extent()*.9; } y0+=noffset; - std::vector > > paths_in; + std::vector > > paths_in; paths_in = split_at_discontinuities(pwd2_in); for (unsigned idx = 0; idx < paths_in.size(); idx++) { - Geom::Piecewise > path_i = paths_in[idx]; + Piecewise > path_i = paths_in[idx]; Piecewise x = x0; Piecewise y = y0; Piecewise > uskeleton = arc_length_parametrization(path_i,2,.1); @@ -489,8 +498,8 @@ Geom::Piecewise > stretch_along(Geom::Piecewise > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs); - std::vector > > splited_output_piece = split_at_discontinuities(output_piece); + Piecewise > output_piece = compose(uskeleton,x+offs)+y*compose(n,x+offs); + std::vector > > splited_output_piece = split_at_discontinuities(output_piece); pre_output.insert(pre_output.end(), splited_output_piece.begin(), splited_output_piece.end() ); } else { output.concat(compose(uskeleton,x+offs)+y*compose(n,x+offs)); @@ -507,12 +516,12 @@ Geom::Piecewise > stretch_along(Geom::Piecewise(curve_in)) { - //special case for line segments + // special case for line segments std::pair seg_pair = linear->subdivide(t); val_first = seg_pair.first.duplicate(); val_second = seg_pair.second.duplicate(); } else { - //all other cases: + // all other cases: Geom::CubicBezier cubic = Geom::sbasis_to_cubicbezier(curve_in->toSBasis()); std::pair cubic_pair = cubic.subdivide(t); val_first = cubic_pair.first.duplicate(); @@ -523,22 +532,18 @@ void subdivideCurve(Geom::Curve * curve_in, Geom::Coord t, Geom::Curve *& val_fi void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { - { - KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); - e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE ); - knotholder->add(e); - } - { - KnotHolderEntity *e = new TpS::KnotHolderEntityAttachEnd(this); - e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE ); - knotholder->add(e); - } + KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this); + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE); + knotholder->add(e); + + KnotHolderEntity *f = new TpS::KnotHolderEntityAttachEnd(this); + f->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE); + knotholder->add(f); } namespace TpS { -void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) + +void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point const&/*origin*/, guint state) { using namespace Geom; @@ -546,19 +551,18 @@ void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point con Geom::Point const s = snap_knot_position(p, state); - if (!SP_IS_SHAPE(lpe->sp_lpe_item) ) { - g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); + if (!SP_IS_SHAPE(lpe->sp_lpe_item)) { + printf("WARNING: LPEItem is not a path!\n"); return; } SPCurve* curve; - if ( !(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve()) ) { - //oops - //lpe->attach_start.param_set_value(0); + if (!(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve())) { + // oops return; } - //in case you are wondering, the above are simply sanity checks. we never want to actually - //use that object. + // in case you are wondering, the above are simply sanity checks. we never want to actually + // use that object. Geom::PathVector pathv = lpe->pathvector_before_effect; @@ -570,7 +574,7 @@ void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point con lpe->attach_start.param_set_value(t0); // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, true); } void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state) { @@ -581,14 +585,13 @@ void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const Geom::Point const s = snap_knot_position(p, state); if (!SP_IS_SHAPE(lpe->sp_lpe_item) ) { - g_warning("LPEItem is not a path! %s:%d\n", __FILE__, __LINE__); + printf("WARNING: LPEItem is not a path!\n"); return; } SPCurve* curve; if ( !(curve = SP_SHAPE(lpe->sp_lpe_item)->getCurve()) ) { - //oops - //lpe->attach_end.param_set_value(0); + // oops return; } Geom::PathVector pathv = lpe->pathvector_before_effect; @@ -600,20 +603,22 @@ void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); } + Geom::Point KnotHolderEntityAttachBegin::knot_get() const { LPETaperStroke const * lpe = dynamic_cast (_effect); return lpe->start_attach_point; } + Geom::Point KnotHolderEntityAttachEnd::knot_get() const { LPETaperStroke const * lpe = dynamic_cast (_effect); return lpe->end_attach_point; } -} -} //namespace LivePathEffect -} /* namespace Inkscape */ +} // namespace TpS +} // namespace LivePathEffect +} // namespace Inkscape /* Local Variables: diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h index 4719d1a46..88604486e 100644 --- a/src/live_effects/lpe-taperstroke.h +++ b/src/live_effects/lpe-taperstroke.h @@ -28,7 +28,7 @@ class KnotHolderEntityAttachEnd; class LPETaperStroke : public Effect { public: LPETaperStroke(LivePathEffectObject *lpeobject); - virtual ~LPETaperStroke(); + virtual ~LPETaperStroke() {} virtual void doOnApply(SPLPEItem const* lpeitem); virtual void doOnRemove(SPLPEItem const* lpeitem); -- cgit v1.2.3 From fb4d4b30b50b7b4505d63772c0aeca4c05c2c5c6 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 22 Sep 2014 21:15:47 +0200 Subject: Fix for strange gap at shift to cusp in bspline Now curves with cusp noden in bspline mode looks better, more smooth. Remove some duplicate code from outside for loops Fix a bug continuing shapes in bspline-spiro mode. Style code formating (bzr r13341.1.215) --- src/live_effects/lpe-bspline.cpp | 360 +++++++++++---------------------------- 1 file changed, 101 insertions(+), 259 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 433696aab..1141e87ef 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -52,6 +52,7 @@ using Inkscape::DocumentUndo; namespace Inkscape { namespace LivePathEffect { +const double handleCubicGap = 0.01; LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject), steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), @@ -97,192 +98,136 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) void LPEBSpline::doEffect(SPCurve *curve) { - if (curve->get_segment_count() < 1) + if (curve->get_segment_count() < 1){ return; - // Make copy of old path as it is changed during processing + } + Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo 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 - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores + 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(); SPCurve *nCurve = new SPCurve(); Geom::Point previousNode(0, 0); Geom::Point node(0, 0); Geom::Point pointAt1(0, 0); Geom::Point pointAt2(0, 0); Geom::Point nextPointAt1(0, 0); - Geom::Point nextPointAt2(0, 0); - Geom::Point nextPointAt3(0, 0); Geom::D2 SBasisIn; Geom::D2 SBasisOut; Geom::D2 SBasisHelper; Geom::CubicBezier const *cubic = NULL; 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. + const Geom::Curve &closingline = path_it->back_closed(); 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(); } } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último - while (curve_it2 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path - //recto de entrada y de salida + while (curve_it1 != curve_endit) { SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); cubic = dynamic_cast(&*curve_it1); if (cubic) { SBasisIn = in->first_segment()->toSBasis(); - pointAt1 = SBasisIn.valueAt( - Geom::nearest_point((*cubic)[1], *in->first_segment())); - pointAt2 = SBasisIn.valueAt( - Geom::nearest_point((*cubic)[2], *in->first_segment())); + if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { + pointAt1 = SBasisIn.valueAt(0.3334); + } else { + pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); + } + if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) { + pointAt2 = SBasisIn.valueAt(0.6667); + } else { + pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); + } } else { pointAt1 = in->first_segment()->initialPoint(); pointAt2 = in->first_segment()->finalPoint(); } in->reset(); delete in; - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); - SPCurve *out = new SPCurve(); - out->moveto(curve_it2->initialPoint()); - out->lineto(curve_it2->finalPoint()); - cubic = dynamic_cast(&*curve_it2); - if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt( - Geom::nearest_point((*cubic)[1], *out->first_segment())); - nextPointAt2 = SBasisOut.valueAt( - Geom::nearest_point((*cubic)[2], *out->first_segment())); - ; - nextPointAt3 = out->first_segment()->finalPoint(); + if ( curve_it2 != curve_endit ) { + SPCurve *out = new SPCurve(); + out->moveto(curve_it2->initialPoint()); + out->lineto(curve_it2->finalPoint()); + cubic = dynamic_cast(&*curve_it2); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { + nextPointAt1 = SBasisIn.valueAt(0.3334); + } else { + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + } + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + } + out->reset(); + delete out; + } + Geom::Point startNode = path_it->begin()->initialPoint(); + if (path_it->closed() && curve_it2 == curve_endit) { + SPCurve *start = new SPCurve(); + start->moveto(path_it->begin()->initialPoint()); + start->lineto(path_it->begin()->finalPoint()); + Geom::D2 SBasisStart = start->first_segment()->toSBasis(); + SPCurve *lineHelper = new SPCurve(); + cubic = dynamic_cast(&*path_it->begin()); + if (cubic) { + lineHelper->moveto(SBasisStart.valueAt( + Geom::nearest_point((*cubic)[1], *start->first_segment()))); + } else { + lineHelper->moveto(start->first_segment()->initialPoint()); + } + start->reset(); + delete start; + + SPCurve *end = new SPCurve(); + end->moveto(curve_it1->initialPoint()); + end->lineto(curve_it1->finalPoint()); + Geom::D2 SBasisEnd = end->first_segment()->toSBasis(); + cubic = dynamic_cast(&*curve_it1); + if (cubic) { + lineHelper->lineto(SBasisEnd.valueAt( + Geom::nearest_point((*cubic)[2], *end->first_segment()))); + } else { + lineHelper->lineto(end->first_segment()->finalPoint()); + } + end->reset(); + delete end; + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + startNode = SBasisHelper.valueAt(0.5); + nCurve->curveto(pointAt1, pointAt2, startNode); + nCurve->move_endpoints(startNode, startNode); + } else if ( curve_it2 == curve_endit) { + nCurve->curveto(pointAt1, pointAt2, curve_it1->finalPoint()); + nCurve->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint()); } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); + SPCurve *lineHelper = new SPCurve(); + lineHelper->moveto(pointAt2); + lineHelper->lineto(nextPointAt1); + SBasisHelper = lineHelper->first_segment()->toSBasis(); + lineHelper->reset(); + delete lineHelper; + previousNode = node; + node = SBasisHelper.valueAt(0.5); + Geom::CubicBezier const *cubic2 = dynamic_cast(&*curve_it1); + if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) { + node = curve_it1->finalPoint(); + } + nCurve->curveto(pointAt1, pointAt2, node); } - out->reset(); - delete out; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de - //los manejadores de la curva - SPCurve *lineHelper = new SPCurve(); - lineHelper->moveto(pointAt2); - lineHelper->lineto(nextPointAt1); - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de - //principio de curva - previousNode = node; - //Y este hará de final de curva - node = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, node); - //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; } - SPCurve *out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); - nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); - nextPointAt3 = out->first_segment()->finalPoint(); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - } - out->reset(); - delete out; - //Si está cerrada la curva, la cerramos sobre el valor guardado - //previamente - //Si no finalizamos en el punto final - Geom::Point startNode = path_it->begin()->initialPoint(); - if (path_it->closed()) { - SPCurve *start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - Geom::D2 SBasisStart = start->first_segment()->toSBasis(); - SPCurve *lineHelper = new SPCurve(); - cubic = dynamic_cast(&*path_it->begin()); - if (cubic) { - lineHelper->moveto(SBasisStart.valueAt( - Geom::nearest_point((*cubic)[1], *start->first_segment()))); - } else { - lineHelper->moveto(start->first_segment()->initialPoint()); - } - start->reset(); - delete start; - - SPCurve *end = new SPCurve(); - end->moveto(curve_it1->initialPoint()); - end->lineto(curve_it1->finalPoint()); - Geom::D2 SBasisEnd = end->first_segment()->toSBasis(); - - cubic = dynamic_cast(&*curve_it1); - if (cubic) { - lineHelper->lineto(SBasisEnd.valueAt( - Geom::nearest_point((*cubic)[2], *end->first_segment()))); - } else { - lineHelper->lineto(end->first_segment()->finalPoint()); - } - end->reset(); - delete end; - SBasisHelper = lineHelper->first_segment()->toSBasis(); - lineHelper->reset(); - delete lineHelper; - startNode = SBasisHelper.valueAt(0.5); - nCurve->curveto(nextPointAt1, nextPointAt2, startNode); - nCurve->move_endpoints(startNode, startNode); - } else { - SPCurve *start = new SPCurve(); - start->moveto(path_it->begin()->initialPoint()); - start->lineto(path_it->begin()->finalPoint()); - startNode = start->first_segment()->initialPoint(); - start->reset(); - delete start; - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(startNode, nextPointAt3); - } //y cerramos la curva if (path_it->closed()) { nCurve->closepath_current(); @@ -402,7 +347,7 @@ bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) for (std::vector::iterator i = points.begin(); i != points.end(); ++i) { Geom::Point p = *i; - if (Geom::are_near(p, nodePoint, 0.0001)) { + if (Geom::are_near(p, nodePoint, handleCubicGap)) { return true; } else { } @@ -463,10 +408,6 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) Geom::Point pointAt1(0, 0); Geom::Point pointAt2(0, 0); Geom::Point pointAt3(0, 0); - Geom::Point nextPointAt0(0, 0); - Geom::Point nextPointAt1(0, 0); - Geom::Point nextPointAt2(0, 0); - Geom::Point nextPointAt3(0, 0); Geom::D2 SBasisIn; Geom::D2 SBasisOut; Geom::CubicBezier const *cubic = NULL; @@ -490,7 +431,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) //BSPline nCurve->moveto(curve_it1->initialPoint()); //Recorremos todos los segmentos menos el último - while (curve_it2 != curve_endit) { + while (curve_it1 != curve_endit) { //previousPointAt3 = pointAt3; //Calculamos los puntos que dividirían en tres segmentos iguales el path //recto de entrada y de salida @@ -507,7 +448,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt1 = SBasisIn.valueAt(weightValue); if (weightValue != 0.0000) { pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } } else { pointAt1 = in->first_segment()->initialPoint(); @@ -516,7 +457,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt2 = SBasisIn.valueAt(1 - weightValue); if (weightValue != 0.0000) { pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } } else { pointAt2 = in->first_segment()->finalPoint(); @@ -526,12 +467,12 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt1 = SBasisIn.valueAt(weightValue); if (weightValue != 0.0000) { pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } pointAt2 = SBasisIn.valueAt(1 - weightValue); if (weightValue != 0.0000) { pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } } else { pointAt1 = in->first_segment()->initialPoint(); @@ -545,7 +486,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt1 = SBasisIn.valueAt(weightValue); if (weightValue != 0.0000) { pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } } else { pointAt1 = (*cubic)[1]; @@ -558,7 +499,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt2 = SBasisIn.valueAt(1 - weightValue); if (weightValue != 0.0000) { pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } } else { pointAt2 = (*cubic)[2]; @@ -567,18 +508,18 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt2 = in->first_segment()->finalPoint(); } } else { - if (!ignoreCusp && weightValue != 0.000) { + if (!ignoreCusp && weightValue != 0.0000) { if (nodeIsSelected(pointAt0)) { pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = - Geom::Point(pointAt1[X] + 0.0001, pointAt1[Y] + 0.0001); + Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } else { pointAt1 = in->first_segment()->initialPoint(); } if (nodeIsSelected(pointAt3)) { pointAt2 = SBasisIn.valueAt(weightValue); pointAt2 = - Geom::Point(pointAt2[X] + 0.0001, pointAt2[Y] + 0.0001); + Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } else { pointAt2 = in->first_segment()->finalPoint(); } @@ -601,110 +542,11 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) ++curve_it1; ++curve_it2; } - SPCurve *out = new SPCurve(); - out->moveto(curve_it1->initialPoint()); - out->lineto(curve_it1->finalPoint()); - SBasisOut = out->first_segment()->toSBasis(); - nextPointAt0 = out->first_segment()->initialPoint(); - nextPointAt3 = out->first_segment()->finalPoint(); - cubic = dynamic_cast(&*curve_it1); - if (!onlySelected) { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - if (weightValue != 0.0000) { - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - } - } - } else { - if (cubic) { - if (!ignoreCusp || !Geom::are_near((*cubic)[1], nextPointAt0)) { - if (nodeIsSelected(nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - if (weightValue != 0.0000) { - nextPointAt1 = Geom::Point(nextPointAt1[X] + 0.0001, - nextPointAt1[Y] + 0.0001); - } - } else { - nextPointAt1 = (*cubic)[1]; - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (!ignoreCusp || !Geom::are_near((*cubic)[2], nextPointAt3)) { - if (nodeIsSelected(nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(1 - weightValue); - if (weightValue != 0.0000) { - nextPointAt2 = Geom::Point(nextPointAt2[X] + 0.0001, - nextPointAt2[Y] + 0.0001); - } - } else { - nextPointAt2 = (*cubic)[2]; - } - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - if (!ignoreCusp && weightValue != 0.0000) { - if (nodeIsSelected(nextPointAt0)) { - nextPointAt1 = SBasisOut.valueAt(weightValue); - nextPointAt1 = - Geom::Point(nextPointAt1[X] + 0.0001, nextPointAt1[Y] + 0.0001); - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - } - if (nodeIsSelected(nextPointAt3)) { - nextPointAt2 = SBasisOut.valueAt(weightValue); - nextPointAt2 = - Geom::Point(nextPointAt2[X] + 0.0001, nextPointAt2[Y] + 0.0001); - } else { - nextPointAt2 = out->first_segment()->finalPoint(); - } - } else { - nextPointAt1 = out->first_segment()->initialPoint(); - nextPointAt2 = out->first_segment()->finalPoint(); - } - } - } - out->reset(); - delete out; - //Aberiguamos la ultima parte de la curva correspondiente al último - //segmento - //Y hacemos lo propio con el path de salida - //nextPointAt0 = curveOut.valueAt(0); if (path_it->closed()) { - nCurve->curveto(nextPointAt1, nextPointAt2, - path_it->begin()->initialPoint()); nCurve->move_endpoints(path_it->begin()->initialPoint(), path_it->begin()->initialPoint()); } else { - nCurve->curveto(nextPointAt1, nextPointAt2, nextPointAt3); - nCurve->move_endpoints(path_it->begin()->initialPoint(), nextPointAt3); + nCurve->move_endpoints(path_it->begin()->initialPoint(), pointAt3); } //y cerramos la curva if (path_it->closed()) { -- cgit v1.2.3 From 86cf2d0a97e0412629102ae51df0a4797f9179db Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 23 Sep 2014 23:43:31 +0200 Subject: remove magic numbers from bspline (bzr r13341.1.219) --- src/live_effects/lpe-bspline.cpp | 42 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 1141e87ef..eb0604273 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -53,19 +53,23 @@ namespace Inkscape { namespace LivePathEffect { const double handleCubicGap = 0.01; +const double noPower = 0.0; +const double defaultStartPower = 0.3334; +const double defaultEndPower = 0.6667; + LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject), steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, 0.3334) + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, defaultStartPower) { registerParameter(&weight); registerParameter(&steps); registerParameter(&ignoreCusp); registerParameter(&onlySelected); - weight.param_set_range(0.0000, 1); + weight.param_set_range(noPower, 1); weight.param_set_increments(0.1, 0.1); weight.param_set_digits(4); @@ -138,12 +142,12 @@ void LPEBSpline::doEffect(SPCurve *curve) if (cubic) { SBasisIn = in->first_segment()->toSBasis(); if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { - pointAt1 = SBasisIn.valueAt(0.3334); + pointAt1 = SBasisIn.valueAt(defaultStartPower); } else { pointAt1 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); } if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) { - pointAt2 = SBasisIn.valueAt(0.6667); + pointAt2 = SBasisIn.valueAt(defaultEndPower); } else { pointAt2 = SBasisIn.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); } @@ -161,7 +165,7 @@ void LPEBSpline::doEffect(SPCurve *curve) if (cubic) { SBasisOut = out->first_segment()->toSBasis(); if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { - nextPointAt1 = SBasisIn.valueAt(0.3334); + nextPointAt1 = SBasisIn.valueAt(defaultStartPower); } else { nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); } @@ -294,22 +298,22 @@ Gtk::Widget *LPEBSpline::newWidget() void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) { - weight.param_set_value(0.3334); - changeWeight(0.3334); + weight.param_set_value(defaultStartPower); + changeWeight(defaultStartPower); Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); Gtk::Entry* entryWidg = dynamic_cast(childList[1]); - entryWidg->set_text("0.3334"); + entryWidg->set_text("defaultStartPower"); } void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) { - weight.param_set_value(0.0000); - changeWeight(0.0000); + weight.param_set_value(noPower); + changeWeight(noPower); Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); Gtk::Entry* entryWidg = dynamic_cast(childList[1]); - entryWidg->set_text("0.0000"); + entryWidg->set_text("noPower"); } void LPEBSpline::toWeight() @@ -446,7 +450,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) if (cubic) { if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { + if (weightValue != noPower) { pointAt1 = Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } @@ -455,7 +459,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { + if (weightValue != noPower) { pointAt2 = Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } @@ -463,14 +467,14 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt2 = in->first_segment()->finalPoint(); } } else { - if (!ignoreCusp && weightValue != 0.0000) { + if (!ignoreCusp && weightValue != noPower) { pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { + if (weightValue != noPower) { pointAt1 = Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { + if (weightValue != noPower) { pointAt2 = Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } @@ -484,7 +488,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { if (nodeIsSelected(pointAt0)) { pointAt1 = SBasisIn.valueAt(weightValue); - if (weightValue != 0.0000) { + if (weightValue != noPower) { pointAt1 = Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } @@ -497,7 +501,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { if (nodeIsSelected(pointAt3)) { pointAt2 = SBasisIn.valueAt(1 - weightValue); - if (weightValue != 0.0000) { + if (weightValue != noPower) { pointAt2 = Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); } @@ -508,7 +512,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt2 = in->first_segment()->finalPoint(); } } else { - if (!ignoreCusp && weightValue != 0.0000) { + if (!ignoreCusp && weightValue != noPower) { if (nodeIsSelected(pointAt0)) { pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = -- cgit v1.2.3 From 241347e25e559460b985f944bbcb2b5c9c910c86 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 29 Sep 2014 03:35:12 +0200 Subject: Fillet-Chamfer update. Two things. Helper paths on knots: now work well in rect and curves Method: Now the method ase selectable. Three methods: Auto: Straight lines whith arcs and curves whith bezier Arc: Always use arc. Bezier: Always use bezier. (bzr r13341.1.225) --- src/live_effects/lpe-fillet-chamfer.cpp | 16 +++++++--- src/live_effects/lpe-fillet-chamfer.h | 8 ++++- .../parameter/filletchamferpointarray.cpp | 37 +++++++++++----------- 3 files changed, 37 insertions(+), 24 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 0ad21a284..4e7d62ff5 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -42,6 +42,14 @@ using namespace Geom; namespace Inkscape { namespace LivePathEffect { +static const Util::EnumData FilletMethodData[FM_END] = { + { FM_AUTO, N_("Auto"), "auto" }, + { FM_ARC, N_("Force arc"), "arc" }, + { FM_BEZIER, N_("Force bezier"), "bezier" } +}; +static const Util::EnumDataConverter +FMConverter(FilletMethodData, FM_END); + const double tolerance = 0.001; const double gapHelper = 0.00001; @@ -52,14 +60,15 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : ignore_radius_0(_("Ignore 0 radius knots"), _("Ignore 0 radius knots"), "ignore_radius_0", &wr, this, false), only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), - force_arcs(_("Use arcs in cubic curves"), _("Use arcs in cubic curves"), "force_arcs", &wr, this, false), use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false), unit(_("Unit"), _("Unit"), "unit", &wr, this), + method(_("Method"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO), radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) { registerParameter(&fillet_chamfer_values); registerParameter(&unit); + registerParameter(&method); registerParameter(&radius); registerParameter(&helper_size); registerParameter(&flexible); @@ -67,7 +76,6 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : registerParameter(&ignore_radius_0); registerParameter(&only_selected); registerParameter(&hide_knots); - registerParameter(&force_arcs); radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); @@ -591,14 +599,14 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } path_out.appendNew(endArcPoint); } else if (type == 2) { - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed)) || force_arcs){ + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ ccwToggle = ccwToggle?0:1; path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); }else{ path_out.appendNew(inverseHandle1, inverseHandle2, endArcPoint); } } else { - if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed)) || force_arcs){ + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); } else { path_out.appendNew(handle1, handle2, endArcPoint); diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 49b407b71..873684101 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -33,6 +33,12 @@ namespace Inkscape { namespace LivePathEffect { +enum FilletMethod { + FM_AUTO, + FM_ARC, + FM_BEZIER, + FM_END +}; class LPEFilletChamfer : public Effect { public: @@ -67,9 +73,9 @@ private: BoolParam ignore_radius_0; BoolParam only_selected; BoolParam flexible; - BoolParam force_arcs; BoolParam use_knot_distance; UnitParam unit; + EnumParam method; ScalarParam radius; ScalarParam helper_size; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index bb00ef045..e2b1aba61 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -8,11 +8,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include - -#include "ui/dialog/lpe-fillet-chamfer-properties.h" -#include "live_effects/parameter/filletchamferpointarray.h" - #include <2geom/piecewise.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/sbasis-geometric.h> @@ -384,25 +379,29 @@ void FilletChamferPointArrayParam::updateCanvasIndicators() std::vector ts = data(); hp.clear(); unsigned int i = 0; - Piecewise > const &n = get_pwd2_normal(); for (std::vector::const_iterator point_it = ts.begin(); point_it != ts.end(); ++point_it) { - double Xvalue = to_time(i, (*point_it)[X]); - double XPlusValue = to_time(i, -helper_size) - i; - if (Xvalue == i) { + double Xvalue = to_time(i, (*point_it)[X]) -i; + if (Xvalue == 0) { i++; continue; } - Point canvas_point = last_pwd2.valueAt(Xvalue) + 0 * n.valueAt(Xvalue); - Point start_point = last_pwd2.valueAt(Xvalue + XPlusValue) + - helper_size * n.valueAt(Xvalue + XPlusValue); - Point end_point = last_pwd2.valueAt(Xvalue + XPlusValue) - - helper_size * n.valueAt(Xvalue + XPlusValue); - Geom::Path arrow; - arrow.start(start_point); - arrow.appendNew(canvas_point); - arrow.appendNew(end_point); - hp.push_back(arrow); + Geom::Point ptA = last_pwd2[i].valueAt(Xvalue); + Geom::Point derivA = unit_vector(derivative(last_pwd2[i]).valueAt(Xvalue)); + Geom::Rotate rot(Geom::Rotate::from_degrees(-90)); + derivA = derivA * rot; + Geom::Point C = ptA - derivA * helper_size; + Geom::Point D = ptA + derivA * helper_size; + Geom::Ray ray1(C, D); + char const * svgd = "M 1,0.25 0.5,0 1,-0.25 M 1,0.5 0,0 1,-0.5"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + Geom::Affine aff = Geom::Affine(); + aff *= Geom::Scale(helper_size); + aff *= Geom::Rotate(ray1.angle() - deg_to_rad(270)); + pathv *= aff; + pathv += last_pwd2[i].valueAt(Xvalue); + hp.push_back(pathv[0]); + hp.push_back(pathv[1]); i++; } } -- cgit v1.2.3 From b2514a837cdb7f41b6928baf9fd8678b388bbc08 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 29 Sep 2014 03:44:50 +0200 Subject: Add helper paths to BSPline (bzr r13341.1.226) --- src/live_effects/lpe-bspline.cpp | 33 +++++++++++++++++++++++++++++++++ src/live_effects/lpe-bspline.h | 4 ++++ 2 files changed, 37 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index eb0604273..5dfad95dc 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -80,6 +80,13 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : LPEBSpline::~LPEBSpline() {} +void LPEBSpline::doBeforeEffect (SPLPEItem const* lpeitem) +{ + if(!hp.empty()){ + hp.clear(); + } +} + void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) { if (!SP_IS_SHAPE(item)) { @@ -109,6 +116,11 @@ void LPEBSpline::doEffect(SPCurve *curve) Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); + double radiusHelperNodes = 6.0; + if (SP_ACTIVE_DESKTOP) { + radiusHelperNodes /= SP_ACTIVE_DESKTOP->current_zoom(); + } + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -228,6 +240,9 @@ void LPEBSpline::doEffect(SPCurve *curve) node = curve_it1->finalPoint(); } nCurve->curveto(pointAt1, pointAt2, node); + if(!are_near(node,curve_it1->finalPoint())){ + drawHandle(node, radiusHelperNodes); + } } ++curve_it1; ++curve_it2; @@ -239,9 +254,27 @@ void LPEBSpline::doEffect(SPCurve *curve) curve->append(nCurve, false); nCurve->reset(); delete nCurve; + Geom::PathVector const pathv = curve->get_pathvector(); + hp.push_back(pathv[0]); } } +void +LPEBSpline::drawHandle(Geom::Point p, double radiusHelperNodes) +{ + char const * svgd = "M 1,0.5 A 0.5,0.5 0 0 1 0.5,1 0.5,0.5 0 0 1 0,0.5 0.5,0.5 0 0 1 0.5,0 0.5,0.5 0 0 1 1,0.5 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(radiusHelperNodes,0,0,radiusHelperNodes,0,0); + pathv += p - Geom::Point(0.5*radiusHelperNodes, 0.5*radiusHelperNodes); + hp.push_back(pathv[0]); +} + +void +LPEBSpline::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec) +{ + hp_vec.push_back(hp); +} + Gtk::Widget *LPEBSpline::newWidget() { // use manage here, because after deletion of Effect object, others might diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index f37741a4a..e066015ad 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -24,6 +24,9 @@ public: return SUPPRESS_FLASH; } virtual void doEffect(SPCurve *curve); + virtual void doBeforeEffect(SPLPEItem const* lpeitem); + void drawHandle(Geom::Point p, double radiusHelperNodes); + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); void doBSplineFromWidget(SPCurve *curve, double value); bool nodeIsSelected(Geom::Point nodePoint); @@ -43,6 +46,7 @@ private: BoolParam ignoreCusp; BoolParam onlySelected; ScalarParam weight; + Geom::PathVector hp; LPEBSpline(const LPEBSpline &); LPEBSpline &operator=(const LPEBSpline &); -- cgit v1.2.3 From a82e6521b78fb89d040d9ae0b38c8e4691571920 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 29 Sep 2014 03:56:43 +0200 Subject: This push add a partial solution to scale powerstroke shapes without distorsion Currently best results are for fixed ratio scales, non fixed scale give a aproximation. (bzr r13341.1.228) --- src/live_effects/parameter/powerstrokepointarray.cpp | 11 +++++++---- src/live_effects/parameter/powerstrokepointarray.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 427be8065..851b12ef8 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -68,13 +68,16 @@ PowerStrokePointArrayParam::param_newWidget() */ } - -void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) +void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) { -// param_set_and_write_new_value( (*this) * postmul ); + std::vector result; + for (std::vector::const_iterator point_it = _vector.begin(); point_it != _vector.end(); ++point_it) { + Geom::Coord A = (*point_it)[Geom::Y] * ((postmul.expansionX() + postmul.expansionY()) / 2); + result.push_back(Geom::Point((*point_it)[Geom::X], A)); + } + param_set_and_write_new_value(result); } - /** call this method to recalculate the controlpoints such that they stay at the same location relative to the new path. Useful after adding/deleting nodes to the path.*/ void PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewise > const & pwd2_in) diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index 911bbc82d..70b22e27e 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -31,7 +31,7 @@ public: virtual Gtk::Widget * param_newWidget(); - virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); + virtual void param_transform_multiply(Geom::Affine const& postmul, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); -- cgit v1.2.3 From faec2fcff4372e4ee4ce4e967b95747e3c52c241 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 29 Sep 2014 04:01:20 +0200 Subject: this patch fix the problem whith clips and mask update in live effects. More info in the bug: https://bugs.launchpad.net/inkscape/+bug/1241902 (bzr r13341.1.229) --- src/live_effects/lpe-bendpath.cpp | 3 +++ src/live_effects/lpe-envelope-perspective.cpp | 3 +++ src/live_effects/lpe-envelope.cpp | 5 ++++- src/live_effects/lpe-lattice.cpp | 3 +++ src/live_effects/lpe-lattice2.cpp | 3 +++ src/live_effects/lpe-mirror_symmetry.cpp | 8 ++++++++ src/live_effects/lpe-mirror_symmetry.h | 2 ++ src/live_effects/lpe-offset.cpp | 8 ++++++++ src/live_effects/lpe-offset.h | 2 ++ src/live_effects/lpe-perspective_path.cpp | 3 +++ src/live_effects/lpe-roughen.cpp | 5 ++++- src/live_effects/lpe-roughen.h | 2 +- src/live_effects/lpe-simplify.cpp | 3 +++ src/live_effects/lpe-vonkoch.cpp | 3 +++ 14 files changed, 50 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp index eaf9fe4a6..33171b184 100644 --- a/src/live_effects/lpe-bendpath.cpp +++ b/src/live_effects/lpe-bendpath.cpp @@ -76,6 +76,9 @@ LPEBendPath::doBeforeEffect (SPLPEItem const* lpeitem) { // get the item bounding box original_bbox(lpeitem); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } Geom::Piecewise > diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp index 3b91eb183..f847dddc5 100644 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ b/src/live_effects/lpe-envelope-perspective.cpp @@ -350,6 +350,9 @@ 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 diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp index 4f5623fba..05a672ae8 100644 --- a/src/live_effects/lpe-envelope.cpp +++ b/src/live_effects/lpe-envelope.cpp @@ -32,7 +32,7 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) : bend_path2(_("Right bend path:"), _("Right path along which to bend the original path"), "bendpath2", &wr, this, "M0,0 L1,0"), bend_path3(_("Bottom bend path:"), _("Bottom path along which to bend the original path"), "bendpath3", &wr, this, "M0,0 L1,0"), bend_path4(_("Left bend path:"), _("Left path along which to bend the original path"), "bendpath4", &wr, this, "M0,0 L1,0"), - xx(_("E_nable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true), + xx(_("_Enable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true), yy(_("_Enable top & bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true) { registerParameter( dynamic_cast(&yy) ); @@ -54,6 +54,9 @@ LPEEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) { // get the item bounding box original_bbox(lpeitem); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } Geom::Piecewise > diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index 8136569e8..a241a8a2e 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -176,6 +176,9 @@ void LPELattice::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } void diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index db609c9e1..9dad78f6e 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -254,6 +254,9 @@ LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); setDefaults(); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } void diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 4d4837d8d..0bb67a4a2 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -42,6 +42,14 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry() { } +void +LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) +{ + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); +} + void LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) { diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index c01d1bf6f..a4a2b86c0 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -30,6 +30,8 @@ public: virtual void doOnApply (SPLPEItem const* lpeitem); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual std::vector doEffect_path (std::vector const & path_in); private: diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index 192bd17ca..dc91775b7 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -55,6 +55,14 @@ static void append_half_circle(Geom::Piecewise > &pwd2, pwd2.continuousConcat(cap_pwd2); } +void +LPEOffset::doBeforeEffect (SPLPEItem const* lpeitem) +{ + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); +} + Geom::Piecewise > LPEOffset::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) { diff --git a/src/live_effects/lpe-offset.h b/src/live_effects/lpe-offset.h index 9966fd45d..997311c7d 100644 --- a/src/live_effects/lpe-offset.h +++ b/src/live_effects/lpe-offset.h @@ -28,6 +28,8 @@ public: virtual void doOnApply (SPLPEItem const* lpeitem); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); private: diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index 9e21f5d25..d43772cf7 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -90,6 +90,9 @@ LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem) SP_LPE_ITEM(lpeitem)->removeCurrentPathEffect(false); return; } + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index b9d575e06..ffd5433bf 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -71,11 +71,14 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) LPERoughen::~LPERoughen() {} -void LPERoughen::doBeforeEffect(SPLPEItem const */*lpeitem*/) +void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem) { displaceX.resetRandomizer(); displaceY.resetRandomizer(); srand(1); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } Gtk::Widget *LPERoughen::newWidget() diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index 7e99b47bf..d5ec726bd 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -38,7 +38,7 @@ public: virtual void doEffect(SPCurve *curve); virtual double sign(double randNumber); virtual Geom::Point randomize(); - virtual void doBeforeEffect(SPLPEItem const */*lpeitem*/); + virtual void doBeforeEffect(SPLPEItem const * lpeitem); virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t); virtual SPCurve *jitter(const Geom::Curve *A); virtual Geom::Point tpoint(Geom::Point A, Geom::Point B, double t = 0.5); diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index a817f30f1..c191fbbe6 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -65,6 +65,9 @@ LPESimplify::doBeforeEffect (SPLPEItem const* lpeitem) hp.clear(); } bbox = SP_ITEM(lpeitem)->visualBounds(); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 8b0b716fe..7c1913076 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -264,6 +264,9 @@ LPEVonKoch::doBeforeEffect (SPLPEItem const* lpeitem) tmp_pathv.push_back(tmp_path); ref_path.set_new_value(tmp_pathv,true); } + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } -- cgit v1.2.3 From 17a960347e5c93f5a4ebf784ee46cd982c476d07 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 29 Sep 2014 05:59:56 +0200 Subject: A little fix in fillet-chamfer to hide knot helper path at hide the knots (bzr r13341.1.230) --- src/live_effects/lpe-fillet-chamfer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 4e7d62ff5..3f1fa382e 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -455,7 +455,11 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) { if (SP_IS_SHAPE(lpeItem)) { - fillet_chamfer_values.set_helper_size(helper_size); + if(hide_knots){ + fillet_chamfer_values.set_helper_size(0); + } else { + fillet_chamfer_values.set_helper_size(helper_size); + } fillet_chamfer_values.set_use_distance(use_knot_distance); fillet_chamfer_values.set_unit(unit.get_abbreviation()); SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem) -- cgit v1.2.3 From c257c4b640056415043e798da9039e0b5b4caaa9 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 30 Sep 2014 01:42:55 +0200 Subject: add support for document-units in the helper path of bspline (bzr r13341.1.234) --- src/live_effects/lpe-bspline.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 5dfad95dc..e8df6e464 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -39,9 +39,11 @@ #include "desktop-handles.h" #include "verbs.h" #include "sp-lpe-item.h" +#include "sp-namedview.h" #include "display/sp-canvas.h" #include #include +#include "util/units.h" // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" @@ -117,8 +119,11 @@ void LPEBSpline::doEffect(SPCurve *curve) curve->reset(); double radiusHelperNodes = 6.0; - if (SP_ACTIVE_DESKTOP) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop){ radiusHelperNodes /= SP_ACTIVE_DESKTOP->current_zoom(); + SPNamedView *nv = sp_desktop_namedview(desktop); + radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", nv->doc_units->abbr); } for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); @@ -264,7 +269,9 @@ LPEBSpline::drawHandle(Geom::Point p, double radiusHelperNodes) { char const * svgd = "M 1,0.5 A 0.5,0.5 0 0 1 0.5,1 0.5,0.5 0 0 1 0,0.5 0.5,0.5 0 0 1 0.5,0 0.5,0.5 0 0 1 1,0.5 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Affine(radiusHelperNodes,0,0,radiusHelperNodes,0,0); + Geom::Affine aff = Geom::Affine(); + aff *= Geom::Scale(radiusHelperNodes); + pathv *= aff; pathv += p - Geom::Point(0.5*radiusHelperNodes, 0.5*radiusHelperNodes); hp.push_back(pathv[0]); } -- cgit v1.2.3 From 50a19700fb02a712803aa3623f0920d562116534 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Thu, 2 Oct 2014 10:32:46 +0200 Subject: i18n. Fix for Bug #380522 (strings that need to be fixed for translation). Translations. Inkscape.pot and French translation update. Fixed bugs: - https://launchpad.net/bugs/380522 (bzr r13576) --- src/live_effects/lpe-ruler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp index 788ab593a..fd611c78d 100644 --- a/src/live_effects/lpe-ruler.cpp +++ b/src/live_effects/lpe-ruler.cpp @@ -29,7 +29,7 @@ static const Util::EnumData MarkDirData[] = { static const Util::EnumDataConverter MarkDirTypeConverter(MarkDirData, sizeof(MarkDirData)/sizeof(*MarkDirData)); static const Util::EnumData BorderMarkData[] = { - {BORDERMARK_NONE , N_("None"), "none"}, + {BORDERMARK_NONE , NC_("Border mark", "None"), "none"}, {BORDERMARK_START , N_("Start"), "start"}, {BORDERMARK_END , N_("End"), "end"}, {BORDERMARK_BOTH , N_("Both"), "both"}, -- cgit v1.2.3 From 156cf3323a936c7dfccd9e09458cd8b5d174b7fe Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 5 Oct 2014 19:24:27 -0400 Subject: Move more UI code into ui/ (bzr r13341.1.253) --- src/live_effects/effect.cpp | 2 +- src/live_effects/lpe-envelope-perspective.cpp | 2 +- src/live_effects/lpe-fillet-chamfer.cpp | 2 +- src/live_effects/lpe-lattice2.cpp | 2 +- src/live_effects/parameter/path.cpp | 4 ++-- src/live_effects/parameter/pointreseteable.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 3e3f8540a..0885ad6f0 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -74,7 +74,7 @@ #include "xml/document.h" #include #include "ui/tools/pen-tool.h" -#include "tools-switch.h" +#include "ui/tools-switch.h" #include "message-stack.h" #include "desktop.h" #include "knotholder.h" diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp index f847dddc5..c62dbbf6a 100644 --- a/src/live_effects/lpe-envelope-perspective.cpp +++ b/src/live_effects/lpe-envelope-perspective.cpp @@ -19,7 +19,7 @@ #include "helper/geom.h" #include "display/curve.h" #include "svg/svg.h" -#include +#include "ui/tools-switch.h" #include #include "desktop.h" diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 3f1fa382e..f15bf9215 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -29,7 +29,7 @@ // for programmatically updating knots #include "selection.h" -#include "tools-switch.h" +#include "ui/tools-switch.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/selectable-control-point.h" #include "ui/tool/node.h" diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index 9dad78f6e..8fadd79ed 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -32,7 +32,7 @@ #include <2geom/d2.h> #include <2geom/piecewise.h> #include <2geom/transforms.h> -#include +#include "ui/tools-switch.h" #include "desktop.h" // TODO: should be factored out (see below) diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 8095056b7..74d99918a 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -28,8 +28,8 @@ #include "document-undo.h" // needed for on-canvas editting: -#include "tools-switch.h" -#include "shape-editor.h" +#include "ui/tools-switch.h" +#include "ui/shape-editor.h" #include "desktop-handles.h" #include "selection.h" // clipboard support diff --git a/src/live_effects/parameter/pointreseteable.cpp b/src/live_effects/parameter/pointreseteable.cpp index ec36fc035..c0f8858b8 100644 --- a/src/live_effects/parameter/pointreseteable.cpp +++ b/src/live_effects/parameter/pointreseteable.cpp @@ -15,7 +15,7 @@ #include "verbs.h" #include "knotholder.h" #include -#include "tools-switch.h" +#include "ui/tools-switch.h" #include "ui/tools/node-tool.h" // needed for on-canvas editting: -- cgit v1.2.3 From ccb75de1cadbe4c2e8ad833cbbcd1bc8f79cd548 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 11 Oct 2014 19:21:54 +0200 Subject: LPEVonKoch : remove redundant assignment (is taken care of by the following if-statement) Found by clang static analyzer (bzr r13589) --- src/live_effects/lpe-vonkoch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 8b0b716fe..7e396e84a 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -133,7 +133,7 @@ LPEVonKoch::doEffect_path (std::vector const & path_in) for (unsigned k = 0; k < path_in.size(); k++){ path_in_complexity+=path_in[k].size(); } - double complexity = std::pow(transforms.size(),nbgenerations)*path_in_complexity; + double complexity; if (drawall.get_value()){ int k = transforms.size(); if(k>1){ -- cgit v1.2.3 From f369e0ed4157c33e09c426b40ec1e39c7591d2c6 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 12 Oct 2014 12:04:17 +0200 Subject: LPEVonKoch: improve rev. 13589 by removing the else branch for complexity calculation for better human readability (bzr r13591) --- src/live_effects/lpe-vonkoch.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 7e396e84a..709c9e56e 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -132,8 +132,8 @@ LPEVonKoch::doEffect_path (std::vector const & path_in) int path_in_complexity = 0; for (unsigned k = 0; k < path_in.size(); k++){ path_in_complexity+=path_in[k].size(); - } - double complexity; + } + double complexity = std::pow(transforms.size(), nbgenerations) * path_in_complexity; if (drawall.get_value()){ int k = transforms.size(); if(k>1){ @@ -141,8 +141,6 @@ LPEVonKoch::doEffect_path (std::vector const & path_in) }else{ complexity = nbgenerations*k*path_in_complexity; } - }else{ - complexity = std::pow(transforms.size(),nbgenerations)*path_in_complexity; } if (complexity > double(maxComplexity)){ g_warning("VonKoch lpe's output too complex. Effect bypassed."); -- cgit v1.2.3 From 14a9c655de4723dda0c280f4717f2b29d46287a1 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 16 Oct 2014 15:27:50 +0200 Subject: Update to bspline branch, now helper path fixed and optional (bzr r13341.1.275) --- src/live_effects/lpe-bspline.cpp | 126 ++++++++++++++++++++++++++------------- src/live_effects/lpe-bspline.h | 18 +++--- 2 files changed, 94 insertions(+), 50 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index e8df6e464..b68799d08 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -59,17 +59,22 @@ const double noPower = 0.0; const double defaultStartPower = 0.3334; const double defaultEndPower = 0.6667; -LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), - ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), - onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, defaultStartPower) +LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + // initialise your parameters here: + //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, + //Geom::Point(100,100)), + steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), + ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), + onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), + showHelper(_("Show helper paths"), _("Show helper paths"), "showHelper", &wr, this, false), + weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, defaultStartPower) { - registerParameter(&weight); - registerParameter(&steps); - registerParameter(&ignoreCusp); - registerParameter(&onlySelected); + registerParameter(dynamic_cast(&weight)); + registerParameter(dynamic_cast(&steps)); + registerParameter(dynamic_cast(&ignoreCusp)); + registerParameter(dynamic_cast(&onlySelected)); + registerParameter(dynamic_cast(&showHelper)); weight.param_set_range(noPower, 1); weight.param_set_increments(0.1, 0.1); @@ -89,7 +94,9 @@ void LPEBSpline::doBeforeEffect (SPLPEItem const* lpeitem) } } -void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) + +void LPEBSpline::createAndApply(const char *name, SPDocument *doc, + SPItem *item) { if (!SP_IS_SHAPE(item)) { g_warning("LPE BSpline can only be applied to shapes (not groups)."); @@ -99,7 +106,8 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); repr->setAttribute("effect", name); - doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to and assigns the 'id' attribute + doc->getDefs()->getRepr() + ->addChild(repr, NULL); // adds to and assigns the 'id' attribute const gchar *repr_id = repr->attribute("id"); Inkscape::GC::release(repr); @@ -111,13 +119,13 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item) void LPEBSpline::doEffect(SPCurve *curve) { + if (curve->get_segment_count() < 1){ return; } - + // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); - double radiusHelperNodes = 6.0; SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (desktop){ @@ -125,7 +133,6 @@ void LPEBSpline::doEffect(SPCurve *curve) SPNamedView *nv = sp_desktop_namedview(desktop); radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", nv->doc_units->abbr); } - for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -133,7 +140,7 @@ void LPEBSpline::doEffect(SPCurve *curve) 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(); + Geom::Path::const_iterator curve_endit = path_it->end_default(); SPCurve *nCurve = new SPCurve(); Geom::Point previousNode(0, 0); Geom::Point node(0, 0); @@ -145,13 +152,29 @@ void LPEBSpline::doEffect(SPCurve *curve) Geom::D2 SBasisHelper; Geom::CubicBezier const *cubic = NULL; if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_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(); } } + //Si la curva está cerrada calculamos el punto donde + //deveria estar el nodo BSpline de cierre/inicio de la curva + //en posible caso de que se cierre con una linea recta creando un nodo + //BSPline nCurve->moveto(curve_it1->initialPoint()); + //Recorremos todos los segmentos menos el último while (curve_it1 != curve_endit) { + //previousPointAt3 = pointAt3; + //Calculamos los puntos que dividirían en tres segmentos iguales el path + //recto de entrada y de salida SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); @@ -192,7 +215,6 @@ void LPEBSpline::doEffect(SPCurve *curve) out->reset(); delete out; } - Geom::Point startNode = path_it->begin()->initialPoint(); if (path_it->closed() && curve_it2 == curve_endit) { SPCurve *start = new SPCurve(); start->moveto(path_it->begin()->initialPoint()); @@ -225,9 +247,9 @@ void LPEBSpline::doEffect(SPCurve *curve) SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); delete lineHelper; - startNode = SBasisHelper.valueAt(0.5); - nCurve->curveto(pointAt1, pointAt2, startNode); - nCurve->move_endpoints(startNode, startNode); + node = SBasisHelper.valueAt(0.5); + nCurve->curveto(pointAt1, pointAt2, node); + nCurve->move_endpoints(node, node); } else if ( curve_it2 == curve_endit) { nCurve->curveto(pointAt1, pointAt2, curve_it1->finalPoint()); nCurve->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint()); @@ -238,17 +260,26 @@ void LPEBSpline::doEffect(SPCurve *curve) SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); delete lineHelper; + //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de + //principio de curva previousNode = node; + //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); Geom::CubicBezier const *cubic2 = dynamic_cast(&*curve_it1); if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) { node = curve_it1->finalPoint(); } nCurve->curveto(pointAt1, pointAt2, node); - if(!are_near(node,curve_it1->finalPoint())){ - drawHandle(node, radiusHelperNodes); - } } + if(!are_near(node,curve_it1->finalPoint()) && showHelper){ + drawHandle(node, radiusHelperNodes); + } + //La curva BSpline se forma calculando el centro del segmanto de unión + //de el punto situado en las 2/3 partes de el segmento de entrada + //con el punto situado en la posición 1/3 del segmento de salida + //Estos dos puntos ademas estan posicionados en el lugas correspondiente + //de los manejadores de la curva + //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; } @@ -259,6 +290,8 @@ void LPEBSpline::doEffect(SPCurve *curve) curve->append(nCurve, false); nCurve->reset(); delete nCurve; + } + if(showHelper){ Geom::PathVector const pathv = curve->get_pathvector(); hp.push_back(pathv[0]); } @@ -293,32 +326,44 @@ Gtk::Widget *LPEBSpline::newWidget() while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter *param = *it; - Gtk::Widget *widg = Gtk::manage(param->param_newWidget()); + Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); if (param->param_key == "weight") { - Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true, 0)); - - Gtk::Button *defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); - defaultWeight->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::Button *defaultWeight = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight")))); + defaultWeight->signal_clicked() + .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); buttons->pack_start(*defaultWeight, true, true, 2); - - Gtk::Button *makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); - makeCusp->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); + Gtk::Button *makeCusp = + Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); + makeCusp->signal_clicked() + .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); buttons->pack_start(*makeCusp, true, true, 2); - vbox->pack_start(*buttons, true, true, 2); } if (param->param_key == "weight" || param->param_key == "steps") { - Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); - + Inkscape::UI::Widget::Scalar *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed() + .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight)); + widg = dynamic_cast(widgRegistered); if (widg) { Gtk::HBox * scalarParameter = dynamic_cast(widg); - std::vector childList = scalarParameter->get_children(); + std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); Gtk::Entry* entryWidg = dynamic_cast(childList[1]); entryWidg->set_width_chars(6); } } - + if (param->param_key == "onlySelected") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } + if (param->param_key == "ignoreCusp") { + Gtk::CheckButton *widgRegistered = + Gtk::manage(dynamic_cast(widg)); + widg = dynamic_cast(widgRegistered); + } Glib::ustring *tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -333,7 +378,7 @@ Gtk::Widget *LPEBSpline::newWidget() ++it; } - return vbox; + return dynamic_cast(vbox); } void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) @@ -379,7 +424,8 @@ void LPEBSpline::changeWeight(double weightValue) g_free(str); curve->unref(); desktop->clearWaitingCursor(); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, _("Modified the weight of a BSpline")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, + _("Modified the weight of the BSpline")); } bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index e066015ad..169658b94 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -24,19 +24,16 @@ public: return SUPPRESS_FLASH; } virtual void doEffect(SPCurve *curve); - virtual void doBeforeEffect(SPLPEItem const* lpeitem); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); void drawHandle(Geom::Point p, double radiusHelperNodes); void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); - - void doBSplineFromWidget(SPCurve *curve, double value); - bool nodeIsSelected(Geom::Point nodePoint); - + virtual void doBSplineFromWidget(SPCurve *curve, double value); + virtual bool nodeIsSelected(Geom::Point nodePoint); virtual Gtk::Widget *newWidget(); - - void changeWeight(double weightValue); - void toDefaultWeight(Gtk::Widget *widgWeight); - void toMakeCusp(Gtk::Widget *widgWeight); - void toWeight(); + virtual void changeWeight(double weightValue); + virtual void toDefaultWeight(Gtk::Widget *widgWeight); + virtual void toMakeCusp(Gtk::Widget *widgWeight); + virtual void toWeight(); // TODO make this private ScalarParam steps; @@ -45,6 +42,7 @@ private: std::vector points; BoolParam ignoreCusp; BoolParam onlySelected; + BoolParam showHelper; ScalarParam weight; Geom::PathVector hp; -- cgit v1.2.3 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/live_effects') 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 From fa5fb39f8c780f78da13545ece947f167d4324b2 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 18 Oct 2014 16:46:03 +0200 Subject: Fix LPE Powerstroke unintuitive / unstable / scale-dependent behavior (visible for example with Catmul-Rom interpolation) The instability happens when the width-value of adjacent control knots are the same. It's technical, but here goes quickly. Knots are treated as [offset along path, width] points. The offset along path is the segment number + the location along that segment. The width is (may not be true, but for ease of discussion) in canvas coordinates. This means that the interpolation is performed in a *very* compressed coordinate system, where the x-coords may range from, say, 0 to 5, and the y-coords from 0 to 2000. This is also scale dependent; changing the scale of your path and scaling all widths accordingly will change the look of your path. The fix now does the interpolation in a scaled coordinate system. It stretches the x-coordinates to the arclength of the path. After interpolation, the inverse scaling is applied to the interpolation result. (bzr r13341.1.279) --- src/live_effects/lpe-powerstroke.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 58d733b53..03a10807a 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -659,6 +659,15 @@ LPEPowerStroke::doEffect_path (std::vector const & path_in) ts.push_back( Point( pwd2_in.domain().max(), (end_linecap==LINECAP_ZERO_WIDTH) ? 0. : ts.back()[Geom::Y]) ); } + + // do the interpolation in a coordinate system that is more alike to the on-canvas knots, + // instead of the heavily compressed coordinate system of (segment_no offset, Y) in which the knots are stored + double pwd2_in_arclength = length(pwd2_in); + double xcoord_scaling = pwd2_in_arclength / ts.back()[Geom::X]; + for (std::size_t i = 0, e = ts.size(); i < e; ++i) { + ts[i][Geom::X] *= xcoord_scaling; + } + // create stroke path where points (x,y) := (t, offset) Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast(interpolator_type.get_value())); if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast(interpolator)) { @@ -670,6 +679,9 @@ LPEPowerStroke::doEffect_path (std::vector const & path_in) Geom::Path strokepath = interpolator->interpolateToPath(ts); delete interpolator; + // apply the inverse knot-xcoord scaling that was applied before the interpolation + strokepath *= Scale(1/xcoord_scaling, 1); + D2 > patternd2 = make_cuts_independent(strokepath.toPwSb()); Piecewise x = Piecewise(patternd2[0]); Piecewise y = Piecewise(patternd2[1]); -- cgit v1.2.3 From 3b585aa639d46417beb401847600e5918406e5c1 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 18 Oct 2014 17:03:29 +0200 Subject: LPE Powerstroke, editing behavior: implement scaling of strokepath width when the proportional-stroke-scaling toggle is on. Patch by Javier, tweaks by Johan. (bzr r13623) --- src/live_effects/parameter/powerstrokepointarray.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 647986da6..420195aa8 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -68,9 +68,23 @@ PowerStrokePointArrayParam::param_newWidget() } -void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) +void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const &postmul, bool /*set*/) { -// param_set_and_write_new_value( (*this) * postmul ); + // Check if proportional stroke-width scaling is on + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool transform_stroke = prefs ? prefs->getBool("/options/transform/stroke", true) : true; + if (transform_stroke) { + std::vector result; + result.reserve(_vector.size()); // reserve space for the points that will be added in the for loop + for (std::vector::const_iterator point_it = _vector.begin(), e = _vector.end(); + point_it != e; ++point_it) + { + // scale each width knot with the average scaling in X and Y + Geom::Coord const A = (*point_it)[Geom::Y] * ((postmul.expansionX() + postmul.expansionY()) / 2); + result.push_back(Geom::Point((*point_it)[Geom::X], A)); + } + param_set_and_write_new_value(result); + } } -- cgit v1.2.3 From 96ae336eb61517078d4ab86629908724824806a4 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 18 Oct 2014 17:10:19 +0200 Subject: noop: remove cruft from powerstrokepointarray.cpp (bzr r13624) --- .../parameter/powerstrokepointarray.cpp | 28 +--------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 420195aa8..964ab13b0 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -9,17 +9,13 @@ #include "live_effects/parameter/powerstrokepointarray.h" #include "live_effects/effect.h" -#include "svg/svg.h" -#include "svg/stringstream.h" #include "knotholder.h" #include "sp-lpe-item.h" #include <2geom/piecewise.h> #include <2geom/sbasis-geometric.h> -// needed for on-canvas editting: -#include "desktop.h" -#include "live_effects/lpeobject.h" +#include "preferences.h" // for proportional stroke/path scaling behavior namespace Inkscape { @@ -43,28 +39,6 @@ Gtk::Widget * PowerStrokePointArrayParam::param_newWidget() { return NULL; -/* - Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage( - new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label, - param_tooltip, - param_key, - *param_wr, - param_effect->getRepr(), - param_effect->getSPDoc() ) ); - // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Geom::Affine transf = desktop->doc2dt(); - pointwdg->setTransform(transf); - pointwdg->setValue( *this ); - pointwdg->clearProgrammatically(); - pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); - - Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); - static_cast(hbox)->pack_start(*pointwdg, true, true); - static_cast(hbox)->show_all_children(); - - return dynamic_cast (hbox); -*/ } -- cgit v1.2.3 From c47cd007e9edff7f57081124f6f2f15cdab3ba6b Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 23 Oct 2014 15:39:44 +0200 Subject: Update perspective-envelope to be affected by the clip or mask on LPE patch (bzr r13341.1.285) --- src/live_effects/lpe-perspective-envelope.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 249269b6f..4d8c79198 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -308,6 +308,9 @@ void LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); + SPLPEItem * item = const_cast(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); setDefaults(); } -- cgit v1.2.3 From 3eec2a62d7ae4c8e08c714647870bcd9e8d39298 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 30 Oct 2014 20:14:36 +0100 Subject: Fix a bug whith units pointed by suv (bzr r13647) --- src/live_effects/lpe-fillet-chamfer.cpp | 12 +++++++----- src/live_effects/parameter/filletchamferpointarray.cpp | 9 ++------- 2 files changed, 9 insertions(+), 12 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index f15bf9215..8a8f68d80 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -34,6 +34,7 @@ #include "ui/tool/selectable-control-point.h" #include "ui/tool/node.h" #include "ui/tools/node-tool.h" +#include // TODO due to internal breakage in glibmm headers, this must be last: #include @@ -172,9 +173,9 @@ void LPEFilletChamfer::toggleHide() for (std::vector::const_iterator point_it = filletChamferData.begin(); point_it != filletChamferData.end(); ++point_it) { if (hide_knots) { - result.push_back(Point((*point_it)[X], abs((*point_it)[Y]) * -1)); + result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]) * -1)); } else { - result.push_back(Point((*point_it)[X], abs((*point_it)[Y]))); + result.push_back(Point((*point_it)[X], std::abs((*point_it)[Y]))); } } fillet_chamfer_values.param_set_and_write_new_value(result); @@ -211,7 +212,8 @@ void LPEFilletChamfer::updateFillet() { double power = 0; if (!flexible) { - power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), "px") * -1; + Inkscape::Util::Unit const *doc_units = inkscape_active_desktop()->namedview->doc_units; + power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), doc_units->abbr) * -1; } else { power = radius; } @@ -589,11 +591,11 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } int type = 0; if(path_it->closed() && last){ - type = abs(filletChamferData[counter - counterCurves][Y]); + type = std::abs(filletChamferData[counter - counterCurves][Y]); } else if (!path_it->closed() && last){ //0 } else { - type = abs(filletChamferData[counter + 1][Y]); + type = std::abs(filletChamferData[counter + 1][Y]); } if (type == 3 || type == 4) { if (type == 4) { diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index e2b1aba61..db24a9735 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -175,13 +175,8 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( last_pathv[counterPaths][counter - offset].initialPoint(), 0.1))) { if ( curve_it2 == curve_endit) { - if (last_pathv[counterPaths].size() < pathv[counterPaths].size()) { - offset = abs(last_pathv[counterPaths].size() - - pathv[counterPaths].size()); - } else if (last_pathv[counterPaths].size() > - pathv[counterPaths].size()) { - offset = (abs(last_pathv[counterPaths].size() - - pathv[counterPaths].size())) * -1; + if (last_pathv[counterPaths].size() != pathv[counterPaths].size()) { + offset = (last_pathv[counterPaths].size() - pathv[counterPaths].size()) * -1; } else { offset = 0; } -- cgit v1.2.3 From ce8746d7fea95b874de630d77674cdd5cf736448 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Sat, 1 Nov 2014 08:18:51 -0700 Subject: Fixed 32-bit build break. (bzr r13650) --- src/live_effects/parameter/parameter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 7a2fd9769..beb750404 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -47,7 +47,7 @@ Parameter::param_write_to_repr(const char * svgd) // in gtk3, it is an issue: it allocates widget size for the maxmium // value you pass to it, leading to some insane lengths. // If you need this to be more, please be conservative about it. -const double SCALARPARAM_G_MAXDOUBLE = 10000000000; +const double SCALARPARAM_G_MAXDOUBLE = 10000000000.0; // TODO fixme: using an arbitrary large number as a magic value seems fragile. void Parameter::write_to_SVG(void) { -- cgit v1.2.3 From e8a542ff4fb18a78bed567eaee7b000581bdd825 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 1 Nov 2014 18:39:48 +0100 Subject: Fix a bug whith units pointed by suv in fillet-chamfer, affecting also to roughen, thanks to Ivan Louette for advert me (bzr r13651) --- src/live_effects/lpe-roughen.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index ffd5433bf..ae054fb8a 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -14,12 +14,13 @@ */ #include - +#include "desktop.h" #include "live_effects/lpe-roughen.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" #include "helper/geom.h" #include +#include #include namespace Inkscape { @@ -145,10 +146,11 @@ double LPERoughen::sign(double randNumber) Geom::Point LPERoughen::randomize() { + Inkscape::Util::Unit const *doc_units = inkscape_active_desktop()->namedview->doc_units; double displaceXParsed = Inkscape::Util::Quantity::convert( - displaceX, unit.get_abbreviation(), "px"); + displaceX, unit.get_abbreviation(), doc_units->abbr); double displaceYParsed = Inkscape::Util::Quantity::convert( - displaceY, unit.get_abbreviation(), "px"); + displaceY, unit.get_abbreviation(), doc_units->abbr); Geom::Point output = Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); return output; @@ -159,6 +161,7 @@ void LPERoughen::doEffect(SPCurve *curve) Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); curve->reset(); + Inkscape::Util::Unit const *doc_units = inkscape_active_desktop()->namedview->doc_units; for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -203,7 +206,7 @@ void LPERoughen::doEffect(SPCurve *curve) nCurve->lineto(A3); } double length = Inkscape::Util::Quantity::convert( - curve_it1->length(0.001), "px", unit.get_abbreviation()); + curve_it1->length(0.001), doc_units->abbr, unit.get_abbreviation()); std::size_t splits = 0; if (method == DM_SEGMENTS) { splits = segments; -- cgit v1.2.3 From 1784329fa3ac4a56944fe03a3b439c4fcd31dea1 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Sat, 1 Nov 2014 13:47:00 -0700 Subject: Warning cleanup. (bzr r13653) --- src/live_effects/lpe-bspline.cpp | 2 +- src/live_effects/parameter/filletchamferpointarray.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index b68799d08..e1ff49959 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -87,7 +87,7 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) LPEBSpline::~LPEBSpline() {} -void LPEBSpline::doBeforeEffect (SPLPEItem const* lpeitem) +void LPEBSpline::doBeforeEffect (SPLPEItem const* /*lpeitem*/) { if(!hp.empty()){ hp.clear(); diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index db24a9735..165dcd930 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -712,8 +712,8 @@ FilletChamferPointArrayParamKnotHolderEntity( : _pparam(p), _index(index) {} void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, - Point const &origin, - guint state) + Point const &/*origin*/, + guint /*state*/) { using namespace Geom; -- cgit v1.2.3 From d4056752d41865bf7b6890b14cbd00ae0fa1478f Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 1 Nov 2014 22:58:19 +0100 Subject: Fix a bug in perspective/envelope LPE, rendering points -handles- outside bounding box It affect to Envelope mode, sometimes give undesirable results, now fixed. (bzr r13655) --- src/live_effects/lpe-perspective-envelope.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 4d8c79198..0e620bc99 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -193,8 +193,8 @@ LPEPerspectiveEnvelope::project_point(Geom::Point p){ 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::Coord xratio = (delta_x * -1) / width; + Geom::Coord yratio = 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)); -- cgit v1.2.3 From c3cf3749afd1dddde094e4e1cf5e6c3285c03261 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 2 Nov 2014 01:19:42 +0100 Subject: Change calls to desktop with SP_ACTIVE_DESKTOP (bzr r13656) --- src/live_effects/lpe-bspline.cpp | 9 ++++----- src/live_effects/lpe-fillet-chamfer.cpp | 8 ++++---- src/live_effects/lpe-lattice2.cpp | 2 +- src/live_effects/lpe-perspective-envelope.cpp | 2 +- src/live_effects/lpe-roughen.cpp | 4 ++-- src/live_effects/lpe-simplify.cpp | 4 ++-- 6 files changed, 14 insertions(+), 15 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index e1ff49959..4f5ec2609 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -129,9 +129,8 @@ void LPEBSpline::doEffect(SPCurve *curve) double radiusHelperNodes = 6.0; SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (desktop){ - radiusHelperNodes /= SP_ACTIVE_DESKTOP->current_zoom(); - SPNamedView *nv = sp_desktop_namedview(desktop); - radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", nv->doc_units->abbr); + radiusHelperNodes /= desktop->current_zoom(); + radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", desktop->namedview->doc_units->abbr); } for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { @@ -408,7 +407,7 @@ void LPEBSpline::toWeight() void LPEBSpline::changeWeight(double weightValue) { - SPDesktop *desktop = inkscape_active_desktop(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList *items = (GSList *)selection->itemList(); SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; @@ -450,7 +449,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { using Geom::X; using Geom::Y; - SPDesktop *desktop = inkscape_active_desktop(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); Inkscape::UI::ControlPointSelection::Set &selection = diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 8a8f68d80..a3964f553 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -212,7 +212,7 @@ void LPEFilletChamfer::updateFillet() { double power = 0; if (!flexible) { - Inkscape::Util::Unit const *doc_units = inkscape_active_desktop()->namedview->doc_units; + Inkscape::Util::Unit const *doc_units = SP_ACTIVE_DESKTOP->namedview->doc_units; power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), doc_units->abbr) * -1; } else { power = radius; @@ -249,7 +249,7 @@ void LPEFilletChamfer::refreshKnots() { Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); fillet_chamfer_values.recalculate_knots(pwd2); - SPDesktop *desktop = inkscape_active_desktop(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (tools_isactive(desktop, TOOLS_NODES)) { tools_switch(desktop, TOOLS_SELECT); tools_switch(desktop, TOOLS_NODES); @@ -272,7 +272,7 @@ bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector const& original_pathv, double power) { std::vector point; - SPDesktop *desktop = inkscape_active_desktop(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nodeTool = INK_NODE_TOOL(desktop->event_context); Inkscape::UI::ControlPointSelection::Set &selection = nodeTool->_selected_nodes->allPoints(); @@ -334,7 +334,7 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa void LPEFilletChamfer::doChangeType(std::vector const& original_pathv, int type) { std::vector point; - SPDesktop *desktop = inkscape_active_desktop(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nodeTool = INK_NODE_TOOL(desktop->event_context); diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index 8fadd79ed..e1cd91340 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -394,7 +394,7 @@ LPELattice2::resetGrid() grid_point32x33x34x35.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(); + SPDesktop * desktop = SP_ACTIVE_DESKTOP; tools_switch(desktop, TOOLS_SELECT); tools_switch(desktop, TOOLS_NODES); } diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 0e620bc99..b5ef26e2f 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -337,7 +337,7 @@ LPEPerspectiveEnvelope::resetGrid() 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(); + SPDesktop * desktop = SP_ACTIVE_DESKTOP; tools_switch(desktop, TOOLS_SELECT); tools_switch(desktop, TOOLS_NODES); } diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index ae054fb8a..7ebd61c13 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -146,7 +146,7 @@ double LPERoughen::sign(double randNumber) Geom::Point LPERoughen::randomize() { - Inkscape::Util::Unit const *doc_units = inkscape_active_desktop()->namedview->doc_units; + Inkscape::Util::Unit const *doc_units = SP_ACTIVE_DESKTOP->namedview->doc_units; double displaceXParsed = Inkscape::Util::Quantity::convert( displaceX, unit.get_abbreviation(), doc_units->abbr); double displaceYParsed = Inkscape::Util::Quantity::convert( @@ -161,7 +161,7 @@ void LPERoughen::doEffect(SPCurve *curve) Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); curve->reset(); - Inkscape::Util::Unit const *doc_units = inkscape_active_desktop()->namedview->doc_units; + Inkscape::Util::Unit const *doc_units = SP_ACTIVE_DESKTOP->namedview->doc_units; for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index c191fbbe6..2b2efb1a9 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -157,8 +157,8 @@ LPESimplify::doEffect(SPCurve *curve) { Geom::PathVector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); generateHelperPath(outres); curve->set_pathvector(outres); - if(SP_ACTIVE_DESKTOP && INK_IS_NODE_TOOL(SP_ACTIVE_DESKTOP->event_context)){ - SPDesktop* desktop = SP_ACTIVE_DESKTOP; + SPDesktop* desktop = SP_ACTIVE_DESKTOP; + if(desktop && INK_IS_NODE_TOOL(desktop->event_context)){ Inkscape::UI::Tools::NodeTool *nt = static_cast(desktop->event_context); nt->update_helperpath(); } -- cgit v1.2.3 From 6f44b427bfd81fb7067f880ce75c03cc77b9046c Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 3 Nov 2014 19:14:04 +0100 Subject: Fix a bug pointed by Ivan Louette about strage fixed angle displazements (bzr r13663) --- src/live_effects/lpe-roughen.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 7ebd61c13..a11a06ce7 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -188,6 +188,7 @@ void LPERoughen::doEffect(SPCurve *curve) Geom::Point A1(0, 0); Geom::Point A2(0, 0); Geom::Point A3(0, 0); + bool first = true; while (curve_it1 != curve_endit) { Geom::CubicBezier const *cubic = NULL; A0 = curve_it1->initialPoint(); @@ -197,7 +198,7 @@ void LPERoughen::doEffect(SPCurve *curve) cubic = dynamic_cast(&*curve_it1); if (cubic) { A1 = (*cubic)[1]; - if (shiftNodes) { + if (shiftNodes && first) { A1 = (*cubic)[1] + initialMove; } A2 = (*cubic)[2]; @@ -235,6 +236,7 @@ void LPERoughen::doEffect(SPCurve *curve) if(curve_it2 != curve_endit) { ++curve_it2; } + first = false; } if (path_it->closed()) { nCurve->closepath_current(); -- cgit v1.2.3 From 3dfff76972208b0328ac7937bb9e9fe037560a26 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 3 Nov 2014 21:54:01 +0100 Subject: Update fillet/chamfer to allow subdivisions in chamfer mode. Still happends bug affecting only selected nodes in document:units diferent than "px". I think the problem is node->position() send me a bad data if document units not px. (bzr r13665) --- src/live_effects/lpe-fillet-chamfer.cpp | 59 +++++++++++++--------- src/live_effects/lpe-fillet-chamfer.h | 2 +- .../parameter/filletchamferpointarray.cpp | 22 ++++---- .../parameter/filletchamferpointarray.h | 2 + 4 files changed, 50 insertions(+), 35 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index a3964f553..240e2e2d9 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -65,12 +65,15 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : unit(_("Unit"), _("Unit"), "unit", &wr, this), method(_("Method"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO), radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), + chamferSteps(_("Chamfer steps"), _("Chamfer steps"), "chamferSteps", &wr, this, 0), + helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) { registerParameter(&fillet_chamfer_values); registerParameter(&unit); registerParameter(&method); registerParameter(&radius); + registerParameter(&chamferSteps); registerParameter(&helper_size); registerParameter(&flexible); registerParameter(&use_knot_distance); @@ -81,6 +84,9 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); + chamferSteps.param_set_range(0, infinity()); + chamferSteps.param_set_increments(1, 1); + chamferSteps.param_set_digits(0); helper_size.param_set_range(0, infinity()); helper_size.param_set_increments(5, 5); helper_size.param_set_digits(0); @@ -112,6 +118,16 @@ Gtk::Widget *LPEFilletChamfer::newWidget() Gtk::Entry *entryWidg = dynamic_cast(childList[1]); entryWidg->set_width_chars(6); } + } else if (param->param_key == "chamferSteps") { + Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + widg = widgRegistered; + if (widg) { + Gtk::HBox *scalarParameter = dynamic_cast(widg); + std::vector childList = scalarParameter->get_children(); + Gtk::Entry *entryWidg = dynamic_cast(childList[1]); + entryWidg->set_width_chars(3); + } } else if (param->param_key == "flexible") { Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast(widg)); widgRegistered->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::toggleFlexFixed)); @@ -142,26 +158,20 @@ Gtk::Widget *LPEFilletChamfer::newWidget() ++it; } - Gtk::HBox *filletButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); + Gtk::VBox *buttonsContainer = Gtk::manage(new Gtk::VBox(true, 0)); Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); - filletButtonsContainer->pack_start(*fillet, true, true, 2); + buttonsContainer->pack_start(*fillet, true, true, 2); Gtk::Button *inverse = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); inverse->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse)); - filletButtonsContainer->pack_start(*inverse, true, true, 2); + buttonsContainer->pack_start(*inverse, true, true, 2); - Gtk::HBox *chamferButtonsContainer = Gtk::manage(new Gtk::HBox(true, 0)); Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + buttonsContainer->pack_start(*chamfer, true, true, 2); - chamferButtonsContainer->pack_start(*chamfer, true, true, 2); - Gtk::Button *doubleChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Double chamfer")))); - doubleChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::doubleChamfer)); - chamferButtonsContainer->pack_start(*doubleChamfer, true, true, 2); - - vbox->pack_start(*filletButtonsContainer, true, true, 2); - vbox->pack_start(*chamferButtonsContainer, true, true, 2); + vbox->pack_start(*buttonsContainer, true, true, 2); return vbox; } @@ -236,13 +246,8 @@ void LPEFilletChamfer::inverse() void LPEFilletChamfer::chamfer() { Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 3); -} - -void LPEFilletChamfer::doubleChamfer() -{ - Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), 4); + doChangeType(path_from_piecewise(pwd2, tolerance), chamferSteps + 3); + fillet_chamfer_values.set_chamferSteps(chamferSteps + 3); } void LPEFilletChamfer::refreshKnots() @@ -597,11 +602,19 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } else { type = std::abs(filletChamferData[counter + 1][Y]); } - if (type == 3 || type == 4) { - if (type == 4) { - Geom::Point central = middle_point(startArcPoint, endArcPoint); - LineSegment chamferCenter(central, curve_it1->finalPoint()); - path_out.appendNew(chamferCenter.pointAt(0.5)); + if (type >= 3) { + unsigned int chamferSubs = type-2; + Geom::Path path_chamfer; + path_chamfer.start(path_out.finalPoint()); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ + path_chamfer.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + } else { + path_chamfer.appendNew(handle1, handle2, endArcPoint); + } + double chamferStepsTime = 1.0/chamferSubs; + for(unsigned int i = 1; i < chamferSubs; i++){ + Geom::Point chamferStep = path_chamfer.pointAt(chamferStepsTime * i); + path_out.appendNew(chamferStep); } path_out.appendNew(endArcPoint); } else if (type == 2) { diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 873684101..75d6b5f6b 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -57,7 +57,6 @@ public: void toggleFlexFixed(); void chamfer(); void fillet(); - void doubleChamfer(); void inverse(); void updateFillet(); void doUpdateFillet(std::vector const& original_pathv, double power); @@ -77,6 +76,7 @@ private: UnitParam unit; EnumParam method; ScalarParam radius; + ScalarParam chamferSteps; ScalarParam helper_size; LPEFilletChamfer(const LPEFilletChamfer &); diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 165dcd930..f43f6108d 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -359,6 +359,11 @@ void FilletChamferPointArrayParam::set_helper_size(int hs) helper_size = hs; } +void FilletChamferPointArrayParam::set_chamferSteps(int chamferSteps) +{ + chamfer_steps = chamferSteps; +} + void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) { use_distance = use_knot_distance; @@ -767,14 +772,17 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) }else{ using namespace Geom; double type = _pparam->_vector.at(_index)[Y] + 1; - if (type > 4) { + if (type > 3) { type = 1; } + if (type == 3){ + type = _pparam->chamfer_steps; + } _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type); _pparam->param_set_and_write_new_value(_pparam->_vector); sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); const gchar *tip; - if (type == 3) { + if (type >= 3) { tip = _("Chamfer: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); @@ -786,10 +794,6 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) tip = _("Fillet: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); - } else { - tip = _("Double Chamfer: Ctrl+Click toogle type, " - "Shift+Click open dialog, " - "Ctrl+Alt+Click reset"); } this->knot->tip = g_strdup(tip); this->knot->show(); @@ -835,7 +839,7 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, continue; } const gchar *tip; - if (_vector[i][Y] == 3) { + if (_vector[i][Y] >= 3) { tip = _("Chamfer: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); @@ -847,10 +851,6 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, tip = _("Fillet: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); - } else { - tip = _("Double Chamfer: Ctrl+Click toogle type, " - "Shift+Click open dialog, " - "Ctrl+Alt+Click reset"); } FilletChamferPointArrayParamKnotHolderEntity *e = new FilletChamferPointArrayParamKnotHolderEntity(this, i); diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index a1fa698ae..3ef52d11a 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -52,6 +52,7 @@ public: std::vector get_times(int index, std::vector subpaths, bool last); virtual void set_helper_size(int hs); virtual void set_use_distance(bool use_knot_distance); + virtual void set_chamferSteps(int chamferSteps); virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); @@ -85,6 +86,7 @@ private: SPKnotModeType knot_mode; guint32 knot_color; int helper_size; + int chamfer_steps; bool use_distance; const gchar *unit; Geom::PathVector hp; -- cgit v1.2.3 From c4c3db6548b086733031f8dbfe02ea17f3747b9d Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 3 Nov 2014 22:40:49 +0100 Subject: Added a extra layer of roughen pointed by Ivan Louette (bzr r13666) --- src/live_effects/lpe-roughen.cpp | 24 ++++++++++++++++++++++-- src/live_effects/lpe-roughen.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index a11a06ce7..b30fb4f1e 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -47,6 +47,8 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) "displaceX", &wr, this, 10.), displaceY(_("Max. displacement in Y"), _("Max. displacement in Y"), "displaceY", &wr, this, 10.), + globalRandomize(_("Global randomize"), _("Global randomize"), + "globalRandomize", &wr, this, 1.), shiftNodes(_("Shift nodes"), _("Shift nodes"), "shiftNodes", &wr, this, true), shiftNodeHandles(_("Shift node handles"), _("Shift node handles"), @@ -58,10 +60,12 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) registerParameter(&segments); registerParameter(&displaceX); registerParameter(&displaceY); + registerParameter(&globalRandomize); registerParameter(&shiftNodes); registerParameter(&shiftNodeHandles); displaceX.param_set_range(0., Geom::infinity()); displaceY.param_set_range(0., Geom::infinity()); + globalRandomize.param_set_range(0., Geom::infinity()); maxSegmentSize.param_set_range(0., Geom::infinity()); maxSegmentSize.param_set_increments(1, 1); maxSegmentSize.param_set_digits(1); @@ -76,6 +80,7 @@ void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem) { displaceX.resetRandomizer(); displaceY.resetRandomizer(); + globalRandomize.resetRandomizer(); srand(1); SPLPEItem * item = const_cast(lpeitem); item->apply_to_clippath(item); @@ -119,6 +124,15 @@ Gtk::Widget *LPERoughen::newWidget() vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } + if (param->param_key == "globalRandomize") { + Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( + Glib::ustring(_("Extra roughen Retain 1 to no changes")), + Gtk::ALIGN_START)); + displaceXLabel->set_use_markup(true); + vbox->pack_start(*displaceXLabel, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } Glib::ustring *tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -147,10 +161,16 @@ double LPERoughen::sign(double randNumber) Geom::Point LPERoughen::randomize() { Inkscape::Util::Unit const *doc_units = SP_ACTIVE_DESKTOP->namedview->doc_units; + double displaceXRandom = displaceX; + double displaceYRandom = displaceY; + if(globalRandomize != 1.0){ + displaceXRandom = displaceX * globalRandomize; + displaceYRandom = displaceY * globalRandomize; + } double displaceXParsed = Inkscape::Util::Quantity::convert( - displaceX, unit.get_abbreviation(), doc_units->abbr); + displaceXRandom, unit.get_abbreviation(), doc_units->abbr); double displaceYParsed = Inkscape::Util::Quantity::convert( - displaceY, unit.get_abbreviation(), doc_units->abbr); + displaceYRandom, unit.get_abbreviation(), doc_units->abbr); Geom::Point output = Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); return output; diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index d5ec726bd..74331f1ef 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -51,8 +51,10 @@ private: ScalarParam segments; RandomParam displaceX; RandomParam displaceY; + RandomParam globalRandomize; BoolParam shiftNodes; BoolParam shiftNodeHandles; + LPERoughen(const LPERoughen &); LPERoughen &operator=(const LPERoughen &); -- cgit v1.2.3 From 39cda1b3f4b2444a99e7378f5853b3bbd578ae04 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 3 Nov 2014 22:50:33 +0100 Subject: A bit remove of unnecesary code (bzr r13667) --- src/live_effects/lpe-roughen.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index b30fb4f1e..07d9e63e8 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -126,7 +126,7 @@ Gtk::Widget *LPERoughen::newWidget() } if (param->param_key == "globalRandomize") { Gtk::Label *displaceXLabel = Gtk::manage(new Gtk::Label( - Glib::ustring(_("Extra roughen Retain 1 to no changes")), + Glib::ustring(_("Extra roughen Add a extra layer of rough")), Gtk::ALIGN_START)); displaceXLabel->set_use_markup(true); vbox->pack_start(*displaceXLabel, false, false, 2); @@ -161,16 +161,10 @@ double LPERoughen::sign(double randNumber) Geom::Point LPERoughen::randomize() { Inkscape::Util::Unit const *doc_units = SP_ACTIVE_DESKTOP->namedview->doc_units; - double displaceXRandom = displaceX; - double displaceYRandom = displaceY; - if(globalRandomize != 1.0){ - displaceXRandom = displaceX * globalRandomize; - displaceYRandom = displaceY * globalRandomize; - } double displaceXParsed = Inkscape::Util::Quantity::convert( - displaceXRandom, unit.get_abbreviation(), doc_units->abbr); + displaceX * globalRandomize, unit.get_abbreviation(), doc_units->abbr); double displaceYParsed = Inkscape::Util::Quantity::convert( - displaceYRandom, unit.get_abbreviation(), doc_units->abbr); + displaceY * globalRandomize, unit.get_abbreviation(), doc_units->abbr); Geom::Point output = Geom::Point(sign(displaceXParsed), sign(displaceYParsed)); return output; -- cgit v1.2.3 From 83f7ed76a1f5e92db4247ed4bb947fad591be50d Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 4 Nov 2014 00:02:08 +0100 Subject: Update wrong variable name and apply the same way to select nodes to fillet/chamfer and BSpline, still the boring bug -ignore apply only to selected nodes- when document not in 'px' (bzr r13668) --- src/live_effects/lpe-bspline.cpp | 23 ++++++++++++----------- src/live_effects/lpe-bspline.h | 3 +-- src/live_effects/lpe-fillet-chamfer.cpp | 22 +++++++++++----------- src/live_effects/lpe-fillet-chamfer.h | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 4f5ec2609..fcd01c3fb 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -427,14 +427,14 @@ void LPEBSpline::changeWeight(double weightValue) _("Modified the weight of the BSpline")); } -bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint) +bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints) { using Geom::X; using Geom::Y; - if (points.size() > 0) { - for (std::vector::iterator i = points.begin(); - i != points.end(); ++i) { + if (selectedPoints.size() > 0) { + for (std::vector::iterator i = selectedPoints.begin(); + i != selectedPoints.end(); ++i) { Geom::Point p = *i; if (Geom::are_near(p, nodePoint, handleCubicGap)) { return true; @@ -450,19 +450,20 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) using Geom::X; using Geom::Y; SPDesktop *desktop = SP_ACTIVE_DESKTOP; + std::vector selectedPoints; if (INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); Inkscape::UI::ControlPointSelection::Set &selection = nt->_selected_nodes->allPoints(); - points.clear(); + selectedPoints.clear(); std::vector::iterator pbegin; for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i) { if ((*i)->selected()) { Inkscape::UI::Node *n = dynamic_cast(*i); - pbegin = points.begin(); - points.insert(pbegin, desktop->doc2dt(n->position())); + pbegin = selectedPoints.begin(); + selectedPoints.insert(pbegin, desktop->doc2dt(n->position())); } } } @@ -571,7 +572,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } else { if (cubic) { if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - if (nodeIsSelected(pointAt0)) { + if (nodeIsSelected(pointAt0, selectedPoints)) { pointAt1 = SBasisIn.valueAt(weightValue); if (weightValue != noPower) { pointAt1 = @@ -584,7 +585,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt1 = in->first_segment()->initialPoint(); } if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - if (nodeIsSelected(pointAt3)) { + if (nodeIsSelected(pointAt3, selectedPoints)) { pointAt2 = SBasisIn.valueAt(1 - weightValue); if (weightValue != noPower) { pointAt2 = @@ -598,14 +599,14 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } } else { if (!ignoreCusp && weightValue != noPower) { - if (nodeIsSelected(pointAt0)) { + if (nodeIsSelected(pointAt0, selectedPoints)) { pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } else { pointAt1 = in->first_segment()->initialPoint(); } - if (nodeIsSelected(pointAt3)) { + if (nodeIsSelected(pointAt3, selectedPoints)) { pointAt2 = SBasisIn.valueAt(weightValue); pointAt2 = Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 169658b94..ca9ae06be 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -28,7 +28,7 @@ public: void drawHandle(Geom::Point p, double radiusHelperNodes); void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); virtual void doBSplineFromWidget(SPCurve *curve, double value); - virtual bool nodeIsSelected(Geom::Point nodePoint); + virtual bool nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints); virtual Gtk::Widget *newWidget(); virtual void changeWeight(double weightValue); virtual void toDefaultWeight(Gtk::Widget *widgWeight); @@ -39,7 +39,6 @@ public: ScalarParam steps; private: - std::vector points; BoolParam ignoreCusp; BoolParam onlySelected; BoolParam showHelper; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 240e2e2d9..da6819120 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -261,10 +261,10 @@ void LPEFilletChamfer::refreshKnots() } } -bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector point) +bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints) { - if (point.size() > 0) { - for (std::vector::iterator i = point.begin(); i != point.end(); + if (selectedPoints.size() > 0) { + for (std::vector::iterator i = selectedPoints.begin(); i != selectedPoints.end(); ++i) { Geom::Point p = *i; if (Geom::are_near(p, nodePoint, 2)) { @@ -276,7 +276,7 @@ bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector const& original_pathv, double power) { - std::vector point; + std::vector selectedPoints; SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nodeTool = INK_NODE_TOOL(desktop->event_context); @@ -285,8 +285,8 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i) { if ((*i)->selected()) { Inkscape::UI::Node *n = dynamic_cast(*i); - pBegin = point.begin(); - point.insert(pBegin, desktop->doc2dt(n->position())); + pBegin = selectedPoints.begin(); + selectedPoints.insert(pBegin, desktop->doc2dt(n->position())); } } } @@ -324,7 +324,7 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa if (filletChamferData[counter][Y] == 0) { powerend = filletChamferData[counter][X]; } - if (only_selected && !nodeIsSelected(curve_it1->initialPoint(), point)) { + if (only_selected && !nodeIsSelected(curve_it1->initialPoint(), selectedPoints)) { powerend = filletChamferData[counter][X]; } result.push_back(Point(powerend, filletChamferData[counter][Y])); @@ -338,7 +338,7 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa void LPEFilletChamfer::doChangeType(std::vector const& original_pathv, int type) { - std::vector point; + std::vector selectedPoints; SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (INK_IS_NODE_TOOL(desktop->event_context)) { Inkscape::UI::Tools::NodeTool *nodeTool = @@ -351,8 +351,8 @@ void LPEFilletChamfer::doChangeType(std::vector const& original_path i != selection.end(); ++i) { if ((*i)->selected()) { Inkscape::UI::Node *n = dynamic_cast(*i); - pBegin = point.begin(); - point.insert(pBegin, desktop->doc2dt(n->position())); + pBegin = selectedPoints.begin(); + selectedPoints.insert(pBegin, desktop->doc2dt(n->position())); } } } @@ -380,7 +380,7 @@ void LPEFilletChamfer::doChangeType(std::vector const& original_path (ignore_radius_0 && (filletChamferData[counter][X] == 0 || filletChamferData[counter][X] == counter)) || (only_selected && - !nodeIsSelected(curve_it1->initialPoint(), point))) { + !nodeIsSelected(curve_it1->initialPoint(), selectedPoints))) { toggle = false; } if (toggle) { diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 75d6b5f6b..25e619436 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -61,7 +61,7 @@ public: void updateFillet(); void doUpdateFillet(std::vector const& original_pathv, double power); void doChangeType(std::vector const& original_pathv, int type); - bool nodeIsSelected(Geom::Point nodePoint, std::vector points); + bool nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints); void refreshKnots(); FilletChamferPointArrayParam fillet_chamfer_values; -- cgit v1.2.3 From ff6f0db21af7e564e205dcec40a886ce2b674608 Mon Sep 17 00:00:00 2001 From: Masato Hashimoto Date: Wed, 5 Nov 2014 07:01:12 +0100 Subject: i18n. Fix for bug #1389509 (typos in trunk-r13669). (bzr r13670) --- src/live_effects/lpe-bspline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index fcd01c3fb..eb492b821 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -64,7 +64,7 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) // initialise your parameters here: //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this, //Geom::Point(100,100)), - steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2), + steps(_("Steps with CTRL:"), _("Change number of steps with CTRL pressed"), "steps", &wr, this, 2), ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true), onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false), showHelper(_("Show helper paths"), _("Show helper paths"), "showHelper", &wr, this, false), -- cgit v1.2.3 From f51e8d7c6b4e2caa9e470af674949f3cd1695bf5 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 5 Nov 2014 19:30:49 +0100 Subject: Refactor to remove references to Desktop/Ui in Effect, bspline and fillet-chamfer. Also fixed the selected node problem in units not px. Also fixed two var to not allow NULL pointed by Johan Engelen. (bzr r13672) --- src/live_effects/effect.cpp | 35 ++++- src/live_effects/effect.h | 8 +- src/live_effects/lpe-bspline.cpp | 151 +++------------------ src/live_effects/lpe-bspline.h | 7 +- src/live_effects/lpe-fillet-chamfer.cpp | 81 ++--------- src/live_effects/lpe-fillet-chamfer.h | 3 +- .../parameter/filletchamferpointarray.cpp | 28 ++-- .../parameter/filletchamferpointarray.h | 2 +- 8 files changed, 96 insertions(+), 219 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 1a64defd9..fbdc78f8a 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -75,8 +75,6 @@ #include #include "ui/tools/pen-tool.h" #include "ui/tools-switch.h" -#include "message-stack.h" -#include "desktop.h" #include "knotholder.h" #include "sp-lpe-item.h" #include "live_effects/lpeobject.h" @@ -370,6 +368,7 @@ Effect::Effect(LivePathEffectObject *lpeobject) { registerParameter( dynamic_cast(&is_visible) ); is_visible.widget_is_visible = false; + current_zoom = 0.0; } Effect::~Effect() @@ -398,6 +397,36 @@ Effect::doOnApply (SPLPEItem const*/*lpeitem*/) { } +void +Effect::setSelectedNodePoints(std::vector sNP) +{ + selectedNodesPoints = sNP; +} + +void +Effect::setCurrentZoom(double cZ) +{ + current_zoom = cZ; +} + +bool +Effect::isNodePointSelected(Geom::Point const &nodePoint) const +{ + if (selectedNodesPoints.size() > 0) { + for (std::vector::const_iterator i = selectedNodesPoints.begin(); + i != selectedNodesPoints.end(); ++i) { + Geom::Point p = *i; + std::cout << p << "p\n"; + p[Geom::X] = Inkscape::Util::Quantity::convert(p[Geom::X], "px", *defaultUnit); + p[Geom::Y] = Inkscape::Util::Quantity::convert(p[Geom::Y], "px", *defaultUnit); + if (Geom::are_near(p, nodePoint, 0.01)) { + return true; + } + } + } + return false; +} + /** * Is performed each time before the effect is updated. */ @@ -419,6 +448,7 @@ void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); + defaultUnit = &sp_lpe_item->document->getDefaultUnit()->abbr; /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); pathvector_before_effect = sp_curve->get_pathvector();*/ doOnApply(lpeitem); @@ -427,6 +457,7 @@ void Effect::doOnApply_impl(SPLPEItem const* lpeitem) void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); + defaultUnit = &sp_lpe_item->document->getDefaultUnit()->abbr; //printf("(SPLPEITEM*) %p\n", sp_lpe_item); sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); pathvector_before_effect = sp_curve->get_pathvector(); diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index a486e8491..7da76b267 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -13,6 +13,7 @@ #include "parameter/bool.h" #include "effect-enum.h" + #define LPE_CONVERSION_TOLERANCE 0.01 // FIXME: find good solution for this. class SPDocument; @@ -57,7 +58,9 @@ public: //of indirection is needed. We first call these methods, then the below. void doOnApply_impl(SPLPEItem const* lpeitem); void doBeforeEffect_impl(SPLPEItem const* lpeitem); - + void setCurrentZoom(double cZ); + void setSelectedNodePoints(std::vector sNP); + bool isNodePointSelected(Geom::Point const &nodePoint) const; virtual void doOnApply (SPLPEItem const* lpeitem); virtual void doBeforeEffect (SPLPEItem const* lpeitem); @@ -156,6 +159,9 @@ protected: bool concatenate_before_pwd2; SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. + Glib::ustring const * defaultUnit; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. + double current_zoom; + std::vector selectedNodesPoints; SPCurve * sp_curve; std::vector pathvector_before_effect; private: diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index eb492b821..97a4c6205 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -24,11 +24,6 @@ #include "live_effects/lpeobject.h" #include "live_effects/parameter/parameter.h" #include "ui/widget/scalar.h" -#include "ui/tool/node.h" -#include "ui/tools/node-tool.h" -#include "ui/tool/control-point-selection.h" -#include "ui/tool/selectable-control-point.h" -#include "selection.h" #include "xml/repr.h" #include "svg/svg.h" #include "sp-path.h" @@ -36,7 +31,6 @@ #include "document-private.h" #include "document.h" #include "document-undo.h" -#include "desktop-handles.h" #include "verbs.h" #include "sp-lpe-item.h" #include "sp-namedview.h" @@ -47,7 +41,6 @@ // For handling un-continuous paths: #include "message-stack.h" #include "inkscape.h" -#include "desktop.h" using Inkscape::DocumentUndo; @@ -127,11 +120,8 @@ void LPEBSpline::doEffect(SPCurve *curve) Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); double radiusHelperNodes = 6.0; - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (desktop){ - radiusHelperNodes /= desktop->current_zoom(); - radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", desktop->namedview->doc_units->abbr); - } + radiusHelperNodes /= current_zoom; + radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", *defaultUnit); for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -164,16 +154,8 @@ void LPEBSpline::doEffect(SPCurve *curve) curve_endit = path_it->end_open(); } } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último while (curve_it1 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path - //recto de entrada y de salida SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); @@ -259,10 +241,7 @@ void LPEBSpline::doEffect(SPCurve *curve) SBasisHelper = lineHelper->first_segment()->toSBasis(); lineHelper->reset(); delete lineHelper; - //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de - //principio de curva previousNode = node; - //Y este hará de final de curva node = SBasisHelper.valueAt(0.5); Geom::CubicBezier const *cubic2 = dynamic_cast(&*curve_it1); if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) { @@ -273,12 +252,6 @@ void LPEBSpline::doEffect(SPCurve *curve) if(!are_near(node,curve_it1->finalPoint()) && showHelper){ drawHandle(node, radiusHelperNodes); } - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de los manejadores de la curva - //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; } @@ -292,7 +265,7 @@ void LPEBSpline::doEffect(SPCurve *curve) } if(showHelper){ Geom::PathVector const pathv = curve->get_pathvector(); - hp.push_back(pathv[0]); + hp.push_back(pathv[0]); } } @@ -313,7 +286,6 @@ LPEBSpline::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vectorsignal_clicked() - .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg)); + .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight)); buttons->pack_start(*defaultWeight, true, true, 2); Gtk::Button *makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp")))); makeCusp->signal_clicked() - .connect(sigc::bind(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg)); + .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp)); buttons->pack_start(*makeCusp, true, true, 2); vbox->pack_start(*buttons, true, true, 2); } @@ -380,24 +352,14 @@ Gtk::Widget *LPEBSpline::newWidget() return dynamic_cast(vbox); } -void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight) +void LPEBSpline::toDefaultWeight() { - weight.param_set_value(defaultStartPower); changeWeight(defaultStartPower); - Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); - std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); - Gtk::Entry* entryWidg = dynamic_cast(childList[1]); - entryWidg->set_text("defaultStartPower"); } -void LPEBSpline::toMakeCusp(Gtk::Widget *widgWeight) +void LPEBSpline::toMakeCusp() { - weight.param_set_value(noPower); changeWeight(noPower); - Gtk::HBox * scalarParameter = dynamic_cast(widgWeight); - std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); - Gtk::Entry* entryWidg = dynamic_cast(childList[1]); - entryWidg->set_text("noPower"); } void LPEBSpline::toWeight() @@ -407,92 +369,33 @@ void LPEBSpline::toWeight() void LPEBSpline::changeWeight(double weightValue) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList *items = (GSList *)selection->itemList(); - SPItem *item = (SPItem *)g_slist_nth(items, 0)->data; - SPPath *path = SP_PATH(item); + SPPath *path = SP_PATH(sp_lpe_item); SPCurve *curve = path->get_curve_for_edit(); LPEBSpline::doBSplineFromWidget(curve, weightValue); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - nt->desktop->updateNow(); - } - g_free(str); - curve->unref(); - desktop->clearWaitingCursor(); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, - _("Modified the weight of the BSpline")); -} - -bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints) -{ - using Geom::X; - using Geom::Y; - - if (selectedPoints.size() > 0) { - for (std::vector::iterator i = selectedPoints.begin(); - i != selectedPoints.end(); ++i) { - Geom::Point p = *i; - if (Geom::are_near(p, nodePoint, handleCubicGap)) { - return true; - } else { - } - } - } - return false; } void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { using Geom::X; using Geom::Y; - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - std::vector selectedPoints; - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = - nt->_selected_nodes->allPoints(); - selectedPoints.clear(); - std::vector::iterator pbegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = - selection.begin(); - i != selection.end(); ++i) { - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast(*i); - pbegin = selectedPoints.begin(); - selectedPoints.insert(pbegin, desktop->doc2dt(n->position())); - } - } - } - //bool hasNodesSelected = LPEBspline::hasNodesSelected(); if (curve->get_segment_count() < 1) return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); - //Recorremos todos los paths a los que queremos aplicar el efecto, hasta el - //penúltimo 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()) + + if (path_it->empty()){ continue; - //Itreadores - - 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 - //Creamos las lineas rectas que unen todos los puntos del trazado y donde se - //calcularán - //los puntos clave para los manejadores. - //Esto hace que la curva BSpline no pierda su condición aunque se trasladen - //dichos manejadores + } + 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(); + SPCurve *nCurve = new SPCurve(); Geom::Point pointAt0(0, 0); Geom::Point pointAt1(0, 0); @@ -515,16 +418,8 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) curve_endit = path_it->end_open(); } } - //Si la curva está cerrada calculamos el punto donde - //deveria estar el nodo BSpline de cierre/inicio de la curva - //en posible caso de que se cierre con una linea recta creando un nodo - //BSPline nCurve->moveto(curve_it1->initialPoint()); - //Recorremos todos los segmentos menos el último while (curve_it1 != curve_endit) { - //previousPointAt3 = pointAt3; - //Calculamos los puntos que dividirían en tres segmentos iguales el path - //recto de entrada y de salida SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); in->lineto(curve_it1->finalPoint()); @@ -572,7 +467,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } else { if (cubic) { if (!ignoreCusp || !Geom::are_near((*cubic)[1], pointAt0)) { - if (nodeIsSelected(pointAt0, selectedPoints)) { + if (isNodePointSelected(pointAt0)) { pointAt1 = SBasisIn.valueAt(weightValue); if (weightValue != noPower) { pointAt1 = @@ -585,7 +480,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) pointAt1 = in->first_segment()->initialPoint(); } if (!ignoreCusp || !Geom::are_near((*cubic)[2], pointAt3)) { - if (nodeIsSelected(pointAt3, selectedPoints)) { + if (isNodePointSelected(pointAt3)) { pointAt2 = SBasisIn.valueAt(1 - weightValue); if (weightValue != noPower) { pointAt2 = @@ -599,14 +494,14 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } } else { if (!ignoreCusp && weightValue != noPower) { - if (nodeIsSelected(pointAt0, selectedPoints)) { + if (isNodePointSelected(pointAt0)) { pointAt1 = SBasisIn.valueAt(weightValue); pointAt1 = Geom::Point(pointAt1[X] + handleCubicGap, pointAt1[Y] + handleCubicGap); } else { pointAt1 = in->first_segment()->initialPoint(); } - if (nodeIsSelected(pointAt3, selectedPoints)) { + if (isNodePointSelected(pointAt3)) { pointAt2 = SBasisIn.valueAt(weightValue); pointAt2 = Geom::Point(pointAt2[X] + handleCubicGap, pointAt2[Y] + handleCubicGap); @@ -621,14 +516,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } in->reset(); delete in; - //La curva BSpline se forma calculando el centro del segmanto de unión - //de el punto situado en las 2/3 partes de el segmento de entrada - //con el punto situado en la posición 1/3 del segmento de salida - //Estos dos puntos ademas estan posicionados en el lugas correspondiente - //de - //los manejadores de la curva nCurve->curveto(pointAt1, pointAt2, pointAt3); - //aumentamos los valores para el siguiente paso en el bucle ++curve_it1; ++curve_it2; } @@ -638,7 +526,6 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) } else { nCurve->move_endpoints(path_it->begin()->initialPoint(), pointAt3); } - //y cerramos la curva if (path_it->closed()) { nCurve->closepath_current(); } diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index ca9ae06be..8751a5720 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -26,13 +26,12 @@ public: virtual void doEffect(SPCurve *curve); virtual void doBeforeEffect (SPLPEItem const* lpeitem); void drawHandle(Geom::Point p, double radiusHelperNodes); - void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); virtual void doBSplineFromWidget(SPCurve *curve, double value); - virtual bool nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints); + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); virtual Gtk::Widget *newWidget(); virtual void changeWeight(double weightValue); - virtual void toDefaultWeight(Gtk::Widget *widgWeight); - virtual void toMakeCusp(Gtk::Widget *widgWeight); + virtual void toDefaultWeight(); + virtual void toMakeCusp(); virtual void toWeight(); // TODO make this private diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index da6819120..c491ea858 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -28,12 +28,7 @@ #include "live_effects/parameter/filletchamferpointarray.h" // for programmatically updating knots -#include "selection.h" #include "ui/tools-switch.h" -#include "ui/tool/control-point-selection.h" -#include "ui/tool/selectable-control-point.h" -#include "ui/tool/node.h" -#include "ui/tools/node-tool.h" #include // TODO due to internal breakage in glibmm headers, this must be last: @@ -65,7 +60,7 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : unit(_("Unit"), _("Unit"), "unit", &wr, this), method(_("Method"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO), radius(_("Radius (unit or %)"), _("Radius, in unit or %"), "radius", &wr, this, 0.), - chamferSteps(_("Chamfer steps"), _("Chamfer steps"), "chamferSteps", &wr, this, 0), + chamfer_steps(_("Chamfer steps"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0), helper_size(_("Helper size with direction"), _("Helper size with direction"), "helper_size", &wr, this, 0) { @@ -73,7 +68,7 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : registerParameter(&unit); registerParameter(&method); registerParameter(&radius); - registerParameter(&chamferSteps); + registerParameter(&chamfer_steps); registerParameter(&helper_size); registerParameter(&flexible); registerParameter(&use_knot_distance); @@ -84,12 +79,13 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); - chamferSteps.param_set_range(0, infinity()); - chamferSteps.param_set_increments(1, 1); - chamferSteps.param_set_digits(0); + chamfer_steps.param_set_range(0, infinity()); + chamfer_steps.param_set_increments(1, 1); + chamfer_steps.param_set_digits(0); helper_size.param_set_range(0, infinity()); helper_size.param_set_increments(5, 5); helper_size.param_set_digits(0); + fillet_chamfer_values.set_chamfer_steps(3); } LPEFilletChamfer::~LPEFilletChamfer() {} @@ -118,7 +114,7 @@ Gtk::Widget *LPEFilletChamfer::newWidget() Gtk::Entry *entryWidg = dynamic_cast(childList[1]); entryWidg->set_width_chars(6); } - } else if (param->param_key == "chamferSteps") { + } else if (param->param_key == "chamfer_steps") { Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); widg = widgRegistered; @@ -222,8 +218,7 @@ void LPEFilletChamfer::updateFillet() { double power = 0; if (!flexible) { - Inkscape::Util::Unit const *doc_units = SP_ACTIVE_DESKTOP->namedview->doc_units; - power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), doc_units->abbr) * -1; + power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), *defaultUnit) * -1; } else { power = radius; } @@ -245,9 +240,9 @@ void LPEFilletChamfer::inverse() void LPEFilletChamfer::chamfer() { + fillet_chamfer_values.set_chamfer_steps(chamfer_steps + 3); Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamferSteps + 3); - fillet_chamfer_values.set_chamferSteps(chamferSteps + 3); + doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3); } void LPEFilletChamfer::refreshKnots() @@ -261,35 +256,8 @@ void LPEFilletChamfer::refreshKnots() } } -bool LPEFilletChamfer::nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints) -{ - if (selectedPoints.size() > 0) { - for (std::vector::iterator i = selectedPoints.begin(); i != selectedPoints.end(); - ++i) { - Geom::Point p = *i; - if (Geom::are_near(p, nodePoint, 2)) { - return true; - } - } - } - return false; -} void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pathv, double power) { - std::vector selectedPoints; - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nodeTool = INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = nodeTool->_selected_nodes->allPoints(); - std::vector::iterator pBegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i) { - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast(*i); - pBegin = selectedPoints.begin(); - selectedPoints.insert(pBegin, desktop->doc2dt(n->position())); - } - } - } std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; std::vector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); @@ -324,7 +292,7 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa if (filletChamferData[counter][Y] == 0) { powerend = filletChamferData[counter][X]; } - if (only_selected && !nodeIsSelected(curve_it1->initialPoint(), selectedPoints)) { + if (only_selected && !isNodePointSelected(curve_it1->initialPoint())) { powerend = filletChamferData[counter][X]; } result.push_back(Point(powerend, filletChamferData[counter][Y])); @@ -338,24 +306,6 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa void LPEFilletChamfer::doChangeType(std::vector const& original_pathv, int type) { - std::vector selectedPoints; - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (INK_IS_NODE_TOOL(desktop->event_context)) { - Inkscape::UI::Tools::NodeTool *nodeTool = - INK_NODE_TOOL(desktop->event_context); - Inkscape::UI::ControlPointSelection::Set &selection = - nodeTool->_selected_nodes->allPoints(); - std::vector::iterator pBegin; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = - selection.begin(); - i != selection.end(); ++i) { - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast(*i); - pBegin = selectedPoints.begin(); - selectedPoints.insert(pBegin, desktop->doc2dt(n->position())); - } - } - } std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; std::vector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); @@ -378,9 +328,8 @@ void LPEFilletChamfer::doChangeType(std::vector const& original_path bool toggle = true; if (filletChamferData[counter][Y] == 0 || (ignore_radius_0 && (filletChamferData[counter][X] == 0 || - filletChamferData[counter][X] == counter)) || - (only_selected && - !nodeIsSelected(curve_it1->initialPoint(), selectedPoints))) { + filletChamferData[counter][X] == counter)) || + (only_selected && !isNodePointSelected(curve_it1->initialPoint()))) { toggle = false; } if (toggle) { @@ -611,9 +560,9 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } else { path_chamfer.appendNew(handle1, handle2, endArcPoint); } - double chamferStepsTime = 1.0/chamferSubs; + double chamfer_stepsTime = 1.0/chamferSubs; for(unsigned int i = 1; i < chamferSubs; i++){ - Geom::Point chamferStep = path_chamfer.pointAt(chamferStepsTime * i); + Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); path_out.appendNew(chamferStep); } path_out.appendNew(endArcPoint); diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 25e619436..e3589197c 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -61,7 +61,6 @@ public: void updateFillet(); void doUpdateFillet(std::vector const& original_pathv, double power); void doChangeType(std::vector const& original_pathv, int type); - bool nodeIsSelected(Geom::Point nodePoint, std::vector selectedPoints); void refreshKnots(); FilletChamferPointArrayParam fillet_chamfer_values; @@ -76,7 +75,7 @@ private: UnitParam unit; EnumParam method; ScalarParam radius; - ScalarParam chamferSteps; + ScalarParam chamfer_steps; ScalarParam helper_size; LPEFilletChamfer(const LPEFilletChamfer &); diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index f43f6108d..31d996ad0 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -359,9 +359,9 @@ void FilletChamferPointArrayParam::set_helper_size(int hs) helper_size = hs; } -void FilletChamferPointArrayParam::set_chamferSteps(int chamferSteps) +void FilletChamferPointArrayParam::set_chamfer_steps(int value_chamfer_steps) { - chamfer_steps = chamferSteps; + chamfer_steps = value_chamfer_steps; } void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) @@ -771,14 +771,20 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); }else{ using namespace Geom; - double type = _pparam->_vector.at(_index)[Y] + 1; - if (type > 3) { - type = 1; + int type = (int)_pparam->_vector.at(_index)[Y]; + + switch(type){ + case 1: + type = 2; + break; + case 2: + type = _pparam->chamfer_steps; + break; + default: + type = 1; + break; } - if (type == 3){ - type = _pparam->chamfer_steps; - } - _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], type); + _pparam->_vector.at(_index) = Point(_pparam->_vector.at(_index)[X], (double)type); _pparam->param_set_and_write_new_value(_pparam->_vector); sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); const gchar *tip; @@ -790,7 +796,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) tip = _("Inverse Fillet: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); - } else if (type == 1) { + } else { tip = _("Fillet: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); @@ -847,7 +853,7 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, tip = _("Inverse Fillet: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); - } else if (_vector[i][Y] == 1) { + } else { tip = _("Fillet: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 3ef52d11a..1dd31d6d4 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -52,7 +52,7 @@ public: std::vector get_times(int index, std::vector subpaths, bool last); virtual void set_helper_size(int hs); virtual void set_use_distance(bool use_knot_distance); - virtual void set_chamferSteps(int chamferSteps); + virtual void set_chamfer_steps(int value_chamfer_steps); virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); -- cgit v1.2.3 From 044036e791bf9bd1644a194226cced94b2a09f08 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 8 Nov 2014 22:45:56 +0100 Subject: powerstroke: enable unset fill fallback when style is nullptr. fixes nullptr deref. (bzr r13686) --- src/live_effects/lpe-powerstroke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 03a10807a..f7fe9592d 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -277,7 +277,7 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.; SPCSSAttr *css = sp_repr_css_attr_new (); - if (true) { + if (lpeitem->style) { if (lpeitem->style->stroke.isPaintserver()) { SPPaintServer * server = lpeitem->style->getStrokePaintServer(); if (server) { -- cgit v1.2.3 From 05a8ca8653fefcdc59e3ee1d1416829ec2712c8f Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 10 Nov 2014 00:50:46 +0100 Subject: fix a bug pointed by su_v in fillet chamfer dialog, about units (bzr r13697) --- src/live_effects/effect.cpp | 1 - src/live_effects/lpe-fillet-chamfer.cpp | 1 + src/live_effects/parameter/filletchamferpointarray.cpp | 7 ++++++- src/live_effects/parameter/filletchamferpointarray.h | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index fbdc78f8a..ca3b29b66 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -416,7 +416,6 @@ Effect::isNodePointSelected(Geom::Point const &nodePoint) const for (std::vector::const_iterator i = selectedNodesPoints.begin(); i != selectedNodesPoints.end(); ++i) { Geom::Point p = *i; - std::cout << p << "p\n"; p[Geom::X] = Inkscape::Util::Quantity::convert(p[Geom::X], "px", *defaultUnit); p[Geom::Y] = Inkscape::Util::Quantity::convert(p[Geom::Y], "px", *defaultUnit); if (Geom::are_near(p, nodePoint, 0.01)) { diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index c491ea858..c89bfbd37 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -416,6 +416,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) } else { fillet_chamfer_values.set_helper_size(helper_size); } + fillet_chamfer_values.set_document_unit(defaultUnit); fillet_chamfer_values.set_use_distance(use_knot_distance); fillet_chamfer_values.set_unit(unit.get_abbreviation()); SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem) diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 31d996ad0..cf9ef3132 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -354,6 +354,11 @@ void FilletChamferPointArrayParam::set_pwd2( last_pwd2_normal = pwd2_normal_in; } +void FilletChamferPointArrayParam::set_document_unit(Glib::ustring const * value_document_unit) +{ + documentUnit = value_document_unit; +} + void FilletChamferPointArrayParam::set_helper_size(int hs) { helper_size = hs; @@ -819,7 +824,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false; Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y()); Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( - this->desktop, offset, this, _pparam->unit, _pparam->use_distance, aprox); + this->desktop, offset, this, _pparam->unit, _pparam->use_distance, aprox, _pparam->documentUnit); } } diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 1dd31d6d4..6e5cce353 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -53,6 +53,7 @@ public: virtual void set_helper_size(int hs); virtual void set_use_distance(bool use_knot_distance); virtual void set_chamfer_steps(int value_chamfer_steps); + virtual void set_document_unit(Glib::ustring const * value_document_unit); virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); @@ -89,6 +90,7 @@ private: int chamfer_steps; bool use_distance; const gchar *unit; + Glib::ustring const * documentUnit; Geom::PathVector hp; Geom::Piecewise > last_pwd2; -- cgit v1.2.3 From 7ff4799d9ecde4286c94e76f4005e18db5a60055 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 12 Nov 2014 01:12:35 +0100 Subject: Fixed bug in node point selection to LPE. (bzr r13704) --- src/live_effects/effect.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index ca3b29b66..e49a15dd0 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -413,12 +413,15 @@ bool Effect::isNodePointSelected(Geom::Point const &nodePoint) const { if (selectedNodesPoints.size() > 0) { + using Geom::X; + using Geom::Y; for (std::vector::const_iterator i = selectedNodesPoints.begin(); i != selectedNodesPoints.end(); ++i) { Geom::Point p = *i; - p[Geom::X] = Inkscape::Util::Quantity::convert(p[Geom::X], "px", *defaultUnit); - p[Geom::Y] = Inkscape::Util::Quantity::convert(p[Geom::Y], "px", *defaultUnit); - if (Geom::are_near(p, nodePoint, 0.01)) { + Geom::Affine transformCoordinate = sp_lpe_item->i2dt_affine(); + Geom::Point p2(nodePoint[X],nodePoint[Y]); + p2 *= transformCoordinate; + if (Geom::are_near(p, p2, 0.01)) { return true; } } -- cgit v1.2.3 From 87469d81799b58681b91800234f266ea8b19b30b Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 14 Nov 2014 01:08:40 +0100 Subject: Add inverse subdivision chamfer to fillet chamfer LPE, feature sugested by Ivan Louette. (bzr r13708) --- src/live_effects/lpe-fillet-chamfer.cpp | 76 +++++++++++++++++----- src/live_effects/lpe-fillet-chamfer.h | 4 +- .../parameter/filletchamferpointarray.cpp | 32 ++++++--- 3 files changed, 86 insertions(+), 26 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index c89bfbd37..78e24f0b8 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -79,7 +79,7 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); - chamfer_steps.param_set_range(0, infinity()); + chamfer_steps.param_set_range(0, 999); chamfer_steps.param_set_increments(1, 1); chamfer_steps.param_set_digits(0); helper_size.param_set_range(0, infinity()); @@ -116,7 +116,7 @@ Gtk::Widget *LPEFilletChamfer::newWidget() } } else if (param->param_key == "chamfer_steps") { Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast(widg)); - widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); + widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamferSubdivisions)); widg = widgRegistered; if (widg) { Gtk::HBox *scalarParameter = dynamic_cast(widg); @@ -153,21 +153,26 @@ Gtk::Widget *LPEFilletChamfer::newWidget() ++it; } - - Gtk::VBox *buttonsContainer = Gtk::manage(new Gtk::VBox(true, 0)); + Gtk::HBox *filletContainer = Gtk::manage(new Gtk::HBox(true, 0)); Gtk::Button *fillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Fillet")))); fillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::fillet)); - buttonsContainer->pack_start(*fillet, true, true, 2); - Gtk::Button *inverse = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); - inverse->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverse)); - buttonsContainer->pack_start(*inverse, true, true, 2); - + filletContainer->pack_start(*fillet, true, true, 2); + Gtk::Button *inverseFillet = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse fillet")))); + inverseFillet->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseFillet)); + filletContainer->pack_start(*inverseFillet, true, true, 2); + + Gtk::HBox *chamferContainer = Gtk::manage(new Gtk::HBox(true, 0)); Gtk::Button *chamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Chamfer")))); chamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::chamfer)); - buttonsContainer->pack_start(*chamfer, true, true, 2); - vbox->pack_start(*buttonsContainer, true, true, 2); + chamferContainer->pack_start(*chamfer, true, true, 2); + Gtk::Button *inverseChamfer = Gtk::manage(new Gtk::Button(Glib::ustring(_("Inverse chamfer")))); + inverseChamfer->signal_clicked().connect(sigc::mem_fun(*this, &LPEFilletChamfer::inverseChamfer)); + chamferContainer->pack_start(*inverseChamfer, true, true, 2); + + vbox->pack_start(*filletContainer, true, true, 2); + vbox->pack_start(*chamferContainer, true, true, 2); return vbox; } @@ -232,17 +237,31 @@ void LPEFilletChamfer::fillet() doChangeType(path_from_piecewise(pwd2, tolerance), 1); } -void LPEFilletChamfer::inverse() +void LPEFilletChamfer::inverseFillet() { Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); doChangeType(path_from_piecewise(pwd2, tolerance), 2); } +void LPEFilletChamfer::chamferSubdivisions() +{ + fillet_chamfer_values.set_chamfer_steps(chamfer_steps); + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000); +} + void LPEFilletChamfer::chamfer() { - fillet_chamfer_values.set_chamfer_steps(chamfer_steps + 3); + fillet_chamfer_values.set_chamfer_steps(chamfer_steps); Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); - doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3); + doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000); +} + +void LPEFilletChamfer::inverseChamfer() +{ + fillet_chamfer_values.set_chamfer_steps(chamfer_steps); + Piecewise > const &pwd2 = fillet_chamfer_values.get_pwd2(); + doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000); } void LPEFilletChamfer::refreshKnots() @@ -333,6 +352,13 @@ void LPEFilletChamfer::doChangeType(std::vector const& original_path toggle = false; } if (toggle) { + if(type >= 5000){ + if(filletChamferData[counter][Y] >= 3000 && filletChamferData[counter][Y] < 4000){ + type = type - 2000; + } else if (filletChamferData[counter][Y] >= 4000 && filletChamferData[counter][Y] < 5000){ + type = type - 1000; + } + } result.push_back(Point(filletChamferData[counter][X], type)); } else { result.push_back(filletChamferData[counter]); @@ -552,8 +578,8 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } else { type = std::abs(filletChamferData[counter + 1][Y]); } - if (type >= 3) { - unsigned int chamferSubs = type-2; + if (type >= 3000 && type < 4000) { + unsigned int chamferSubs = type-2999; Geom::Path path_chamfer; path_chamfer.start(path_out.finalPoint()); if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ @@ -567,6 +593,22 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) path_out.appendNew(chamferStep); } path_out.appendNew(endArcPoint); + } else if (type >= 4000 && type < 5000) { + unsigned int chamferSubs = type-3999; + Geom::Path path_chamfer; + path_chamfer.start(path_out.finalPoint()); + if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ + ccwToggle = ccwToggle?0:1; + path_chamfer.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + }else{ + path_chamfer.appendNew(inverseHandle1, inverseHandle2, endArcPoint); + } + double chamfer_stepsTime = 1.0/chamferSubs; + for(unsigned int i = 1; i < chamferSubs; i++){ + Geom::Point chamferStep = path_chamfer.pointAt(chamfer_stepsTime * i); + path_out.appendNew(chamferStep); + } + path_out.appendNew(endArcPoint); } else if (type == 2) { if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ ccwToggle = ccwToggle?0:1; @@ -574,7 +616,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) }else{ path_out.appendNew(inverseHandle1, inverseHandle2, endArcPoint); } - } else { + } else if (type == 1){ if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); } else { diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index e3589197c..0d6a1ff17 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -56,8 +56,10 @@ public: void toggleHide(); void toggleFlexFixed(); void chamfer(); + void chamferSubdivisions(); + void inverseChamfer(); void fillet(); - void inverse(); + void inverseFillet(); void updateFillet(); void doUpdateFillet(std::vector const& original_pathv, double power); void doChangeType(std::vector const& original_pathv, int type); diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index cf9ef3132..4e2be6e88 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -723,7 +723,7 @@ FilletChamferPointArrayParamKnotHolderEntity( void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, Point const &/*origin*/, - guint /*state*/) + guint state) { using namespace Geom; @@ -733,7 +733,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, /// @todo how about item transforms??? Piecewise > const &pwd2 = _pparam->get_pwd2(); //todo: add snapping - //Geom::Point const s = snap_knot_position(p, state); + Geom::Point const s = snap_knot_position(p, state); double t = nearest_point(p, pwd2[_index]); if (t == 1) { t = 0.9999; @@ -777,13 +777,21 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) }else{ using namespace Geom; int type = (int)_pparam->_vector.at(_index)[Y]; - + if (type >=3000 && type < 4000){ + type = 3; + } + if (type >=4000 && type < 5000){ + type = 4; + } switch(type){ case 1: type = 2; break; case 2: - type = _pparam->chamfer_steps; + type = _pparam->chamfer_steps + 3000; + break; + case 3: + type = _pparam->chamfer_steps + 4000; break; default: type = 1; @@ -793,8 +801,12 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) _pparam->param_set_and_write_new_value(_pparam->_vector); sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); const gchar *tip; - if (type >= 3) { - tip = _("Chamfer: Ctrl+Click toogle type, " + if (type >=3000 && type < 4000){ + tip = _("Chamfer: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); + } else if (type >=4000 && type < 5000) { + tip = _("Inverse Chamfer: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); } else if (type == 2) { @@ -850,8 +862,12 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, continue; } const gchar *tip; - if (_vector[i][Y] >= 3) { - tip = _("Chamfer: Ctrl+Click toogle type, " + if (_vector[i][Y] >=3000 && _vector[i][Y] < 4000){ + tip = _("Chamfer: Ctrl+Click toogle type, " + "Shift+Click open dialog, " + "Ctrl+Alt+Click reset"); + } else if (_vector[i][Y] >=4000 && _vector[i][Y] < 5000) { + tip = _("Inverse Chamfer: Ctrl+Click toogle type, " "Shift+Click open dialog, " "Ctrl+Alt+Click reset"); } else if (_vector[i][Y] == 2) { -- cgit v1.2.3 From 4cf17a9344015106366ecf292d947abdd21724ea Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 15 Nov 2014 20:20:31 +0100 Subject: Update Chamfer Steps to more unequivocal number, thanks to the feedback of Ivan Louette (bzr r13714) --- src/live_effects/lpe-fillet-chamfer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 78e24f0b8..85b4ba5b2 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -79,7 +79,7 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); - chamfer_steps.param_set_range(0, 999); + chamfer_steps.param_set_range(1, 999); chamfer_steps.param_set_increments(1, 1); chamfer_steps.param_set_digits(0); helper_size.param_set_range(0, infinity()); @@ -579,7 +579,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) type = std::abs(filletChamferData[counter + 1][Y]); } if (type >= 3000 && type < 4000) { - unsigned int chamferSubs = type-2999; + unsigned int chamferSubs = type-3000; Geom::Path path_chamfer; path_chamfer.start(path_out.finalPoint()); if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ @@ -594,7 +594,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } path_out.appendNew(endArcPoint); } else if (type >= 4000 && type < 5000) { - unsigned int chamferSubs = type-3999; + unsigned int chamferSubs = type-4000; Geom::Path path_chamfer; path_chamfer.start(path_out.finalPoint()); if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ -- cgit v1.2.3 From cb34932037da3ac780f327c10d3cb5bdab529d9f Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 16 Nov 2014 00:36:30 +0100 Subject: add snap to fillet/chamfer knots. Fixed a bug whith 180 degree node angle (bzr r13716) --- src/live_effects/lpe-fillet-chamfer.cpp | 4 +++- .../parameter/filletchamferpointarray.cpp | 25 ++-------------------- 2 files changed, 5 insertions(+), 24 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 85b4ba5b2..680b4f763 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -578,7 +578,9 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) } else { type = std::abs(filletChamferData[counter + 1][Y]); } - if (type >= 3000 && type < 4000) { + if(are_near(middle_point(startArcPoint,endArcPoint),curve_it1->finalPoint(), 0.0001)){ + path_out.appendNew(endArcPoint); + } else if (type >= 3000 && type < 4000) { unsigned int chamferSubs = type-3000; Geom::Path path_chamfer; path_chamfer.start(path_out.finalPoint()); diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 4e2be6e88..b23145db1 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -693,28 +693,6 @@ void FilletChamferPointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, knot_mode = mode; knot_color = color; } -/* -class FilletChamferPointArrayParamKnotHolderEntity : public KnotHolderEntity { -public: - FilletChamferPointArrayParamKnotHolderEntity(FilletChamferPointArrayParam -*p, unsigned int index); - virtual ~FilletChamferPointArrayParamKnotHolderEntity() {} - - virtual void knot_set(Point const &p, Point const &origin, guint state); - virtual Point knot_get() const; - virtual void knot_click(guint state); - virtual void knot_doubleclicked(guint state); - - /Checks whether the index falls within the size of the parameter's vector/ - bool valid_index(unsigned int index) const { - return (_pparam->_vector.size() > index); - }; - -private: - FilletChamferPointArrayParam *_pparam; - unsigned int _index; -}; -/*/ FilletChamferPointArrayParamKnotHolderEntity:: FilletChamferPointArrayParamKnotHolderEntity( @@ -733,8 +711,9 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, /// @todo how about item transforms??? Piecewise > const &pwd2 = _pparam->get_pwd2(); //todo: add snapping - Geom::Point const s = snap_knot_position(p, state); double t = nearest_point(p, pwd2[_index]); + Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state); + t = nearest_point(s, pwd2[_index]); if (t == 1) { t = 0.9999; } -- cgit v1.2.3 From 44c2ad791f6decf4b3a856eeeca05a026763afb5 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sun, 16 Nov 2014 20:44:13 +0100 Subject: Fixed problems on groups and add a extra option to not need calculate degrees if want a 360 degree result (bzr r13722) --- src/live_effects/lpe-copy_rotate.cpp | 59 +++++++++--------------------------- src/live_effects/lpe-copy_rotate.h | 5 +-- 2 files changed, 17 insertions(+), 47 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index e466093d3..51787e292 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -38,12 +38,6 @@ public: virtual Geom::Point knot_get() const; }; -class KnotHolderEntityRotationAngle : public LPEKnotHolderEntity { -public: - KnotHolderEntityRotationAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; } // namespace CR @@ -52,6 +46,7 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0), num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 5), + copiesTo360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copiesTo360", &wr, this, true), origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"), dist_angle_handle(100) { @@ -59,6 +54,7 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : _provides_knotholder_entities = true; // register all your parameters here, so Inkscape knows which parameters this effect has: + registerParameter( dynamic_cast(&copiesTo360) ); registerParameter( dynamic_cast(&starting_angle) ); registerParameter( dynamic_cast(&rotation_angle) ); registerParameter( dynamic_cast(&num_copies) ); @@ -76,11 +72,13 @@ LPECopyRotate::~LPECopyRotate() void LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) { - SPCurve const *curve = SP_SHAPE(lpeitem)->_curve; + using namespace Geom; - A = *(curve->first_point()); - B = *(curve->last_point()); + original_bbox(lpeitem); + Point A(boundingbox_X.min(), boundingbox_Y.middle()); + Point B(boundingbox_X.max(), boundingbox_Y.middle()); + Point C(boundingbox_X.middle(), boundingbox_Y.middle()); origin.param_setValue(A); dir = unit_vector(B - A); @@ -95,7 +93,11 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise > const & p // I first suspected the minus sign to be a bug in 2geom but it is // likely due to SVG's choice of coordinate system orientation (max) start_pos = origin + dir * Rotate(-deg_to_rad(starting_angle)) * dist_angle_handle; - rot_pos = origin + dir * Rotate(-deg_to_rad(starting_angle + rotation_angle)) * dist_angle_handle; + double rotation_angle_end = rotation_angle; + if(copiesTo360){ + rotation_angle_end = 360.0/(double)num_copies; + } + rot_pos = origin + dir * Rotate(-deg_to_rad(starting_angle + rotation_angle_end)) * dist_angle_handle; A = pwd2_in.firstValue(); B = pwd2_in.lastValue(); @@ -107,7 +109,7 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise > const & p for (int i = 0; i < num_copies; ++i) { // I first suspected the minus sign to be a bug in 2geom but it is // likely due to SVG's choice of coordinate system orientation (max) - Rotate rot(-deg_to_rad(rotation_angle * i)); + Rotate rot(-deg_to_rad(rotation_angle_end * i)); Affine t = pre * rot * Translate(origin); output.concat(pwd2_in * t); } @@ -123,12 +125,12 @@ LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector((Geom::Point) origin); path.appendNew(rot_pos); - PathVector pathv; pathv.push_back(path); hp_vec.push_back(pathv); } + void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { { KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this); @@ -136,12 +138,6 @@ void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *des _("Adjust the starting angle") ); knotholder->add(e); } - { - KnotHolderEntity *e = new CR::KnotHolderEntityRotationAngle(this); - e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, - _("Adjust the rotation angle") ); - knotholder->add(e); - } }; namespace CR { @@ -168,26 +164,6 @@ KnotHolderEntityStartingAngle::knot_set(Geom::Point const &p, Geom::Point const sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); } -void -KnotHolderEntityRotationAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) -{ - LPECopyRotate* lpe = dynamic_cast(_effect); - - Geom::Point const s = snap_knot_position(p, state); - - // I first suspected the minus sign to be a bug in 2geom but it is - // likely due to SVG's choice of coordinate system orientation (max) - lpe->rotation_angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle); - if (state & GDK_SHIFT_MASK) { - lpe->dist_angle_handle = L2(lpe->B - lpe->A); - } else { - lpe->dist_angle_handle = L2(p - lpe->origin); - } - - // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. - sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); -} - Geom::Point KnotHolderEntityStartingAngle::knot_get() const { @@ -195,13 +171,6 @@ KnotHolderEntityStartingAngle::knot_get() const return lpe->start_pos; } -Geom::Point -KnotHolderEntityRotationAngle::knot_get() const -{ - LPECopyRotate const *lpe = dynamic_cast(_effect); - return lpe->rot_pos; -} - } // namespace CR diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index ca7aa269c..123c92cdd 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -16,6 +16,7 @@ #include "live_effects/effect.h" #include "live_effects/parameter/point.h" +#include "live_effects/lpegroupbbox.h" namespace Inkscape { namespace LivePathEffect { @@ -26,7 +27,7 @@ namespace CR { class KnotHolderEntityRotationAngle; } -class LPECopyRotate : public Effect { +class LPECopyRotate : public Effect, GroupBBoxEffect { public: LPECopyRotate(LivePathEffectObject *lpeobject); virtual ~LPECopyRotate(); @@ -37,7 +38,6 @@ public: /* the knotholder entity classes must be declared friends */ friend class CR::KnotHolderEntityStartingAngle; - friend class CR::KnotHolderEntityRotationAngle; void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); protected: @@ -47,6 +47,7 @@ private: ScalarParam starting_angle; ScalarParam rotation_angle; ScalarParam num_copies; + BoolParam copiesTo360; PointParam origin; -- cgit v1.2.3 From 8e9f1ad900f718cbbf2d529bbd5606845902feaa Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 17 Nov 2014 22:18:25 +0100 Subject: Fixes crash with perspective_lpe (bzr r13725) --- src/live_effects/lpe-perspective_path.cpp | 40 ++++++++++++++++++------------- src/live_effects/lpe-perspective_path.h | 5 +--- 2 files changed, 25 insertions(+), 20 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index d43772cf7..5183a455f 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -44,6 +44,8 @@ public: } // namespace PP static Glib::ustring perspectiveID = _("First perspective"); + + LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: @@ -62,35 +64,41 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; - unapply = false; - Persp3D *persp = persp3d_document_first_persp(lpeobject->document); +} + +LPEPerspectivePath::~LPEPerspectivePath() +{ + +} +void +LPEPerspectivePath::doOnApply(SPLPEItem const* lpeitem) +{ + Persp3D *persp = persp3d_document_first_persp(lpeitem->document); if(persp == 0 ){ char *msg = _("You need a BOX 3D object"); Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true); dialog.run(); - unapply = true; - return; + SPLPEItem * item = const_cast(lpeitem); + item->removeCurrentPathEffect(false); } - Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; - pmat = pmat * SP_ACTIVE_DESKTOP->doc2dt(); - pmat.copy_tmat(tmat); -} - -LPEPerspectivePath::~LPEPerspectivePath() -{ - } - void LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem, true); - if(unapply){ - SP_LPE_ITEM(lpeitem)->removeCurrentPathEffect(false); + SPLPEItem * item = const_cast(lpeitem); + Persp3D *persp = persp3d_document_first_persp(lpeitem->document); + if(persp == 0 ){ + char *msg = _("You need a BOX 3D object"); + Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_INFO, + Gtk::BUTTONS_OK, true); + dialog.run(); return; } - SPLPEItem * item = const_cast(lpeitem); + Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; + pmat = pmat * SP_ACTIVE_DESKTOP->doc2dt(); + pmat.copy_tmat(tmat); item->apply_to_clippath(item); item->apply_to_mask(item); } diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h index 6ccac4a51..c4ddf1853 100644 --- a/src/live_effects/lpe-perspective_path.h +++ b/src/live_effects/lpe-perspective_path.h @@ -33,9 +33,8 @@ class LPEPerspectivePath : public Effect, GroupBBoxEffect { public: LPEPerspectivePath(LivePathEffectObject *lpeobject); virtual ~LPEPerspectivePath(); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); - + virtual void doOnApply(SPLPEItem const* lpeitem); virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); virtual void refresh(Gtk::Entry* perspective); @@ -53,8 +52,6 @@ private: ScalarParam offsety; BoolParam uses_plane_xy; // there are all kinds of parameters. Check the /live_effects/parameter directory which types exist! - - bool unapply; Geom::Point orig; LPEPerspectivePath(const LPEPerspectivePath&); -- cgit v1.2.3 From d2417aa8fb6f6945faccd0ba4a19337c509329b6 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 17 Nov 2014 22:27:06 +0100 Subject: fix a bug in bspline on apply on non shapes (bzr r13726) --- src/live_effects/lpe-bspline.cpp | 21 ++++----------------- src/live_effects/lpe-bspline.h | 2 +- 2 files changed, 5 insertions(+), 18 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 97a4c6205..c5390a0c9 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -88,25 +88,12 @@ void LPEBSpline::doBeforeEffect (SPLPEItem const* /*lpeitem*/) } -void LPEBSpline::createAndApply(const char *name, SPDocument *doc, - SPItem *item) +void LPEBSpline::doOnApply(SPLPEItem const* lpeitem) { - if (!SP_IS_SHAPE(item)) { + if (!SP_IS_SHAPE(lpeitem)) { g_warning("LPE BSpline can only be applied to shapes (not groups)."); - } else { - // Path effect definition - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); - repr->setAttribute("effect", name); - - doc->getDefs()->getRepr() - ->addChild(repr, NULL); // adds to and assigns the 'id' attribute - const gchar *repr_id = repr->attribute("id"); - Inkscape::GC::release(repr); - - gchar *href = g_strdup_printf("#%s", repr_id); - SP_LPE_ITEM(item)->addPathEffect(href, true); - g_free(href); + SPLPEItem * item = const_cast(lpeitem); + item->removeCurrentPathEffect(false); } } diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 8751a5720..a17c0c4ac 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -19,10 +19,10 @@ public: LPEBSpline(LivePathEffectObject *lpeobject); virtual ~LPEBSpline(); - virtual void createAndApply(const char *name, SPDocument *doc, SPItem *item); virtual LPEPathFlashType pathFlashType() const { return SUPPRESS_FLASH; } + virtual void doOnApply(SPLPEItem const* lpeitem); virtual void doEffect(SPCurve *curve); virtual void doBeforeEffect (SPLPEItem const* lpeitem); void drawHandle(Geom::Point p, double radiusHelperNodes); -- cgit v1.2.3 From 332ce1f44ba815b149c288b2cc03977caeb56adf Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 17 Nov 2014 22:32:18 +0100 Subject: fix a bug in fillet/chamfer on apply on non shapes (bzr r13727) --- src/live_effects/lpe-fillet-chamfer.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 680b4f763..119759b87 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -431,6 +431,8 @@ void LPEFilletChamfer::doOnApply(SPLPEItem const *lpeItem) fillet_chamfer_values.param_set_and_write_new_value(point); } else { g_warning("LPE Fillet can only be applied to shapes (not groups)."); + SPLPEItem * item = const_cast(lpeItem); + item->removeCurrentPathEffect(false); } } -- cgit v1.2.3 From 7be365f943fa4204784b0358b21a338b22230d04 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 19 Nov 2014 19:36:52 +0100 Subject: remove extra commnets (bzr r13732) --- src/live_effects/parameter/filletchamferpointarray.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index b23145db1..7d8c8e9b0 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -708,9 +708,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, if (!valid_index(_index)) { return; } - /// @todo how about item transforms??? Piecewise > const &pwd2 = _pparam->get_pwd2(); - //todo: add snapping double t = nearest_point(p, pwd2[_index]); Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state); t = nearest_point(s, pwd2[_index]); -- cgit v1.2.3 From d90ab1169c440127365212e344f158a33f077e4b Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 21 Nov 2014 13:13:24 +0100 Subject: Fixed a bug pointed by suv running from comand line, also removed another desktop call (bzr r13743) --- src/live_effects/lpe-perspective_path.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/live_effects') diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index 5183a455f..901519b4f 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -23,7 +23,7 @@ #include "knot-holder-entity.h" #include "knotholder.h" #include "desktop.h" - +#include #include "inkscape.h" #include <2geom/path.h> @@ -97,7 +97,8 @@ LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem) return; } Proj::TransfMat3x4 pmat = persp->perspective_impl->tmat; - pmat = pmat * SP_ACTIVE_DESKTOP->doc2dt(); + Geom::Affine doc2d = Geom::Scale(1, -1) * Geom::Translate(0, item->document->getHeight().value("px")); + pmat = pmat * doc2d; pmat.copy_tmat(tmat); item->apply_to_clippath(item); item->apply_to_mask(item); -- cgit v1.2.3