diff options
Diffstat (limited to 'src/live_effects/lpe-roughen.cpp')
| -rw-r--r-- | src/live_effects/lpe-roughen.cpp | 392 |
1 files changed, 294 insertions, 98 deletions
diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 33ffd96d6..105fe2fc4 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -18,7 +18,9 @@ #include "live_effects/lpe-roughen.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" +#include <boost/functional/hash.hpp> #include "helper/geom.h" +#include "sp-item-group.h" #include <glibmm/i18n.h> #include <cmath> @@ -32,13 +34,22 @@ static const Util::EnumData<DivisionMethod> DivisionMethodData[DM_END] = { static const Util::EnumDataConverter<DivisionMethod> DMConverter(DivisionMethodData, DM_END); +static const Util::EnumData<HandlesMethod> HandlesMethodData[HM_END] = { + { HM_ALONG_NODES, N_("Along nodes"), "along" }, + { HM_RAND, N_("Rand"), "rand" }, + { HM_RETRACT, N_("Retract"), "retract" }, + { HM_SMOOTH, N_("Smooth"), "smooth" } +}; +static const Util::EnumDataConverter<HandlesMethod> +HMConverter(HandlesMethodData, HM_END); + LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: method(_("Method"), _("Division method"), "method", DMConverter, &wr, this, DM_SEGMENTS), max_segment_size(_("Max. segment size"), _("Max. segment size"), - "max_segment_size", &wr, this, 10.), + "max_segment_size", &wr, this, 10), segments(_("Number of segments"), _("Number of segments"), "segments", &wr, this, 2), displace_x(_("Max. displacement in X"), _("Max. displacement in X"), @@ -47,10 +58,14 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) "displace_y", &wr, this, 10.), global_randomize(_("Global randomize"), _("Global randomize"), "global_randomize", &wr, this, 1.), + handles(_("Handles"), _("Handles options"), "handles", HMConverter, &wr, + this, HM_ALONG_NODES), shift_nodes(_("Shift nodes"), _("Shift nodes"), "shift_nodes", &wr, this, true), - shift_node_handles(_("Shift node handles"), _("Shift node handles"), - "shift_node_handles", &wr, this, true) + fixed_displacement(_("Fixed displacement"), _("Fixed displacement, 1/3 of segment length"), + "fixed_displacement", &wr, this, false), + spray_tool_friendly(_("Spray Tool friendly"), _("For use with spray tool in copy mode"), + "spray_tool_friendly", &wr, this, false) { registerParameter(&method); registerParameter(&max_segment_size); @@ -58,8 +73,10 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) registerParameter(&displace_x); registerParameter(&displace_y); registerParameter(&global_randomize); + registerParameter(&handles); registerParameter(&shift_nodes); - registerParameter(&shift_node_handles); + registerParameter(&fixed_displacement); + registerParameter(&spray_tool_friendly); displace_x.param_set_range(0., Geom::infinity()); displace_y.param_set_range(0., Geom::infinity()); global_randomize.param_set_range(0., Geom::infinity()); @@ -69,19 +86,23 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) segments.param_set_range(1, Geom::infinity()); segments.param_set_increments(1, 1); segments.param_set_digits(0); + seed = 0; + apply_to_clippath_and_mask = true; } LPERoughen::~LPERoughen() {} void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem) { + if(spray_tool_friendly && seed == 0 && SP_OBJECT(lpeitem)->getId()){ + std::string id_item(SP_OBJECT(lpeitem)->getId()); + long seed = static_cast<long>(boost::hash_value(id_item)); + global_randomize.param_set_value(global_randomize.get_value(), seed); + } displace_x.resetRandomizer(); displace_y.resetRandomizer(); global_randomize.resetRandomizer(); srand(1); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); } Gtk::Widget *LPERoughen::newWidget() @@ -122,6 +143,15 @@ Gtk::Widget *LPERoughen::newWidget() vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } + if (param->param_key == "handles") { + Gtk::Label *options = Gtk::manage(new Gtk::Label( + Glib::ustring(_("<b>Options</b> Modify options to rough")), + Gtk::ALIGN_START)); + options->set_use_markup(true); + vbox->pack_start(*options, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } Glib::ustring *tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -133,7 +163,6 @@ Gtk::Widget *LPERoughen::newWidget() } } } - ++it; } return dynamic_cast<Gtk::Widget *>(vbox); @@ -147,19 +176,25 @@ double LPERoughen::sign(double random_number) return random_number; } -Geom::Point LPERoughen::randomize() +Geom::Point LPERoughen::randomize(double max_lenght, bool is_node) { - double displace_x_parsed = displace_x * global_randomize; - double displace_y_parsed = displace_y * global_randomize; - + double factor = 1.0/3.0; + if(is_node){ + factor = 1.0; + } + double displace_x_parsed = displace_x * global_randomize * factor; + double displace_y_parsed = displace_y * global_randomize * factor; Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed)); + if( fixed_displacement ){ + Geom::Ray ray(Geom::Point(0,0),output); + output = Geom::Point::polar(ray.angle(), max_lenght); + } return output; } void LPERoughen::doEffect(SPCurve *curve) { - Geom::PathVector const original_pathv = - pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); curve->reset(); for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { @@ -170,41 +205,30 @@ void LPERoughen::doEffect(SPCurve *curve) Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); Geom::Path::const_iterator curve_endit = path_it->end_default(); SPCurve *nCurve = new SPCurve(); + Geom::Point prev(0, 0); + Geom::Point last_move(0, 0); + nCurve->moveto(curve_it1->initialPoint()); if (path_it->closed()) { - const Geom::Curve &closingline = - path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - Geom::Point initialMove(0, 0); - if (shift_nodes) { - initialMove = randomize(); + const Geom::Curve &closingline = path_it->back_closed(); + // the closing line segment is always of type + // Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } } - Geom::Point initialPoint = curve_it1->initialPoint() + initialMove; - nCurve->moveto(initialPoint); - Geom::Point point0(0, 0); - Geom::Point point1(0, 0); - Geom::Point point2(0, 0); - Geom::Point point3(0, 0); - bool first = true; while (curve_it1 != curve_endit) { Geom::CubicBezier const *cubic = NULL; - point0 = curve_it1->initialPoint(); - point1 = curve_it1->initialPoint(); - point2 = curve_it1->finalPoint(); - point3 = curve_it1->finalPoint(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - point1 = (*cubic)[1]; - if (shift_nodes && first) { - point1 = (*cubic)[1] + initialMove; - } - point2 = (*cubic)[2]; - nCurve->curveto(point1, point2, point3); + nCurve->curveto((*cubic)[1] + last_move, (*cubic)[2], curve_it1->finalPoint()); } else { - nCurve->lineto(point3); + nCurve->lineto(curve_it1->finalPoint()); } + last_move = Geom::Point(0, 0); double length = curve_it1->length(0.001); std::size_t splits = 0; if (method == DM_SEGMENTS) { @@ -212,15 +236,21 @@ void LPERoughen::doEffect(SPCurve *curve) } else { splits = ceil(length / max_segment_size); } - for (unsigned int t = splits; t >= 1; t--) { - if (t == 1 && splits != 1) { + Geom::Curve const * original = nCurve->last_segment()->duplicate() ; + for (unsigned int t = 1; t <= splits; t++) { + if(t == splits && splits != 1){ continue; } - const SPCurve *tmp; + SPCurve const * tmp; if (splits == 1) { - tmp = jitter(nCurve->last_segment()); + tmp = jitter(nCurve->last_segment(), prev, last_move); } else { - tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); + bool last = false; + if(t == splits-1){ + last = true; + } + double time = Geom::nearest_time(original->pointAt((1. / (double)splits) * t), *nCurve->last_segment()); + tmp = addNodesAndJitter(nCurve->last_segment(), prev, last_move, time, last); } if (nCurve->get_segment_count() > 1) { nCurve->backspace(); @@ -231,12 +261,44 @@ void LPERoughen::doEffect(SPCurve *curve) delete tmp; } ++curve_it1; - if(curve_it2 != curve_endit) { - ++curve_it2; - } - first = false; + ++curve_it2; } if (path_it->closed()) { + if(handles == HM_SMOOTH && curve_it1 == curve_endit){ + SPCurve *out = new SPCurve(); + nCurve = nCurve->create_reverse(); + Geom::CubicBezier const *cubic_start = dynamic_cast<Geom::CubicBezier const *>(nCurve->first_segment()); + Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment()); + Geom::Point oposite = nCurve->first_segment()->pointAt(1.0/3.0); + if(cubic_start){ + Geom::Ray ray((*cubic_start)[1], (*cubic_start)[0]); + double dist = Geom::distance((*cubic_start)[1], (*cubic_start)[0]); + oposite = Geom::Point::polar(ray.angle(),dist) + (*cubic_start)[0]; + } + if(cubic){ + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1], oposite, (*cubic)[3]); + } else { + out->moveto(nCurve->last_segment()->initialPoint()); + out->curveto(nCurve->last_segment()->initialPoint(), oposite, nCurve->last_segment()->finalPoint()); + } + nCurve->backspace(); + nCurve->append_continuous(out, 0.001); + nCurve = nCurve->create_reverse(); + } + if(handles == HM_ALONG_NODES && curve_it1 == curve_endit){ + SPCurve *out = new SPCurve(); + nCurve = nCurve->create_reverse(); + Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment()); + if(cubic){ + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1], (*cubic)[2] - ((*cubic)[3] - nCurve->first_segment()->initialPoint()) , (*cubic)[3]); + nCurve->backspace(); + nCurve->append_continuous(out, 0.001); + } + nCurve = nCurve->create_reverse(); + } + nCurve->move_endpoints(nCurve->last_segment()->finalPoint(), nCurve->last_segment()->finalPoint()); nCurve->closepath_current(); } curve->append(nCurve, false); @@ -245,77 +307,211 @@ void LPERoughen::doEffect(SPCurve *curve) } } -SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) +SPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last) { SPCurve *out = new SPCurve(); Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A); - Geom::Point point1(0, 0); - Geom::Point point2(0, 0); - Geom::Point point3(0, 0); + double max_lenght = Geom::distance(A->initialPoint(),A->pointAt(t)) / 3.0; + Geom::Point point_a1(0, 0); + Geom::Point point_a2(0, 0); + Geom::Point point_a3(0, 0); Geom::Point point_b1(0, 0); Geom::Point point_b2(0, 0); Geom::Point point_b3(0, 0); if (shift_nodes) { - point3 = randomize(); - point_b3 = randomize(); + point_a3 = randomize(max_lenght, true); + if(last){ + point_b3 = randomize(max_lenght, true); + } } - if (shift_node_handles) { - point1 = randomize(); - point2 = randomize(); - point_b1 = randomize(); - point_b2 = randomize(); + if (handles == HM_RAND || handles == HM_SMOOTH) { + point_a1 = randomize(max_lenght); + point_a2 = randomize(max_lenght); + point_b1 = randomize(max_lenght); + if(last){ + point_b2 = randomize(max_lenght); + } } else { - point2 = point3; - point_b1 = point3; - point_b2 = point_b3; + point_a2 = point_a3; + point_b1 = point_a3; + if(last){ + point_b2 = point_b3; + } } - if (cubic) { - std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); - std::vector<Geom::Point> seg1 = div.first.controlPoints(), - seg2 = div.second.controlPoints(); - out->moveto(seg1[0]); - out->curveto(seg1[1] + point1, seg1[2] + point2, seg1[3] + point3); - out->curveto(seg2[1] + point_b1, seg2[2], seg2[3]); - } else if (shift_node_handles) { - out->moveto(A->initialPoint()); - out->curveto(A->pointAt(t / 3) + point1, A->pointAt((t / 3) * 2) + point2, - A->pointAt(t) + point3); - out->curveto(A->pointAt(t + (t / 3)) + point_b1, A->pointAt(t + ((t / 3) * 2)), - A->finalPoint()); - } else { + if(handles == HM_SMOOTH){ + if(cubic) { + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); + Geom::Ray ray(seg1[3] + point_a3, seg2[1] + point_a3); + double lenght = max_lenght; + if(!fixed_displacement ){ + lenght = Geom::distance(seg1[3] + point_a3, seg2[1] + point_a3); + } + point_b1 = seg1[3] + point_a3 + Geom::Point::polar(ray.angle() , lenght); + point_b2 = seg2[2]; + point_b3 = seg2[3] + point_b3; + point_a3 = seg1[3] + point_a3; + ray.setPoints(prev,A->initialPoint()); + point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght); + if(prev == Geom::Point(0,0)){ + point_a1 = randomize(max_lenght); + } + if(last){ + Geom::Path b2(point_b3); + b2.appendNew<Geom::LineSegment>(point_a3); + lenght = max_lenght; + ray.setPoints(point_b3, point_b2); + if(!fixed_displacement ){ + lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3); + } + point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght); + } + ray.setPoints(point_b1, point_a3); + point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght); + if(last){ + prev = point_b2; + } else { + prev = point_a2; + } + out->moveto(seg1[0]); + out->curveto(point_a1,point_a2,point_a3); + out->curveto(point_b1, point_b2, point_b3); + } else { + Geom::Ray ray(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3))); + double lenght = max_lenght; + if(!fixed_displacement ){ + lenght = Geom::distance(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3))); + } + point_b1 = A->pointAt(t) + point_a3 + Geom::Point::polar(ray.angle() , lenght); + point_b2 = A->pointAt(t +((t / 3) * 2)); + point_b3 = A->finalPoint() + point_b3; + point_a3 = A->pointAt(t) + point_a3; + ray.setPoints(prev,A->initialPoint()); + point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght); + if(prev == Geom::Point(0,0)){ + point_a1 = randomize(max_lenght); + } + if(last){ + Geom::Path b2(point_b3); + b2.appendNew<Geom::LineSegment>(point_a3); + lenght = max_lenght; + ray.setPoints(point_b3, point_b2); + if(!fixed_displacement ){ + lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3); + } + point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght); + } + ray.setPoints(point_b1, point_a3); + point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght); + if(last){ + prev = point_b2; + } else { + prev = point_a2; + } + out->moveto(A->initialPoint()); + out->curveto(point_a1,point_a2,point_a3); + out->curveto(point_b1, point_b2, point_b3); + } + } else if(handles == HM_RETRACT){ out->moveto(A->initialPoint()); - out->lineto(A->pointAt(t) + point3); - out->lineto(A->finalPoint()); + out->lineto(A->pointAt(t) + point_a3); + if(cubic && !last){ + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg2 = div.second.controlPoints(); + out->curveto(seg2[1], seg2[2], seg2[3]); + } else { + out->lineto(A->finalPoint() + point_b3); + } + } else if(handles == HM_ALONG_NODES){ + if (cubic) { + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); + out->moveto(seg1[0]); + out->curveto(seg1[1] + last_move, seg1[2] + point_a3, seg1[3] + point_a3); + last_move = point_a3; + if(last){ + last_move = point_b3; + } + out->curveto(seg2[1] + point_a3, seg2[2] + point_b3, seg2[3] + point_b3); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->pointAt(t) + point_a3); + out->lineto(A->finalPoint() + point_b3); + } + } else if(handles == HM_RAND) { + if (cubic) { + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); + out->moveto(seg1[0]); + out->curveto(seg1[1] + point_a1, seg1[2] + point_a2 + point_a3, seg1[3] + point_a3); + out->curveto(seg2[1] + point_a3 + point_b1, seg2[2] + point_b2 + point_b3, seg2[3] + point_b3); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->pointAt(t) + point_a3); + out->lineto(A->finalPoint() + point_b3); + } } return out; } -SPCurve *LPERoughen::jitter(const Geom::Curve *A) +SPCurve *LPERoughen::jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move) { SPCurve *out = new SPCurve(); Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A); - Geom::Point point1(0, 0); - Geom::Point point2(0, 0); - Geom::Point point3(0, 0); + double max_lenght = Geom::distance(A->initialPoint(),A->finalPoint()) / 3.0; + Geom::Point point_a1(0, 0); + Geom::Point point_a2(0, 0); + Geom::Point point_a3(0, 0); if (shift_nodes) { - point3 = randomize(); + point_a3 = randomize(max_lenght, true); } - if (shift_node_handles) { - point1 = randomize(); - point2 = randomize(); - } else { - point2 = point3; + if (handles == HM_RAND || handles == HM_SMOOTH) { + point_a1 = randomize(max_lenght); + point_a2 = randomize(max_lenght); } - if (cubic) { - out->moveto((*cubic)[0]); - out->curveto((*cubic)[1] + point1, (*cubic)[2] + point2, (*cubic)[3] + point3); - } else if (shift_node_handles) { + if(handles == HM_SMOOTH) { + if (cubic) { + Geom::Ray ray(prev,A->initialPoint()); + point_a1 = Geom::Point::polar(ray.angle(), max_lenght); + if(prev == Geom::Point(0,0)){ + point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght); + } + ray.setPoints((*cubic)[3] + point_a3, (*cubic)[2] + point_a3); + point_a2 = randomize(max_lenght, ray.angle()); + prev = (*cubic)[2] + point_a2; + out->moveto((*cubic)[0]); + out->curveto((*cubic)[0] + point_a1, (*cubic)[2] + point_a2 + point_a3, (*cubic)[3] + point_a3); + } else { + Geom::Ray ray(prev,A->initialPoint()); + point_a1 = Geom::Point::polar(ray.angle(), max_lenght); + if(prev==Geom::Point(0,0)){ + point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght); + } + ray.setPoints(A->finalPoint() + point_a3, A->pointAt((1.0/3.0) * 2) + point_a3); + point_a2 = randomize(max_lenght, ray.angle()); + prev = A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3; + out->moveto(A->initialPoint()); + out->curveto(A->initialPoint() + point_a1, A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3, A->finalPoint() + point_a3); + } + } else if(handles == HM_RETRACT){ out->moveto(A->initialPoint()); - out->curveto(A->pointAt(0.3333) + point1, A->pointAt(0.6666) + point2, - A->finalPoint() + point3); - } else { + out->lineto(A->finalPoint() + point_a3); + } else if (handles == HM_ALONG_NODES) { + if(cubic){ + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1] + last_move, (*cubic)[2] + point_a3, (*cubic)[3] + point_a3); + last_move = point_a3; + } else { + out->moveto(A->initialPoint()); + out->lineto(A->finalPoint() + point_a3); + } + } else if (handles == HM_RAND) { out->moveto(A->initialPoint()); - out->lineto(A->finalPoint() + point3); + out->curveto(A->pointAt(0.3333) + point_a1, A->pointAt(0.6666) + point_a2 + point_a3, + A->finalPoint() + point_a3); } return out; } |
