summaryrefslogtreecommitdiffstats
path: root/src/ui/tool/path-manipulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/tool/path-manipulator.cpp')
-rw-r--r--src/ui/tool/path-manipulator.cpp170
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;