diff options
Diffstat (limited to 'src/ui/tool/path-manipulator.cpp')
| -rw-r--r-- | src/ui/tool/path-manipulator.cpp | 170 |
1 files changed, 156 insertions, 14 deletions
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 338499672..8b99c33b8 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -11,6 +11,7 @@ */ #include "live_effects/lpe-powerstroke.h" +#include "live_effects/lpe-fillet-chamfer.h" #include <string> #include <sstream> #include <deque> @@ -42,6 +43,7 @@ #include "ui/tool/multi-path-manipulator.h" #include "xml/node.h" #include "xml/node-observer.h" +#include "live_effects/lpe-bspline.h" namespace Inkscape { namespace UI { @@ -54,6 +56,10 @@ enum PathChange { }; } // anonymous namespace +const double handleCubicGap = 0.01; +const double noPower = 0.0; +const double defaultStartPower = 0.3334; + /** * Notifies the path manipulator when something changes the path being edited @@ -102,7 +108,6 @@ private: }; void build_segment(Geom::PathBuilder &, Node *, Node *); - PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Affine const &et, guint32 outline_color, Glib::ustring lpe_key) : PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection) @@ -139,12 +144,14 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path, _selection.signal_update.connect( sigc::bind(sigc::mem_fun(*this, &PathManipulator::update), false)); - _selection.signal_point_changed.connect( - sigc::mem_fun(*this, &PathManipulator::_selectionChanged)); + _selection.signal_selection_changed.connect( + sigc::mem_fun(*this, &PathManipulator::_selectionChangedM)); _desktop->signal_zoom_changed.connect( sigc::hide( sigc::mem_fun(*this, &PathManipulator::_updateOutlineOnZoomChange))); _createControlPointsFromGeometry(); + //Define if the path is BSpline on construction + isBSpline(true); } PathManipulator::~PathManipulator() @@ -662,6 +669,15 @@ unsigned PathManipulator::_deleteStretch(NodeList::iterator start, NodeList::ite nl.erase(start); start = next; } + // if we are removing, we readjust the handlers + if(isBSpline()){ + if(start.prev()){ + start.prev()->front()->setPosition(BSplineHandleReposition(start.prev()->front(),start.prev()->back())); + } + if(end){ + end->back()->setPosition(BSplineHandleReposition(end->back(),end->front())); + } + } return del_len; } @@ -816,7 +832,6 @@ void PathManipulator::scaleHandle(Node *n, int which, int dir, bool pixel) } h->setRelativePos(relpos); update(); - gchar const *key = which < 0 ? "handle:scale:left" : "handle:scale:right"; _commit(_("Scale handle"), key); } @@ -980,9 +995,36 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d // set new handle positions Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]); - n->back()->setPosition(seg1[2]); - n->front()->setPosition(seg2[1]); - n->setType(NODE_SMOOTH, false); + if(!isBSpline()){ + n->back()->setPosition(seg1[2]); + n->front()->setPosition(seg2[1]); + n->setType(NODE_SMOOTH, false); + } else { + Geom::D2< Geom::SBasis > SBasisInsideNodes; + SPCurve *lineInsideNodes = new SPCurve(); + if(second->back()->isDegenerate()){ + lineInsideNodes->moveto(n->position()); + lineInsideNodes->lineto(second->position()); + SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis(); + Geom::Point next = SBasisInsideNodes.valueAt(defaultStartPower); + next = Geom::Point(next[Geom::X] + handleCubicGap,next[Geom::Y] + handleCubicGap); + lineInsideNodes->reset(); + n->front()->setPosition(next); + }else{ + n->front()->setPosition(seg2[1]); + } + if(first->front()->isDegenerate()){ + lineInsideNodes->moveto(n->position()); + lineInsideNodes->lineto(first->position()); + SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis(); + Geom::Point previous = SBasisInsideNodes.valueAt(defaultStartPower); + previous = Geom::Point(previous[Geom::X] + handleCubicGap,previous[Geom::Y] + handleCubicGap); + n->back()->setPosition(previous); + }else{ + n->back()->setPosition(seg1[2]); + } + n->setType(NODE_CUSP, false); + } inserted = list.insert(insert_at, n); first->front()->move(seg1[1]); @@ -1104,7 +1146,6 @@ void PathManipulator::_createControlPointsFromGeometry() Geom::Curve const &cseg = pit->back_closed(); bool fuse_ends = pit->closed() && Geom::are_near(cseg.initialPoint(), cseg.finalPoint()); - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { Geom::Point pos = cit->finalPoint(); Node *current_node; @@ -1171,6 +1212,91 @@ void PathManipulator::_createControlPointsFromGeometry() } } +//determines if the trace has a bspline effect and the number of steps that it takes +int PathManipulator::BSplineGetSteps() const { + + LivePathEffect::LPEBSpline const *lpe_bsp = NULL; + + if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){ + Inkscape::LivePathEffect::Effect const *thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::BSPLINE); + if(thisEffect){ + lpe_bsp = dynamic_cast<LivePathEffect::LPEBSpline const*>(thisEffect->getLPEObj()->get_lpe()); + } + } + int steps = 0; + if(lpe_bsp){ + steps = lpe_bsp->steps+1; + } + return steps; +} + +// determines if the trace has bspline effect +bool PathManipulator::isBSpline(bool recalculate){ + if(recalculate){ + _is_bspline = this->BSplineGetSteps() > 0; + } + return _is_bspline; +} + +bool PathManipulator::isBSpline() const { + return BSplineGetSteps() > 0; +} + +// returns the corresponding strength to the position of the handlers +double PathManipulator::BSplineHandlePosition(Handle *h, Handle *h2){ + using Geom::X; + using Geom::Y; + if(h2){ + h = h2; + } + double pos = noPower; + Node *n = h->parent(); + Node * nextNode = NULL; + nextNode = n->nodeToward(h); + if(nextNode){ + SPCurve *lineInsideNodes = new SPCurve(); + lineInsideNodes->moveto(n->position()); + lineInsideNodes->lineto(nextNode->position()); + if(!are_near(h->position(), n->position())){ + pos = Geom::nearest_point(Geom::Point(h->position()[X] - handleCubicGap, h->position()[Y] - handleCubicGap), *lineInsideNodes->first_segment()); + } + } + if (pos == noPower && !h2){ + return BSplineHandlePosition(h, h->other()); + } + return pos; +} + +// give the location for the handler in the corresponding position +Geom::Point PathManipulator::BSplineHandleReposition(Handle *h, Handle *h2){ + double pos = this->BSplineHandlePosition(h, h2); + return BSplineHandleReposition(h,pos); +} + +// give the location for the handler to the specified position +Geom::Point PathManipulator::BSplineHandleReposition(Handle *h,double pos){ + using Geom::X; + using Geom::Y; + Geom::Point ret = h->position(); + Node *n = h->parent(); + Geom::D2< Geom::SBasis > SBasisInsideNodes; + SPCurve *lineInsideNodes = new SPCurve(); + Node * nextNode = NULL; + nextNode = n->nodeToward(h); + if(nextNode && pos != noPower){ + lineInsideNodes->moveto(n->position()); + lineInsideNodes->lineto(nextNode->position()); + SBasisInsideNodes = lineInsideNodes->first_segment()->toSBasis(); + ret = SBasisInsideNodes.valueAt(pos); + ret = Geom::Point(ret[X] + handleCubicGap,ret[Y] + handleCubicGap); + }else{ + if(pos == noPower){ + ret = n->position(); + } + } + return ret; +} + /** Construct the geometric representation of nodes and handles, update the outline * and display * \param alert_LPE if true, first the LPE is warned what the new path is going to be before updating it @@ -1178,6 +1304,8 @@ void PathManipulator::_createControlPointsFromGeometry() void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) { Geom::PathBuilder builder; + //Refresh if is bspline some times -think on path change selection, this value get lost + isBSpline(true); for (std::list<SubpathPtr>::iterator spi = _subpaths.begin(); spi != _subpaths.end(); ) { SubpathPtr subpath = *spi; if (subpath->empty()) { @@ -1186,7 +1314,6 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) } NodeList::iterator prev = subpath->begin(); builder.moveTo(prev->position()); - for (NodeList::iterator i = ++subpath->begin(); i != subpath->end(); ++i) { build_segment(builder, prev.ptr(), i.ptr()); prev = i; @@ -1207,11 +1334,20 @@ void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) _spcurve->set_pathvector(pathv); if (alert_LPE) { /// \todo note that _path can be an Inkscape::LivePathEffect::Effect* too, kind of confusing, rework member naming? - if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()) { - PathEffectList effect_list = _path->getEffectList(); - LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>( effect_list.front()->lpeobject->get_lpe() ); - if (lpe_pwr) { - lpe_pwr->adjustForNewPath(pathv); + if (SP_IS_LPE_ITEM(_path) && _path->hasPathEffect()){ + Inkscape::LivePathEffect::Effect* thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE); + if(thisEffect){ + LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>(thisEffect->getLPEObj()->get_lpe()); + if (lpe_pwr) { + lpe_pwr->adjustForNewPath(pathv); + } + } + thisEffect = SP_LPE_ITEM(_path)->getPathEffectOfType(Inkscape::LivePathEffect::FILLET_CHAMFER); + if(thisEffect){ + LivePathEffect::LPEFilletChamfer *lpe_fll = dynamic_cast<LivePathEffect::LPEFilletChamfer*>(thisEffect->getLPEObj()->get_lpe()); + if (lpe_fll) { + lpe_fll->adjustForNewPath(pathv); + } } } } @@ -1419,6 +1555,12 @@ bool PathManipulator::_handleClicked(Handle *h, GdkEventButton *event) return false; } +void PathManipulator::_selectionChangedM(std::vector<SelectableControlPoint *> pvec, bool selected) { + for (size_t n = 0, e = pvec.size(); n < e; ++n) { + _selectionChanged(pvec[n], selected); + } +} + void PathManipulator::_selectionChanged(SelectableControlPoint *p, bool selected) { if (selected) ++_num_selected; |
