summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/CMakeLists.txt4
-rw-r--r--src/live_effects/Makefile_insert2
-rw-r--r--src/live_effects/effect-enum.h1
-rw-r--r--src/live_effects/effect.cpp20
-rw-r--r--src/live_effects/lpe-bspline.cpp1242
-rw-r--r--src/live_effects/lpe-bspline.h52
-rw-r--r--src/live_effects/lpe-envelope-perspective.cpp49
-rw-r--r--src/live_effects/lpe-envelope-perspective.h2
-rw-r--r--src/live_effects/lpe-fillet-chamfer.cpp656
-rw-r--r--src/live_effects/lpe-fillet-chamfer.h87
-rw-r--r--src/live_effects/lpe-simplify.cpp22
-rw-r--r--src/live_effects/parameter/Makefile_insert2
-rw-r--r--src/live_effects/parameter/bool.h2
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp656
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h117
-rw-r--r--src/live_effects/parameter/parameter.cpp31
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.cpp5
-rw-r--r--src/live_effects/parameter/togglebutton.cpp88
-rw-r--r--src/live_effects/parameter/togglebutton.h31
19 files changed, 2362 insertions, 707 deletions
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
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-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 e622ca420..0e9f92d09 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"
@@ -107,7 +108,7 @@ const Util::EnumData<EffectType> 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"},
@@ -121,13 +122,15 @@ const Util::EnumData<EffectType> 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<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
@@ -263,6 +266,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case ENVELOPE_PERSPECTIVE:
neweffect = static_cast<Effect*> ( new LPEEnvelopePerspective(lpeobj) );
break;
+ case FILLET_CHAMFER:
+ neweffect = static_cast<Effect*> ( 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-bspline.cpp b/src/live_effects/lpe-bspline.cpp
index 247496167..0a5d8eca5 100644
--- a/src/live_effects/lpe-bspline.cpp
+++ b/src/live_effects/lpe-bspline.cpp
@@ -8,10 +8,13 @@
# include <config.h>
#endif
-#if WITH_GLIBMM_2_32
+#if WITH_GLIBMM_2_32 && HAVE_GLIBMM_THREADS_H
# include <glibmm/threads.h>
#endif
+#include <2geom/bezier-curve.h>
+#include <2geom/point.h>
+
#include <gtkmm/box.h>
#include <gtkmm/entry.h>
#include <gtkmm/box.h>
@@ -21,10 +24,7 @@
#include <glib.h>
#include <glibmm/i18n.h>
-
#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 <typeinfo>
#include <vector>
-// 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<Parameter *>(&weight));
- registerParameter(dynamic_cast<Parameter *>(&steps));
- registerParameter(dynamic_cast<Parameter *>(&ignoreCusp));
- registerParameter(dynamic_cast<Parameter *>(&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 <defs> 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<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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis();
- SPCurve *lineHelper = new SPCurve();
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*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<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis();
- //Geom::BezierCurve const *bezier = dynamic_cast<Geom::BezierCurve
- //const*>(&*curve_endit);
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*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 <defs> 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<Parameter *>::iterator it = param_vector.begin();
- while (it != param_vector.end()) {
- if ((*it)->widget_is_visible) {
- Parameter *param = *it;
- Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
- if (param->param_key == "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<Gtk::Widget *>(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<Gtk::Widget *>(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<Inkscape::UI::Widget::Scalar *>(widg));
- widgRegistered->signal_value_changed()
- .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight));
- widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
- if (widg){
- Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
- std::vector< Gtk::Widget* > childList = scalarParameter->get_children();
- Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(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<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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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<Gtk::CheckButton *>(widg));
- widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
- }
- if (param->param_key == "ignoreCusp") {
- Gtk::CheckButton *widgRegistered =
- Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
- widg = dynamic_cast<Gtk::Widget *>(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<Geom::SBasis> SBasisStart = start->first_segment()->toSBasis();
+ SPCurve *lineHelper = new SPCurve();
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*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<Geom::SBasis> SBasisEnd = end->first_segment()->toSBasis();
+
+ cubic = dynamic_cast<Geom::CubicBezier const *>(&*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<Parameter *>::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<Gtk::Widget *>(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<Gtk::Widget *>(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<Inkscape::UI::Widget::Scalar *>(widg));
+ widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEBSpline::toWeight));
+
+ if (widg) {
+ Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
+ Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
+ entryWidg->set_width_chars(6);
+ }
+ }
- ++it;
- }
- return dynamic_cast<Gtk::Widget *>(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<Gtk::HBox *>(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<Gtk::HBox *>(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<Geom::Point>::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 = 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);
+ 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<Geom::Point>::iterator pbegin;
- for (Inkscape::UI::ControlPointSelection::Set::iterator i =
- selection.begin();
- i != selection.end(); ++i) {
- if ((*i)->selected()) {
- Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*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<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();
- }
- }
- //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<Geom::CubicBezier const *>(&*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<Geom::Point>::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 = 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 =
+ nt->_selected_nodes->allPoints();
+ points.clear();
+ std::vector<Geom::Point>::iterator pbegin;
+ for (Inkscape::UI::ControlPointSelection::Set::iterator i =
+ selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->selected()) {
+ Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*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<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();
}
- } 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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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<Geom::Point> points;
- BoolParam ignoreCusp;
- BoolParam onlySelected;
- ScalarParam weight;
+ std::vector<Geom::Point> 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-envelope-perspective.cpp b/src/live_effects/lpe-envelope-perspective.cpp
index a16ed7ab5..d9bf20752 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<unsigned> DeformationTypeData[] = {
+ {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"},
+ {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"}
+};
+
+static const Util::EnumDataConverter<unsigned> 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<Parameter *>(&perspective));
+ registerParameter( dynamic_cast<Parameter *>(&deform_type));
registerParameter( dynamic_cast<Parameter *>(&Up_Left_Point) );
registerParameter( dynamic_cast<Parameter *>(&Up_Right_Point) );
registerParameter( dynamic_cast<Parameter *>(&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<Geom::Point> 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<Parameter *>::iterator it = param_vector.begin();
Gtk::HBox * hboxUpHandles = Gtk::manage(new Gtk::HBox(false,0));
Gtk::HBox * hboxDownHandles = Gtk::manage(new Gtk::HBox(false,0));
@@ -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<Gtk::Widget *>(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<Geom::PathVector> &hp_vec);
private:
- BoolParam perspective;
+ EnumParam<unsigned> deform_type;
PointReseteableParam Up_Left_Point;
PointReseteableParam Up_Right_Point;
PointReseteableParam Down_Left_Point;
diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp
new file mode 100644
index 000000000..98557196d
--- /dev/null
+++ b/src/live_effects/lpe-fillet-chamfer.cpp
@@ -0,0 +1,656 @@
+/*
+ * Author(s):
+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ *
+ * 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
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+#include "live_effects/lpe-fillet-chamfer.h"
+
+#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 "ui/tool/node.h"
+#include "ui/tools/node-tool.h"
+
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
+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(&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);
+ 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<Parameter *>::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 == "radius") {
+ Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEFilletChamfer::updateFillet));
+ widg = widgRegistered;
+ if (widg) {
+ Gtk::HBox *scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
+ Gtk::Entry *entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
+ entryWidg->set_width_chars(6);
+ }
+ } else if (param->param_key == "flexible") {
+ Gtk::CheckButton *widgRegistered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(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<Inkscape::UI::Widget::Scalar *>(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<Gtk::CheckButton *>(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);
+ }
+
+ 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 vbox;
+}
+
+void LPEFilletChamfer::toggleHide()
+{
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> result;
+ for (std::vector<Point>::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<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> result;
+ unsigned int i = 0;
+ for (std::vector<Point>::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<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doUpdateFillet(path_from_piecewise(pwd2, tolerance), power);
+}
+
+void LPEFilletChamfer::fillet()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 1);
+}
+
+void LPEFilletChamfer::inverse()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 2);
+}
+
+void LPEFilletChamfer::chamfer()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 3);
+}
+
+void LPEFilletChamfer::doubleChamfer()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ doChangeType(path_from_piecewise(pwd2, tolerance), 4);
+}
+
+void LPEFilletChamfer::refreshKnots()
+{
+ Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
+ fillet_chamfer_values.recalculate_knots(pwd2);
+ SPDesktop *desktop = SP_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<Geom::Point> point)
+{
+ if (point.size() > 0) {
+ for (std::vector<Geom::Point>::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<Geom::Path> const& original_pathv, double power)
+{
+ std::vector<Geom::Point> point;
+ 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<Geom::Point>::iterator pBegin;
+ for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection.begin(); i != selection.end(); ++i) {
+ if ((*i)->selected()) {
+ Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i);
+ pBegin = point.begin();
+ point.insert(pBegin, desktop->doc2dt(n->position()));
+ }
+ }
+ }
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> 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<Geom::Path> const& original_pathv, int type)
+{
+ std::vector<Geom::Point> point;
+ 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<Geom::Point>::iterator pBegin;
+ for (Inkscape::UI::ControlPointSelection::Set::iterator i =
+ selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->selected()) {
+ Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i);
+ pBegin = point.begin();
+ point.insert(pBegin, desktop->doc2dt(n->position()));
+ }
+ }
+ }
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ std::vector<Geom::Point> 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> point;
+ PathVector const &original_pathv = SP_SHAPE(lpeItem)->_curve->get_pathvector();
+ Piecewise<D2<SBasis> > 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<SPPath const *>(lpeItem)->get_original_curve() : SP_SHAPE(lpeItem)->getCurve();
+ std::vector<Point> filletChamferData = fillet_chamfer_values.data();
+ if (!filletChamferData.empty() && getKnotsNumber(c) != (int)
+ filletChamferData.size()) {
+ PathVector const original_pathv = c->get_pathvector();
+ Piecewise<D2<SBasis> > 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<Geom::Path>::const_iterator path_it = pv.begin();
+ path_it != pv.end(); ++path_it) {
+ if (!(*path_it).closed()) {
+ nKnots--;
+ }
+ }
+ return nKnots;
+}
+
+void
+LPEFilletChamfer::adjustForNewPath(std::vector<Geom::Path> const &path_in)
+{
+ if (!path_in.empty()) {
+ fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(path_in[0]
+ .toPwSb());
+ }
+}
+
+std::vector<Geom::Path>
+LPEFilletChamfer::doEffect_path(std::vector<Geom::Path> const &path_in)
+{
+ std::vector<Geom::Path> pathvector_out;
+ Piecewise<D2<SBasis> > pwd2_in = paths_to_pw(path_in);
+ pwd2_in = remove_short_cuts(pwd2_in, .01);
+ Piecewise<D2<SBasis> > der = derivative(pwd2_in);
+ Piecewise<D2<SBasis> > n = rot90(unitVector(der));
+ fillet_chamfer_values.set_pwd2(pwd2_in, n);
+ std::vector<Point> 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) {
+ 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();
+ }
+ }
+ 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 {
+ 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 {
+ 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;
+ }
+ 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<Geom::CubicBezier const *>(&*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<Geom::CubicBezier const *>(&*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 = 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);
+ LineSegment chamferCenter(central, curve_it1->finalPoint());
+ path_out.appendNew<Geom::LineSegment>(chamferCenter.pointAt(0.5));
+ }
+ path_out.appendNew<Geom::LineSegment>(endArcPoint);
+ } else if (type == 2) {
+ path_out.appendNew<Geom::CubicBezier>(inverseHandle1, inverseHandle2,
+ endArcPoint);
+ } else {
+ path_out.appendNew<Geom::CubicBezier>(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..420425650
--- /dev/null
+++ b/src/live_effects/lpe-fillet-chamfer.h
@@ -0,0 +1,87 @@
+#ifndef INKSCAPE_LPE_FILLET_CHAMFER_H
+#define INKSCAPE_LPE_FILLET_CHAMFER_H
+
+/*
+ * Author(s):
+ * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ *
+ * 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
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glibmm/threads.h>
+
+#include "live_effects/parameter/enum.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 {
+public:
+ LPEFilletChamfer(LivePathEffectObject *lpeobject);
+ virtual ~LPEFilletChamfer();
+
+ virtual std::vector<Geom::Path> doEffect_path(std::vector<Geom::Path> const &path_in);
+
+ virtual void doOnApply(SPLPEItem const *lpeItem);
+ virtual void doBeforeEffect(SPLPEItem const *lpeItem);
+ virtual void adjustForNewPath(std::vector<Geom::Path> const &path_in);
+ 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<Geom::Path> const& original_pathv, double power);
+ void doChangeType(std::vector<Geom::Path> const& original_pathv, int type);
+ bool nodeIsSelected(Geom::Point nodePoint, std::vector<Geom::Point> points);
+ void refreshKnots();
+
+ 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
+
+/*
+ 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.cpp b/src/live_effects/lpe-simplify.cpp
index d010e75a2..1a02375cd 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 <gtkmm/box.h>
-#include <gtkmm/entry.h>
+
+#include <gtkmm.h>
+
#include "live_effects/lpe-simplify.h"
#include "display/curve.h"
#include "live_effects/parameter/parameter.h"
@@ -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("on"), INKSCAPE_ICON("off")),
+ handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false,
+ "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false,
+ "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false,
+ "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off"))
{
registerParameter(dynamic_cast<Parameter *>(&steps));
registerParameter(dynamic_cast<Parameter *>(&threshold));
@@ -41,7 +45,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject)
registerParameter(dynamic_cast<Parameter *>(&handles));
registerParameter(dynamic_cast<Parameter *>(&simplifyindividualpaths));
registerParameter(dynamic_cast<Parameter *>(&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/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/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 <j.b.c.engelen@utwente.nl>
+ * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp
new file mode 100644
index 000000000..457b68dd2
--- /dev/null
+++ b/src/live_effects/parameter/filletchamferpointarray.cpp
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
+ * 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 <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"
+#include "knotholder.h"
+#include "sp-lpe-item.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 "ui/tools/node-tool.h"
+
+// TODO due to internal breakage in glibmm headers,
+// this has to be included last.
+#include <glibmm/i18n.h>
+
+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<Point>(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<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true);
+ static_cast<Gtk::HBox*>(hbox)->show_all_children();
+
+ return dynamic_cast<Gtk::Widget *> (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<Geom::Point> result;
+ for (std::vector<Point>::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<D2<SBasis> > 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<Point> 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<Point> 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<Point>().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<D2<SBasis> > const &pwd2_in)
+{
+ bool change = false;
+ PathVector pathv = path_from_piecewise(pwd2_in, 0.001);
+ if (!pathv.empty()) {
+ std::vector<Point> 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<D2<SBasis> > const &pwd2_in,
+ Piecewise<D2<SBasis> > 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<Point> ts = data();
+ hp.clear();
+ unsigned int i = 0;
+ Piecewise<D2<SBasis> > const &n = get_pwd2_normal();
+ for (std::vector<Point>::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<Geom::LineSegment>(canvas_point);
+ arrow.appendNew<Geom::LineSegment>(end_point);
+ hp.push_back(arrow);
+ i++;
+ }
+}
+
+void FilletChamferPointArrayParam::addCanvasIndicators(
+ SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &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<D2<SBasis> > u;
+ u.push_cut(0);
+ u.push(last_pwd2[index], 1);
+ std::vector<double> 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<D2<SBasis> > 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<D2<SBasis> > 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<D2<SBasis> > 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 = _("<b>Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (type == 2) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (type == 1) {
+ tip = _("<b>Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else {
+ tip = _("<b>Double Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> 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 = _("<b>Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (_vector[i][Y] == 2) {
+ tip = _("<b>Inverse Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else if (_vector[i][Y] == 1) {
+ tip = _("<b>Fillet</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> open dialog");
+ } else {
+ tip = _("<b>Double Chamfer</b>: <b>Ctrl+click</b> toogle type, "
+ "<b>Shift+click</b> 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 <jabier.arraiza@marker.es>
+ * 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 <glib.h>
+#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<Geom::Point> {
+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<Geom::PathVector> &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<Geom::D2<Geom::SBasis> > const &pwd2_in,
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in);
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2() const {
+ return last_pwd2;
+ }
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &get_pwd2_normal() const {
+ return last_pwd2_normal;
+ }
+
+ void recalculate_controlpoints_for_new_pwd2(
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in);
+ void recalculate_knots(
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > 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<Geom::D2<Geom::SBasis> > last_pwd2;
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > 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
diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp
index a5de2169e..7732eee76 100644
--- a/src/live_effects/parameter/parameter.cpp
+++ b/src/live_effects/parameter/parameter.cpp
@@ -43,6 +43,15 @@ 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.
+// If you need this to be more, please be conservative about it.
+const double SCALARPARAM_G_MAXDOUBLE = 10000000000;
+
+
/*###########################################
* REAL PARAM
*/
@@ -51,8 +60,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),
@@ -108,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
}
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<D2<SBasis> > 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;
}
diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp
index 03238f935..5658d238f 100644
--- a/src/live_effects/parameter/togglebutton.cpp
+++ b/src/live_effects/parameter/togglebutton.cpp
@@ -5,6 +5,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
+#include <glibmm/i18n.h>
+
#include "ui/widget/registered-widget.h"
#include "live_effects/parameter/togglebutton.h"
#include "live_effects/effect.h"
@@ -14,7 +17,6 @@
#include "inkscape.h"
#include "verbs.h"
#include "helper-fns.h"
-#include <glibmm/i18n.h>
namespace Inkscape {
@@ -22,13 +24,20 @@ 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()
{
+ if (_toggled_connection.connected()) {
+ _toggled_connection.disconnect();
+ }
}
void
@@ -54,7 +63,11 @@ ToggleButtonParam::param_getSVGValue() const
Gtk::Widget *
ToggleButtonParam::param_newWidget()
{
- Inkscape::UI::Widget::RegisteredToggleButton * checkwdg = Gtk::manage(
+ if (_toggled_connection.connected()) {
+ _toggled_connection.disconnect();
+ }
+
+ checkwdg = Gtk::manage(
new Inkscape::UI::Widget::RegisteredToggleButton( param_label,
param_tooltip,
param_key,
@@ -62,18 +75,81 @@ 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, false, false, 1);
+ if (!param_label.empty()) {
+ gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1);
+ }
+ }else{
+ gtk_box_pack_start (GTK_BOX(boxButton), labelButton, false, false, 1);
+ }
+ checkwdg->add(*Gtk::manage(Glib::wrap(boxButton)));
checkwdg->setActive(value);
checkwdg->setProgrammatically = false;
checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter"));
- return dynamic_cast<Gtk::Widget *> (checkwdg);
+ _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
+ToggleButtonParam::toggled() {
+ _signal_toggled.emit();
}
} /* namespace LivePathEffect */
diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h
index 9b1c71185..4e545bcfd 100644
--- a/src/live_effects/parameter/togglebutton.h
+++ b/src/live_effects/parameter/togglebutton.h
@@ -2,22 +2,27 @@
#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H
/*
- * Inkscape::LivePathEffectParameters
- *
-* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
+ * Copyright (C) Jabiertxo Arraiza Cenoz 2014
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <glib.h>
+#include <sigc++/connection.h>
+#include <sigc++/signal.h>
#include "live_effects/parameter/parameter.h"
+#include "icon-size.h"
+#include "ui/widget/registered-widget.h"
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,
@@ -25,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();
@@ -39,13 +48,25 @@ public:
bool get_value() const { return value; };
inline operator bool() const { return value; };
+
+ sigc::signal<void>& signal_toggled() { return _signal_toggled; }
+ virtual void toggled();
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<void> _signal_toggled;
+ sigc::connection _toggled_connection;
};