summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/live_effects/lpe-powerstroke.cpp11
-rw-r--r--src/live_effects/lpe-powerstroke.h3
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.cpp36
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.h5
-rw-r--r--src/ui/tool/curve-drag-point.cpp2
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp18
-rw-r--r--src/ui/tool/multi-path-manipulator.h4
-rw-r--r--src/ui/tool/path-manipulator.cpp34
-rw-r--r--src/ui/tool/path-manipulator.h4
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();