diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 11 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.h | 3 | ||||
| -rw-r--r-- | src/live_effects/parameter/powerstrokepointarray.cpp | 36 | ||||
| -rw-r--r-- | src/live_effects/parameter/powerstrokepointarray.h | 5 | ||||
| -rw-r--r-- | src/ui/tool/curve-drag-point.cpp | 2 | ||||
| -rw-r--r-- | src/ui/tool/multi-path-manipulator.cpp | 18 | ||||
| -rw-r--r-- | src/ui/tool/multi-path-manipulator.h | 4 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.cpp | 34 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.h | 4 |
9 files changed, 90 insertions, 27 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 74a594a4b..56248907c 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -301,7 +301,7 @@ enum LineCuspType { static const Util::EnumData<unsigned> LineCuspTypeData[] = { {LINECUSP_BEVEL , N_("Beveled"), "bevel"}, {LINECUSP_ROUND , N_("Rounded"), "round"}, - {LINECUSP_SHARP , N_("Sharp"), "sharp"} +// not yet supported {LINECUSP_SHARP , N_("Sharp"), "sharp"} }; static const Util::EnumDataConverter<unsigned> LineCuspTypeConverter(LineCuspTypeData, sizeof(LineCuspTypeData)/sizeof(*LineCuspTypeData)); @@ -343,6 +343,12 @@ LPEPowerStroke::doOnApply(SPLPEItem *lpeitem) offset_points.param_set_and_write_new_value(points); } +void +LPEPowerStroke::adjustForNewPath(std::vector<Geom::Path> const & path_in) +{ + offset_points.recalculate_controlpoints_for_new_pwd2(path_in[0].toPwSb()); +} + static bool compare_offsets (Geom::Point first, Geom::Point second) { return first[Geom::X] < second[Geom::X]; @@ -435,10 +441,9 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) // for now, only regard first subpath and ignore the rest Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb(); - offset_points.set_pwd2(pwd2_in); Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); Piecewise<D2<SBasis> > n = rot90(der); - offset_points.set_pwd2_normal(n); + offset_points.set_pwd2(pwd2_in, n); std::vector<Geom::Point> ts = offset_points.data(); if (sort_points) { diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index bcfbdadc0..6c005f792 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -29,6 +29,9 @@ public: virtual void doOnApply(SPLPEItem *lpeitem); + // methods called by path-manipulator upon edits + void adjustForNewPath(std::vector<Geom::Path> const & path_in); + private: PowerStrokePointArrayParam offset_points; BoolParam sort_points; diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 5139f0e41..fccbad7e5 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -76,6 +76,42 @@ void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& /* } +/** call this method to recalculate the controlpoints such that they stay at the same location relative to the new path. Useful after adding/deleting nodes to the path.*/ +void +PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +{ + if (!last_pwd2.empty()) { + if (last_pwd2.size() > pwd2_in.size()) { + // Path has become shorter: rescale offsets + double factor = (double)pwd2_in.size() / (double)last_pwd2.size(); + for (unsigned int i = 0; i < _vector.size(); ++i) { + _vector[i][Geom::X] *= factor; + } + } else if (last_pwd2.size() < pwd2_in.size()) { + // Path has become longer: probably node added, maintain position of knots + Geom::Piecewise<Geom::D2<Geom::SBasis> > normal = rot90(unitVector(derivative(pwd2_in))); + for (unsigned int i = 0; i < _vector.size(); ++i) { + Geom::Point pt = _vector[i]; + Geom::Point position = last_pwd2.valueAt(pt[Geom::X]) + pt[Geom::Y] * last_pwd2_normal.valueAt(pt[Geom::X]); + + double t = nearest_point(position, pwd2_in); + double offset = dot(position - pwd2_in.valueAt(t), normal.valueAt(t)); + _vector[i] = Geom::Point(t, offset); + } + } + + write_to_SVG(); + } +} + +void +PowerStrokePointArrayParam::set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in) +{ + last_pwd2 = pwd2_in; + last_pwd2_normal = pwd2_normal_in; +} + + void PowerStrokePointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index d984a7de5..550866384 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -43,11 +43,12 @@ public: virtual bool providesKnotHolderEntities() { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); - void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { last_pwd2 = pwd2_in; } + 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() { return last_pwd2; } - void set_pwd2_normal(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { last_pwd2_normal = pwd2_in; } Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2_normal() { return last_pwd2_normal; } + void recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + friend class PowerStrokePointArrayParamKnotHolderEntity; private: diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp index a3fb5aa6e..8dafb55d7 100644 --- a/src/ui/tool/curve-drag-point.cpp +++ b/src/ui/tool/curve-drag-point.cpp @@ -153,7 +153,7 @@ void CurveDragPoint::_insertNode(bool take_selection) } _pm._selection.insert(inserted.ptr()); - _pm.update(); + _pm.update(true); _pm._commit(_("Add node")); } diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 27418d302..2316058ed 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -402,21 +402,21 @@ void MultiPathManipulator::joinNodes() invokeForAll(&PathManipulator::weldNodes, preserve_pos); } - _doneWithCleanup(_("Join nodes")); + _doneWithCleanup(_("Join nodes"), true); } void MultiPathManipulator::breakNodes() { if (_selection.empty()) return; invokeForAll(&PathManipulator::breakNodes); - _done(_("Break nodes")); + _done(_("Break nodes"), true); } void MultiPathManipulator::deleteNodes(bool keep_shape) { if (_selection.empty()) return; invokeForAll(&PathManipulator::deleteNodes, keep_shape); - _doneWithCleanup(_("Delete nodes")); + _doneWithCleanup(_("Delete nodes"), true); } /** Join selected endpoints to create segments. */ @@ -442,14 +442,14 @@ void MultiPathManipulator::joinSegments() if (joins.empty()) { invokeForAll(&PathManipulator::weldSegments); } - _doneWithCleanup("Join segments"); + _doneWithCleanup("Join segments", true); } void MultiPathManipulator::deleteSegments() { if (_selection.empty()) return; invokeForAll(&PathManipulator::deleteSegments); - _doneWithCleanup("Delete segments"); + _doneWithCleanup("Delete segments", true); } void MultiPathManipulator::alignNodes(Geom::Dim2 d) @@ -801,17 +801,17 @@ void MultiPathManipulator::_commit(CommitEvent cps) } /** Commits changes to XML and adds undo stack entry. */ -void MultiPathManipulator::_done(gchar const *reason) { - invokeForAll(&PathManipulator::update); +void MultiPathManipulator::_done(gchar const *reason, bool alert_LPE) { + invokeForAll(&PathManipulator::update, alert_LPE); invokeForAll(&PathManipulator::writeXML); DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_NODE, reason); signal_coords_changed.emit(); } /** Commits changes to XML, adds undo stack entry and removes empty manipulators. */ -void MultiPathManipulator::_doneWithCleanup(gchar const *reason) { +void MultiPathManipulator::_doneWithCleanup(gchar const *reason, bool alert_LPE) { _changed.block(); - _done(reason); + _done(reason, alert_LPE); cleanup(); _changed.unblock(); } diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index 29b618b5f..6b5686139 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -102,8 +102,8 @@ private: } void _commit(CommitEvent cps); - void _done(gchar const *); - void _doneWithCleanup(gchar const *); + void _done(gchar const *reason, bool alert_LPE = false); + void _doneWithCleanup(gchar const *reason, bool alert_LPE = false); guint32 _getOutlineColor(ShapeRole role); MapType _mmap; diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index a7369f915..96b3a1bb1 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -30,7 +30,9 @@ #include "document.h" #include "live_effects/effect.h" #include "live_effects/lpeobject.h" +#include "live_effects/lpeobject-reference.h" #include "live_effects/parameter/path.h" +#include "live_effects/lpe-powerstroke.h" #include "sp-path.h" #include "helper/geom.h" #include "preferences.h" @@ -137,7 +139,7 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path, sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(_outline), 0, SP_WIND_RULE_NONZERO); _selection.signal_update.connect( - sigc::mem_fun(*this, &PathManipulator::update)); + sigc::bind(sigc::mem_fun(*this, &PathManipulator::update), false)); _selection.signal_point_changed.connect( sigc::mem_fun(*this, &PathManipulator::_selectionChanged)); _desktop->signal_zoom_changed.connect( @@ -175,10 +177,12 @@ bool PathManipulator::empty() { return !_path || _subpaths.empty(); } -/** Update the display and the outline of the path. */ -void PathManipulator::update() +/** Update the display and the outline of the path. + * \param alert_LPE if true, alerts an applied LPE to what the path is going to be changed to, so it can adjust its parameters for nicer user interfacing + */ +void PathManipulator::update(bool alert_LPE) { - _createGeometryFromControlPoints(); + _createGeometryFromControlPoints(alert_LPE); } /** Store the changes to the path in XML. */ @@ -1094,8 +1098,10 @@ void PathManipulator::_createControlPointsFromGeometry() } /** Construct the geometric representation of nodes and handles, update the outline - * and display */ -void PathManipulator::_createGeometryFromControlPoints() + * and display + * \param alert_LPE if true, first the LPE is warned what the new path is going to be before updating it + */ +void PathManipulator::_createGeometryFromControlPoints(bool alert_LPE) { Geom::PathBuilder builder; for (std::list<SubpathPtr>::iterator spi = _subpaths.begin(); spi != _subpaths.end(); ) { @@ -1123,7 +1129,18 @@ void PathManipulator::_createGeometryFromControlPoints() ++spi; } builder.finish(); - _spcurve->set_pathvector(builder.peek() * (_edit_transform * _i2d_transform).inverse()); + Geom::PathVector pathv = builder.peek() * (_edit_transform * _i2d_transform).inverse(); + _spcurve->set_pathvector(pathv); + if (alert_LPE) { + if (SP_IS_LPE_ITEM(_path) && sp_lpe_item_has_path_effect(SP_LPE_ITEM(_path))) { + PathEffectList effect_list = sp_lpe_item_get_effect_list(SP_LPE_ITEM(_path)); + LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>( effect_list.front()->lpeobject->get_lpe() ); + if (lpe_pwr) { + lpe_pwr->adjustForNewPath(pathv); + } + } + } + if (_live_outline) _updateOutline(); if (_live_objects) @@ -1281,8 +1298,9 @@ bool PathManipulator::_nodeClicked(Node *n, GdkEventButton *event) } if (!empty()) { - update(); + update(true); } + // We need to call MPM's method because it could have been our last node _multi_path_manipulator._doneWithCleanup(_("Delete node")); diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index edaf5a8de..e3b724e37 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -60,7 +60,7 @@ public: bool empty(); void writeXML(); - void update(); // update display, but don't commit + void update(bool alert_LPE = false); // update display, but don't commit void clear(); // remove all nodes from manipulator SPPath *item() { return _path; } @@ -102,7 +102,7 @@ private: typedef boost::shared_ptr<NodeList> SubpathPtr; void _createControlPointsFromGeometry(); - void _createGeometryFromControlPoints(); + void _createGeometryFromControlPoints(bool alert_LPE = false); unsigned _deleteStretch(NodeList::iterator first, NodeList::iterator last, bool keep_shape); std::string _createTypeString(); void _updateOutline(); |
