ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof * Roughen LPE implementation. Creates roughen paths.
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof * Jabier Arraiza Cenoz <jabier.arraiza@marker.es>
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof * Thanks to all people involved specialy to Josh Andler for the idea and to the
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof * original extensions authors.
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof * Copyright (C) 2014 Authors
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof * Released under GNU GPL, read the file 'COPYING' for more information
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxofstatic const Util::EnumData<DivisionMethod> DivisionMethodData[DM_END] = {
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof { DM_SEGMENTS, N_("By number of segments"), "segments" },
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxofstatic const Util::EnumDataConverter<DivisionMethod>
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxofstatic const Util::EnumData<HandlesMethod> HandlesMethodData[HM_END] = {
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxofstatic const Util::EnumDataConverter<HandlesMethod>
60db347ea19e568bd09c35a0248a9f78d7931ca0JabiertxofLPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof // initialise your parameters here:
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof method(_("Method"), _("Division method"), "method", DMConverter, &wr,
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof max_segment_size(_("Max. segment size"), _("Max. segment size"),
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof segments(_("Number of segments"), _("Number of segments"), "segments",
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof displace_x(_("Max. displacement in X"), _("Max. displacement in X"),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof displace_y(_("Max. displacement in Y"), _("Max. displacement in Y"),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof global_randomize(_("Global randomize"), _("Global randomize"),
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof handles(_("Handles"), _("Handles options"), "handles", HMConverter, &wr,
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof shift_nodes(_("Shift nodes"), _("Shift nodes"), "shift_nodes", &wr, this,
b04cfe75120fc5d17a8d2f24ca44e8e456cb74d5Yuri Chornoivan fixed_displacement(_("Fixed displacement"), _("Fixed displacement, 1/3 of segment length"),
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof spray_tool_friendly(_("Spray Tool friendly"), _("For use with spray tool in copy mode"),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof displace_x.param_set_range(0., Geom::infinity());
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof displace_y.param_set_range(0., Geom::infinity());
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof global_randomize.param_set_range(0., Geom::infinity());
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof max_segment_size.param_set_range(0., Geom::infinity());
2ce2003d5713154f99c32af18fb904a1af109031Jabiertxofvoid LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem)
610985fe6a87b78eebcd60309f673221a406f238jabiertxof if(spray_tool_friendly && seed == 0 && SP_OBJECT(lpeitem)->getId()){
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof std::string id_item(SP_OBJECT(lpeitem)->getId());
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof long seed = static_cast<long>(boost::hash_value(id_item));
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof global_randomize.param_set_value(global_randomize.get_value(), seed);
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof std::vector<Parameter *>::iterator it = param_vector.begin();
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof Gtk::Label *method_label = Gtk::manage(new Gtk::Label(
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Glib::ustring(_("<b>Add nodes</b> Subdivide each segment")),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof vbox->pack_start(*method_label, false, false, 2);
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof Gtk::Label *displace_x_label = Gtk::manage(new Gtk::Label(
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Glib::ustring(_("<b>Jitter nodes</b> Move nodes/handles")),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof vbox->pack_start(*displace_x_label, false, false, 2);
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
163aa8601274792f2afe8e24a061fed96b7a6599Jabiertxof Gtk::Label *global_rand = Gtk::manage(new Gtk::Label(
de641d2613f4eea940ba6eb6c52ea9bcda516ba2Jabiertxof Glib::ustring(_("<b>Extra roughen</b> Add a extra layer of rough")),
721286d6ce40a27fcd8b9483667a43ed09023b17Jabiertxof vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
3ab4e87511c6a42f29370bf22a9afcf759ca1d0dJabiertxof Gtk::Label *options = Gtk::manage(new Gtk::Label(
3ab4e87511c6a42f29370bf22a9afcf759ca1d0dJabiertxof Glib::ustring(_("<b>Options</b> Modify options to rough")),
3ab4e87511c6a42f29370bf22a9afcf759ca1d0dJabiertxof vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
c2e7008ce6d44e568eb899040b80336e3465882eJabiertxofGeom::Point LPERoughen::randomize(double max_lenght, bool is_node)
c2e7008ce6d44e568eb899040b80336e3465882eJabiertxof double displace_x_parsed = displace_x * global_randomize * factor;
c2e7008ce6d44e568eb899040b80336e3465882eJabiertxof double displace_y_parsed = displace_y * global_randomize * factor;
c2e7008ce6d44e568eb899040b80336e3465882eJabiertxof Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed));
9d766cc272a22da6d0de4ebf6896da731b6c45c0jabiertxof output = Geom::Point::polar(ray.angle(), max_lenght);
8fbc43f88a5488f54a1b99fcc08e340c7c1edf32jabiertxof Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector());
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Geom::Path::const_iterator curve_it1 = path_it->begin();
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Geom::Path::const_iterator curve_endit = path_it->end_default();
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof const Geom::Curve &closingline = path_it->back_closed();
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof // the closing line segment is always of type
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof // Geom::LineSegment.
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof // closingline.isDegenerate() did not work, because it only checks for
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof // *exact* zero length, which goes wrong for relative coordinates and
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof // rounding errors...
90536c2550e30d32a103d11bff4bb61ad00812aejabiertxof // the closing line segment has zero-length. So stop before that one!
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof nCurve->curveto((*cubic)[1] + last_move, (*cubic)[2], curve_it1->finalPoint());
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof Geom::Curve const * original = nCurve->last_segment()->duplicate() ;
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof tmp = jitter(nCurve->last_segment(), prev, last_move);
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof double time = Geom::nearest_time(original->pointAt((1. / (double)splits) * t), *nCurve->last_segment());
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof tmp = addNodesAndJitter(nCurve->last_segment(), prev, last_move, time, last);
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof if(handles == HM_SMOOTH && curve_it1 == curve_endit){
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof Geom::CubicBezier const *cubic_start = dynamic_cast<Geom::CubicBezier const *>(nCurve->first_segment());
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
9d766cc272a22da6d0de4ebf6896da731b6c45c0jabiertxof Geom::Point oposite = nCurve->first_segment()->pointAt(1.0/3.0);
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof Geom::Ray ray((*cubic_start)[1], (*cubic_start)[0]);
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof double dist = Geom::distance((*cubic_start)[1], (*cubic_start)[0]);
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof oposite = Geom::Point::polar(ray.angle(),dist) + (*cubic_start)[0];
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof out->moveto(nCurve->last_segment()->initialPoint());
dbe3e7dacd7d4490ef69cc21314dc718b4706ae5jabiertxof out->curveto(nCurve->last_segment()->initialPoint(), oposite, nCurve->last_segment()->finalPoint());
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof if(handles == HM_ALONG_NODES && curve_it1 == curve_endit){
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
5b08636b45863e8af3f4c0d22a9235d565f2139ejabiertxof out->curveto((*cubic)[1], (*cubic)[2] - ((*cubic)[3] - nCurve->first_segment()->initialPoint()) , (*cubic)[3]);
9d766cc272a22da6d0de4ebf6896da731b6c45c0jabiertxof nCurve->move_endpoints(nCurve->last_segment()->finalPoint(), nCurve->last_segment()->finalPoint());
a7e81150b867e54cf50d331e30bb88f5676248c6JabiertxofSPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last)
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A);
9d766cc272a22da6d0de4ebf6896da731b6c45c0jabiertxof double max_lenght = Geom::distance(A->initialPoint(),A->pointAt(t)) / 3.0;
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof if (handles == HM_RAND || handles == HM_SMOOTH) {
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof std::vector<Geom::Point> seg1 = div.first.controlPoints(),
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof Geom::Ray ray(seg1[3] + point_a3, seg2[1] + point_a3);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof lenght = Geom::distance(seg1[3] + point_a3, seg2[1] + point_a3);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof point_b1 = seg1[3] + point_a3 + Geom::Point::polar(ray.angle() , lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof Geom::Ray ray(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3)));
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof lenght = Geom::distance(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3)));
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof point_b1 = A->pointAt(t) + point_a3 + Geom::Point::polar(ray.angle() , lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3);
7d52c19411e2bb66373fcf808bb2481165b31c26Jabiertxof point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght);
8fbc43f88a5488f54a1b99fcc08e340c7c1edf32jabiertxof std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
8fbc43f88a5488f54a1b99fcc08e340c7c1edf32jabiertxof std::vector<Geom::Point> seg2 = div.second.controlPoints();
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof std::vector<Geom::Point> seg1 = div.first.controlPoints(),
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof out->curveto(seg1[1] + last_move, seg1[2] + point_a3, seg1[3] + point_a3);
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof out->curveto(seg2[1] + point_a3, seg2[2] + point_b3, seg2[3] + point_b3);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof std::vector<Geom::Point> seg1 = div.first.controlPoints(),
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof out->curveto(seg1[1] + point_a1, seg1[2] + point_a2 + point_a3, seg1[3] + point_a3);
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof out->curveto(seg2[1] + point_a3 + point_b1, seg2[2] + point_b2 + point_b3, seg2[3] + point_b3);
a7e81150b867e54cf50d331e30bb88f5676248c6JabiertxofSPCurve *LPERoughen::jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move)
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A);
9d766cc272a22da6d0de4ebf6896da731b6c45c0jabiertxof double max_lenght = Geom::distance(A->initialPoint(),A->finalPoint()) / 3.0;
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof if (handles == HM_RAND || handles == HM_SMOOTH) {
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a1 = Geom::Point::polar(ray.angle(), max_lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof ray.setPoints((*cubic)[3] + point_a3, (*cubic)[2] + point_a3);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof out->curveto((*cubic)[0] + point_a1, (*cubic)[2] + point_a2 + point_a3, (*cubic)[3] + point_a3);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a1 = Geom::Point::polar(ray.angle(), max_lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof ray.setPoints(A->finalPoint() + point_a3, A->pointAt((1.0/3.0) * 2) + point_a3);
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof prev = A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3;
cd37beb25860ded72c3a03f3f32dbb27047ce644Jabiertxof out->curveto(A->initialPoint() + point_a1, A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3, A->finalPoint() + point_a3);
a7e81150b867e54cf50d331e30bb88f5676248c6Jabiertxof out->curveto((*cubic)[1] + last_move, (*cubic)[2] + point_a3, (*cubic)[3] + point_a3);
8fbc43f88a5488f54a1b99fcc08e340c7c1edf32jabiertxof out->curveto(A->pointAt(0.3333) + point_a1, A->pointAt(0.6666) + point_a2 + point_a3,
163aa8601274792f2afe8e24a061fed96b7a6599JabiertxofGeom::Point LPERoughen::tPoint(Geom::Point A, Geom::Point B, double t)
ccbee7d45f91658e83a602a9a28ee26162a261f9Jabiertxof return Geom::Point(A[X] + t * (B[X] - A[X]), A[Y] + t * (B[Y] - A[Y]));
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof}; //namespace LivePathEffect
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof}; /* namespace Inkscape */
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof Local Variables:
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof c-file-style:"stroustrup"
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof indent-tabs-mode:nil
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof fill-column:99
60db347ea19e568bd09c35a0248a9f78d7931ca0Jabiertxof// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :