From: cilix42 Date: Mon, 19 May 2008 15:52:07 +0000 (+0000) Subject: Provide knotholder for LPEPerpBisector; TODO: this replaces the usual nodepath in... X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=73d455c08e8062e257dd052d2d690b9300434351;p=inkscape.git Provide knotholder for LPEPerpBisector; TODO: this replaces the usual nodepath in node context but in the long run it is desired to use both along with each other --- diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 1d4481415..2a90687f1 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -299,9 +299,24 @@ Effect::registerParameter(Parameter * param) param_vector.push_back(param); } +void +Effect::registerKnotHolderHandle(SPKnotHolderSetFunc set_func, SPKnotHolderGetFunc get_func) +{ + knotholder_func_vector.push_back(std::make_pair(set_func, get_func)); +} + +// TODO: allow for adding click_functions and description strings, too +void +Effect::addHandles(SPKnotHolder *knotholder) { + std::vector >::iterator i; + for (i = knotholder_func_vector.begin(); i != knotholder_func_vector.end(); ++i) { + sp_knot_holder_add(knotholder, i->first, i->second, NULL, ("")); + } +} + /** -* This *creates* a new widget, management of deletion should be done by the caller -*/ + * This *creates* a new widget, management of deletion should be done by the caller + */ Gtk::Widget * Effect::newWidget(Gtk::Tooltips * tooltips) { diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index b5c1d6aeb..693c6ad46 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -17,6 +17,7 @@ #include "ui/widget/registry.h" #include "util/enums.h" #include "sp-lpe-item.h" +#include "knotholder.h" #define LPE_CONVERSION_TOLERANCE 0.01 // FIXME: find good solution for this. @@ -97,6 +98,9 @@ public: virtual void transform_multiply(Geom::Matrix const& postmul, bool set); + bool providesKnotholder() { return knotholder_func_vector.size() > 0; } + void addHandles(SPKnotHolder *knotholder); + Glib::ustring getName(); Inkscape::XML::Node * getRepr(); SPDocument * getSPDoc(); @@ -124,9 +128,11 @@ protected: doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); void registerParameter(Parameter * param); + void registerKnotHolderHandle(SPKnotHolderSetFunc set_func, SPKnotHolderGetFunc get_func); Parameter * getNextOncanvasEditableParam(); std::vector param_vector; + std::vector > knotholder_func_vector; int oncanvasedit_it; Inkscape::UI::Widget::Registry wr; diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp index c744f1268..2fec63f3c 100644 --- a/src/live_effects/lpe-perp_bisector.cpp +++ b/src/live_effects/lpe-perp_bisector.cpp @@ -16,39 +16,142 @@ #include "live_effects/lpe-perp_bisector.h" #include "display/curve.h" #include +#include "sp-path.h" +#include "line-geometry.h" #include <2geom/path.h> namespace Inkscape { namespace LivePathEffect { +/* FIXME: We should arguably make these member functions of LPEPerpBisector. + Is there an easy way to register member functions with knotholder? + */ +NR::Point bisector_left_end_get(SPItem *item) { + Inkscape::LivePathEffect::LPEPerpBisector *lpe = + (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item)); + + return NR::Point(lpe->C); +} + +NR::Point bisector_right_end_get(SPItem *item) { + Inkscape::LivePathEffect::LPEPerpBisector *lpe = + (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item)); + + return NR::Point(lpe->D); +} + +void +bisector_end_set(SPItem *item, NR::Point const &p, bool left) { + Inkscape::LivePathEffect::LPEPerpBisector *lpe = + (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item)); + + Geom::Point v(Geom::unit_vector(lpe->B - lpe->A)); + Geom::Point diff(lpe->M - p.to_2geom()); + + double lambda = - v[Geom::Y] * diff[Geom::X] + v[Geom::X] * diff[Geom::Y]; + if (left) { + lpe->C = lpe->M + lpe->perp_dir * lambda; + lpe->length_left.param_set_value(lambda); + } else { + lpe->D = lpe->M + lpe->perp_dir * lambda; + lpe->length_right.param_set_value(-lambda); + } + + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), true); +} + +void +bisector_left_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) { + bisector_end_set(item, p); +} + +void +bisector_right_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) { + bisector_end_set(item, p, false); +} + +NR::Point path_start_get(SPItem *item) { + Inkscape::LivePathEffect::LPEPerpBisector *lpe = + (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item)); + + return NR::Point(lpe->A); +} + +NR::Point path_end_get(SPItem *item) { + Inkscape::LivePathEffect::LPEPerpBisector *lpe = + (Inkscape::LivePathEffect::LPEPerpBisector *) sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item)); + + return NR::Point(lpe->B); +} + +void +path_set_start_end(SPItem *item, NR::Point const &p, bool start) { + SPCurve* curve = sp_path_get_curve_for_edit (SP_PATH(item)); // TODO: Should we use sp_shape_get_curve()? + NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM(item))); + + Geom::Point A, B; + if (start) { + A = p.to_2geom(); + B = (curve->last_point()).to_2geom(); + } else { + A = (curve->first_point()).to_2geom(); + B = (p.to_2geom()); + } + + SPCurve *c = new SPCurve(); + c->moveto(A); + c->lineto(B); + sp_path_set_original_curve(SP_PATH(item), c, TRUE, true); + c->unref(); +} + +void path_start_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) { + path_set_start_end(item, p); +} + +void path_end_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/) { + path_set_start_end(item, p, false); +} + LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) : Effect(lpeobject), - length_left(_("Length left"), _(""), "length-left", &wr, this, 200), - length_right(_("Length right"), _(""), "length-right", &wr, this, 200) + length_left(_("Length left"), _("Specifies the left end of the bisector"), "length-left", &wr, this, 200), + length_right(_("Length right"), _("Specifies the right end of the bisector"), "length-right", &wr, this, 200), + A(0,0), B(0,0), M(0,0), C(0,0), D(0,0), perp_dir(0,0) { + // register all your parameters here, so Inkscape knows which parameters this effect has: registerParameter( dynamic_cast(&length_left) ); registerParameter( dynamic_cast(&length_right) ); + + registerKnotHolderHandle(path_start_set, path_start_get); + registerKnotHolderHandle(path_end_set, path_end_get); + registerKnotHolderHandle(bisector_left_end_set, bisector_left_end_get); + registerKnotHolderHandle(bisector_right_end_set, bisector_right_end_get); } LPEPerpBisector::~LPEPerpBisector() { - } -Geom::Point LPEPerpBisector::left_end(Geom::Piecewise > const & pwd2_in) { - Geom::Point A(pwd2_in.firstValue()); - Geom::Point B(pwd2_in.lastValue()); - Geom::Point M((A + B)/2); - - Geom::Point dir1((B - M).ccw()); - - if (dir1.length() > Geom::EPSILON) - dir1 = Geom::unit_vector(dir1) * length_left; - - return M + dir1; +void +LPEPerpBisector::doOnApply (SPLPEItem *lpeitem) +{ + /* make the path a straight line */ + SPCurve* curve = sp_path_get_curve_for_edit (SP_PATH(lpeitem)); // TODO: Should we use sp_shape_get_curve()? + + Geom::Point A((curve->first_point()).to_2geom()); + Geom::Point B((curve->last_point()).to_2geom()); + + SPCurve *c = new SPCurve(); + c->moveto(A); + c->lineto(B); + // TODO: Why doesn't sp_path_set_original_curve(SP_PATH(lpeitem), c, TRUE, true) work? + SP_PATH(lpeitem)->original_curve = c->ref(); + c->unref(); } + Geom::Piecewise > LPEPerpBisector::doEffect_pwd2 (Geom::Piecewise > const & pwd2_in) { @@ -56,21 +159,14 @@ LPEPerpBisector::doEffect_pwd2 (Geom::Piecewise > const & Piecewise > output; - Point A(pwd2_in.firstValue()); - Point B(pwd2_in.lastValue()); - Point M((A + B)/2); - - Point dir1((B - M).ccw()); - Point dir2((A - M).ccw()); - - if (dir1.length() > EPSILON) - dir1 = unit_vector(dir1) * length_left; + A = pwd2_in.firstValue(); + B = pwd2_in.lastValue(); + M = (A + B)/2; - if (dir2.length() > EPSILON) - dir2 = unit_vector(dir2) * length_right; + perp_dir = unit_vector((B - A).ccw()); - Point C(M + dir1); - Point D(M + dir2); + C = M + perp_dir * length_left; + D = M - perp_dir * length_right; output = Piecewise >(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); diff --git a/src/live_effects/lpe-perp_bisector.h b/src/live_effects/lpe-perp_bisector.h index c25ba35f5..7c4f4fd4e 100644 --- a/src/live_effects/lpe-perp_bisector.h +++ b/src/live_effects/lpe-perp_bisector.h @@ -29,15 +29,30 @@ public: virtual EffectType effectType () { return PERP_BISECTOR; } + void doOnApply (SPLPEItem *lpeitem); + virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); - Geom::Point left_end(Geom::Piecewise > const & pwd2_in); + /* the knotholder functions below must be declared friends */ + friend NR::Point bisector_left_end_get(SPItem *item); + friend NR::Point bisector_right_end_get(SPItem *item); + friend NR::Point path_start_get(SPItem *item); + friend NR::Point path_end_get(SPItem *item); + friend void bisector_end_set(SPItem *item, NR::Point const &p, bool left = true); + friend void path_set_start_end(SPItem *item, NR::Point const &p, bool start = true); private: ScalarParam length_left; ScalarParam length_right; + Geom::Point A; // start of path + Geom::Point B; // end of path + Geom::Point M; // midpoint + Geom::Point C; // left end of bisector + Geom::Point D; // right end of bisector + Geom::Point perp_dir; + LPEPerpBisector(const LPEPerpBisector&); LPEPerpBisector& operator=(const LPEPerpBisector&); }; diff --git a/src/object-edit.cpp b/src/object-edit.cpp index 65b256b34..46ab877b6 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -32,6 +32,7 @@ #include "desktop.h" #include "desktop-handles.h" #include "sp-namedview.h" +#include "live_effects/effect.h" #include "sp-pattern.h" #include "sp-path.h" @@ -44,7 +45,7 @@ #include "xml/repr.h" -#include "isnan.h" +#include "2geom/isnan.h" #define sp_round(v,m) (((v) < 0.0) ? ((ceil((v) / (m) - 0.5)) * (m)) : ((floor((v) / (m) + 0.5)) * (m))) @@ -58,9 +59,23 @@ static SPKnotHolder *sp_misc_knot_holder(SPItem *item, SPDesktop *desktop); static SPKnotHolder *sp_flowtext_knot_holder(SPItem *item, SPDesktop *desktop); static void sp_pat_knot_holder(SPItem *item, SPKnotHolder *knot_holder); +static SPKnotHolder *sp_lpe_knot_holder(SPItem *item, SPDesktop *desktop) +{ + SPKnotHolder *knot_holder = sp_knot_holder_new(desktop, item, NULL); + + Inkscape::LivePathEffect::Effect *effect = sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item)); + effect->addHandles(knot_holder); + + return knot_holder; +} + SPKnotHolder * sp_item_knot_holder(SPItem *item, SPDesktop *desktop) { + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item)) && + sp_lpe_item_get_livepatheffect(SP_LPE_ITEM(item))->providesKnotholder()) { + return sp_lpe_knot_holder(item, desktop); + } else if (SP_IS_RECT(item)) { return sp_rect_knot_holder(item, desktop); } else if (SP_IS_BOX3D(item)) { @@ -1101,7 +1116,7 @@ sp_spiral_outer_set(SPItem *item, NR::Point const &p, NR::Point const &/*origin* spiral->rad = rad_new; spiral->t0 = pow(r0 / spiral->rad, 1.0/spiral->exp); } - if (!isFinite(spiral->t0)) spiral->t0 = 0.0; + if (!IS_FINITE(spiral->t0)) spiral->t0 = 0.0; spiral->t0 = CLAMP(spiral->t0, 0.0, 0.999); } diff --git a/src/shape-editor.cpp b/src/shape-editor.cpp index d73e99e7c..f0bec7ba9 100644 --- a/src/shape-editor.cpp +++ b/src/shape-editor.cpp @@ -190,7 +190,14 @@ void ShapeEditor::set_item(SPItem *item) { this->grab_node = -1; if (item) { - this->nodepath = sp_nodepath_new(desktop, item, (prefs_get_int_attribute("tools.nodes", "show_handles", 1) != 0)); + SPLPEItem *lpeitem = SP_LPE_ITEM(item); + if (!sp_lpe_item_has_path_effect(lpeitem) || + !sp_lpe_item_get_livepatheffect(lpeitem)->providesKnotholder()) { + // only create nodepath if the item either doesn't have an LPE + // or the LPE doesn't provide a knotholder itself + this->nodepath = + sp_nodepath_new(desktop, item, (prefs_get_int_attribute("tools.nodes", "show_handles", 1) != 0)); + } if (this->nodepath) { this->nodepath->shape_editor = this; }