diff options
| author | Jabier Arraiza <jabier.arraiza@marker.es> | 2018-03-30 22:39:26 +0000 |
|---|---|---|
| committer | Jabier Arraiza <jabier.arraiza@marker.es> | 2018-04-01 00:32:25 +0000 |
| commit | f356f24c488ef6bfd03c780b6ca986266199e62f (patch) | |
| tree | 3689a0f2f584936b74b5ecb3dabc21979a34b985 /src | |
| parent | Repair broken link by moving hacking file to contributing. (diff) | |
| download | inkscape-f356f24c488ef6bfd03c780b6ca986266199e62f.tar.gz inkscape-f356f24c488ef6bfd03c780b6ca986266199e62f.zip | |
Add LPE Dash Stroke
Diffstat (limited to 'src')
| -rw-r--r-- | src/helper/geom-pathvectorsatellites.cpp.rej | 38 | ||||
| -rw-r--r-- | src/live_effects/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/live_effects/effect-enum.h | 1 | ||||
| -rw-r--r-- | src/live_effects/effect.cpp | 7 | ||||
| -rw-r--r-- | src/live_effects/lpe-dash-stroke.cpp | 244 | ||||
| -rw-r--r-- | src/live_effects/lpe-dash-stroke.h | 34 | ||||
| -rw-r--r-- | src/live_effects/lpe-fillet-chamfer.cpp.rej | 41 |
7 files changed, 366 insertions, 1 deletions
diff --git a/src/helper/geom-pathvectorsatellites.cpp.rej b/src/helper/geom-pathvectorsatellites.cpp.rej new file mode 100644 index 000000000..a480c16f5 --- /dev/null +++ b/src/helper/geom-pathvectorsatellites.cpp.rej @@ -0,0 +1,38 @@ +--- src/helper/geom-pathvectorsatellites.cpp ++++ src/helper/geom-pathvectorsatellites.cpp +@@ -41,7 +41,7 @@ size_t PathVectorSatellites::getTotalSatellites() + { + size_t counter = 0; + for (size_t i = 0; i < _satellites.size(); ++i) { +- for (size_t j = 0; j < _satellites[i].size(); ++j) { ++ for (size_t j = 0; j < _satellites[i].size(); ++j) { + counter++; + } + } +@@ -204,10 +204,24 @@ void PathVectorSatellites::recalculateForNewPathVector(Geom::PathVector const pa + size_t previous_number_nodes = _pathvector.nodes().size(); + for (size_t i = 0; i < pathv.size(); i++) { + std::vector<Satellite> path_satellites; +- for (size_t j = 0; j < pathv[i].size_closed(); j++) { ++ size_t count = pathv[i].size_default(); ++ if ( pathv[i].closed()) { ++ const Geom::Curve &closingline = pathv[i].back_closed(); ++ if (are_near(closingline.initialPoint(), closingline.finalPoint())) { ++ count = pathv[i].size_open(); ++ } ++ } ++ for (size_t j = 0; j < count; j++) { + found = false; + for (size_t k = 0; k < _pathvector.size(); k++) { +- for (size_t l = 0; l < _pathvector[k].size_closed(); l++) { ++ size_t count2 = _pathvector[k].size_default(); ++ if ( _pathvector[k].closed()) { ++ const Geom::Curve &closingline = _pathvector[k].back_closed(); ++ if (are_near(closingline.initialPoint(), closingline.finalPoint())) { ++ count2 = _pathvector[k].size_open(); ++ } ++ } ++ for (size_t l = 0; l < count2; l++) { + if (Geom::are_near(_pathvector[k][l].initialPoint(), pathv[i][j].initialPoint())) + { + path_satellites.push_back(_satellites[k][l]); diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index aa482a6cf..b0afa14f4 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -13,6 +13,7 @@ set(live_effects_SRC lpe-constructgrid.cpp lpe-copy_rotate.cpp lpe-curvestitch.cpp + lpe-dash-stroke.cpp lpe-dynastroke.cpp lpe-ellipse_5pts.cpp lpe-embrodery-stitch.cpp @@ -106,6 +107,7 @@ set(live_effects_SRC lpe-constructgrid.h lpe-copy_rotate.h lpe-curvestitch.h + lpe-dash-stroke.h lpe-dynastroke.h lpe-ellipse_5pts.h lpe-embrodery-stitch.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index a895a8a9b..493e3bd8c 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -56,6 +56,7 @@ enum EffectType { POWERMASK, PTS2ELLIPSE, OFFSET, + DASH_STROKE, DOEFFECTSTACK_TEST, ANGLE_BISECTOR, CIRCLE_WITH_RADIUS, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 80fa208fa..941923a77 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -24,6 +24,7 @@ #include "live_effects/lpe-constructgrid.h" #include "live_effects/lpe-copy_rotate.h" #include "live_effects/lpe-curvestitch.h" +#include "live_effects/lpe-dash-stroke.h" #include "live_effects/lpe-dynastroke.h" #include "live_effects/lpe-ellipse_5pts.h" #include "live_effects/lpe-envelope.h" @@ -133,7 +134,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, -/* 9.93 */ +/* 0.93 */ {MEASURE_SEGMENTS, N_("Measure Segments"), "measure_segments"}, {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, {BOOL_OP, N_("Boolean operation"), "bool_op"}, @@ -142,6 +143,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {POWERMASK, N_("Power mask"), "powermask"}, {PTS2ELLIPSE, N_("Ellipse from points"), "pts2ellipse"}, {OFFSET, N_("Offset"), "offset"}, + {DASH_STROKE, N_("Dash Stroke"), "dash_stroke"}, #ifdef LPE_ENABLE_TEST_EFFECTS {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, @@ -346,6 +348,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case PTS2ELLIPSE: neweffect = static_cast<Effect*> ( new LPEPts2Ellipse(lpeobj) ); break; + case DASH_STROKE: + neweffect = static_cast<Effect*> ( new LPEDashStroke(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-dash-stroke.cpp b/src/live_effects/lpe-dash-stroke.cpp new file mode 100644 index 000000000..618ba60a3 --- /dev/null +++ b/src/live_effects/lpe-dash-stroke.cpp @@ -0,0 +1,244 @@ +/* + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include "live_effects/lpe-dash-stroke.h" +#include "2geom/pathvector.h" +#include "2geom/path.h" +#include "helper/geom.h" + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + +namespace Inkscape { +namespace LivePathEffect { + +LPEDashStroke::LPEDashStroke(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + numberdashes(_("Number of dashes"), _("Number of dashes"), "numberdashes", &wr, this, 3), + holefactor(_("Hole factor"), _("Hole factor"), "holefactor", &wr, this, 0.0), + splitsegments(_("Use segments"), _("Use segments"), "splitsegments", &wr, this, true), + halfextreme(_("Half start/end"), _("Start and end of each segment has half size"), "halfextreme", &wr, this, true), + message(_("Info Box"), _("Important messages"), "message", &wr, this, _("Add <b>\"Fill Between Many LPE\"</b> to add fill.")) +{ + registerParameter(&numberdashes); + registerParameter(&holefactor); + registerParameter(&splitsegments); + registerParameter(&halfextreme); + registerParameter(&message); + numberdashes.param_set_range(0, 5000); + numberdashes.param_set_increments(1, 1); + numberdashes.param_set_digits(0); + holefactor.param_set_range(-0.99999, 0.99999); + holefactor.param_set_increments(0.01, 0.01); + holefactor.param_set_digits(5); + message.param_set_min_height(30); +} + +LPEDashStroke::~LPEDashStroke() {} + +void +LPEDashStroke::doBeforeEffect (SPLPEItem const* lpeitem){ +} + +///Calculate the time in curve_in with a real time of A +//TODO: find a better place to it +double +LPEDashStroke::timeAtLength(double const A, Geom::Path const &segment) +{ + if ( A == 0 || segment[0].isDegenerate()) { + return 0; + } + double t = 1; + t = timeAtLength(A, segment.toPwSb()); + return t; +} + +///Calculate the time in curve_in with a real time of A +//TODO: find a better place to it +double +LPEDashStroke::timeAtLength(double const A, Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2) +{ + if ( A == 0 || pwd2.size() == 0) { + return 0; + } + + double t = pwd2.size(); + std::vector<double> t_roots = roots(Geom::arcLengthSb(pwd2) - A); + if (!t_roots.empty()) { + t = t_roots[0]; + } + return t; +} + +Geom::PathVector +LPEDashStroke::doEffect_path(Geom::PathVector const & path_in){ + Geom::PathVector const pv = pathv_to_linear_and_cubic_beziers(path_in); + Geom::PathVector result; + for (Geom::PathVector::const_iterator path_it = pv.begin(); path_it != pv.end(); ++path_it) { + if (path_it->empty()) { + continue; + } + Geom::Path::const_iterator curve_it1 = path_it->begin(); + Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); + Geom::Path::const_iterator curve_endit = path_it->end_default(); + if (path_it->closed()) { + 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(); + } + } + if(splitsegments) { + //double item_length = Geom::length(paths_to_pw(path_it)); + //item_length = Inkscape::Util::Quantity::convert(item_length * scale, unit->abbr, unit_name); + } + size_t numberholes = numberdashes - 1; + size_t ammount = numberdashes + numberholes; + if (halfextreme) { + ammount--; + } + double base = 1/(double)ammount; + double globaldash = base * numberdashes * (1 + holefactor); + if (halfextreme) { + globaldash = base * (numberdashes - 1) * (1 + holefactor); + } + double globalhole = 1-globaldash; + double dashpercent = globaldash/numberdashes; + if (halfextreme) { + dashpercent = globaldash/(numberdashes -1); + } + double holepercent = globalhole/numberholes; + + size_t p_index = 0; + size_t start_index = 0; + if(splitsegments) { + while (curve_it1 != curve_endit) { + Geom::Path segment = (*path_it).portion(p_index, p_index + 1); + double dashsize = (*curve_it1).length() * dashpercent; + double holesize = (*curve_it1).length() * holepercent; + if ((*curve_it1).isLineSegment()) { + if (result.size() && Geom::are_near(segment.initialPoint(),result[result.size()-1].finalPoint())) { + result[result.size()-1].setFinal(segment.initialPoint()); + if (halfextreme) { + result[result.size()-1].append(segment.portion(0.0, dashpercent/2.0)); + } else { + result[result.size()-1].append(segment.portion(0.0, dashpercent)); + } + } else { + if (halfextreme) { + result.push_back(segment.portion(0.0, dashpercent/2.0)); + } else { + result.push_back(segment.portion(0.0, dashpercent)); + } + start_index = result.size()-1; + } + + double start = dashpercent + holepercent; + if (halfextreme) { + start = (dashpercent/2.0) + holepercent; + } + while (start < 1) { + if (start + dashpercent > 1) { + result.push_back(segment.portion(start, 1)); + } else { + result.push_back(segment.portion(start, start + dashpercent)); + } + start += dashpercent + holepercent; + } + } else if (!(*curve_it1).isLineSegment()) { + double start = 0.0; + double end = 0.0; + if (halfextreme) { + end = timeAtLength(dashsize/2.0,segment); + } else { + end = timeAtLength(dashsize,segment); + } + if (result.size() && Geom::are_near(segment.initialPoint(),result[result.size()-1].finalPoint())) { + result[result.size()-1].setFinal(segment.initialPoint()); + result[result.size()-1].append(segment.portion(start, end)); + } else { + result.push_back(segment.portion(start, end)); + start_index = result.size()-1; + } + double startsize = dashsize + holesize; + if (halfextreme) { + startsize = (dashsize/2.0) + holesize; + } + double endsize = startsize + dashsize; + start = timeAtLength(startsize,segment); + end = timeAtLength(endsize,segment); + while (start < 1 && start > 0) { + result.push_back(segment.portion(start, end)); + startsize = endsize + holesize; + endsize = startsize + dashsize; + start = timeAtLength(startsize,segment); + end = timeAtLength(endsize,segment); + } + } + p_index ++; + ++curve_it1; + ++curve_it2; + } + } else { + double start = 0.0; + double end = 0.0; + Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2 = (*path_it).toPwSb(); + double lenght_pwd2 = length (pwd2); + double dashsize = lenght_pwd2 * dashpercent; + double holesize = lenght_pwd2 * holepercent; + if (halfextreme) { + end = timeAtLength(dashsize/2.0,pwd2); + } else { + end = timeAtLength(dashsize,pwd2); + } + std::cout << end << "end" << std::endl; + std::cout << start << "start" << std::endl; + result.push_back((*path_it).portion(start, end)); + start_index = result.size()-1; + double startsize = dashsize + holesize; + if (halfextreme) { + startsize = (dashsize/2.0) + holesize; + } + double endsize = startsize + dashsize; + start = timeAtLength(startsize,pwd2); + end = timeAtLength(endsize,pwd2); + while (start < (*path_it).size() && start > 0) { + std::cout << end << "end" << std::endl; + std::cout << start << "start" << std::endl; + result.push_back((*path_it).portion(start, end)); + startsize = endsize + holesize; + endsize = startsize + dashsize; + start = timeAtLength(startsize,pwd2); + end = timeAtLength(endsize,pwd2); + } + } + if (curve_it2 == curve_endit) { + if (path_it->closed()) { + Geom::Path end = result[result.size()-1]; + end.setFinal(result[start_index].initialPoint()); + end.append(result[start_index]); + result[start_index] = end; + } + } + } + return result; +} + +}; //namespace LivePathEffect +}; /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-dash-stroke.h b/src/live_effects/lpe-dash-stroke.h new file mode 100644 index 000000000..0db9b0a48 --- /dev/null +++ b/src/live_effects/lpe-dash-stroke.h @@ -0,0 +1,34 @@ +#ifndef INKSCAPE_LPE_DASH_STROKE_H +#define INKSCAPE_LPE_DASH_STROKE_H + +/* + * Inkscape::LPEDashStroke + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/message.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPEDashStroke : public Effect { +public: + LPEDashStroke(LivePathEffectObject *lpeobject); + virtual ~LPEDashStroke(); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); + double timeAtLength(double const A, Geom::Path const &segment); + double timeAtLength(double const A, Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2); +private: + ScalarParam numberdashes; + ScalarParam holefactor; + BoolParam splitsegments; + BoolParam halfextreme; + MessageParam message; +}; + +} //namespace LivePathEffect +} //namespace Inkscape +#endif diff --git a/src/live_effects/lpe-fillet-chamfer.cpp.rej b/src/live_effects/lpe-fillet-chamfer.cpp.rej new file mode 100644 index 000000000..8a754993d --- /dev/null +++ b/src/live_effects/lpe-fillet-chamfer.cpp.rej @@ -0,0 +1,41 @@ +--- src/live_effects/lpe-fillet-chamfer.cpp ++++ src/live_effects/lpe-fillet-chamfer.cpp +@@ -338,11 +338,11 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) + doOnApply(lpeItem); + satellites = satellites_param.data(); + } ++ bool write = false; + if (_pathvector_satellites) { + size_t number_nodes = pathv.nodes().size(); + size_t previous_number_nodes = _pathvector_satellites->getTotalSatellites(); + if (number_nodes != previous_number_nodes) { +- Satellites satellites; + double power = radius; + if (!flexible) { + SPDocument * document = SP_ACTIVE_DOCUMENT; +@@ -367,6 +367,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) + satellite.setHidden(hide_knots); + _pathvector_satellites->recalculateForNewPathVector(pathv, satellite); + satellites = _pathvector_satellites->getSatellites(); ++ write = true; + } + } + if (_degenerate_hide) { +@@ -410,7 +411,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) + } + _pathvector_satellites->setPathVector(pathv); + _pathvector_satellites->setSatellites(satellites); +- satellites_param.setPathVectorSatellites(_pathvector_satellites, false); ++ satellites_param.setPathVectorSatellites(_pathvector_satellites, write); + refreshKnots(); + } else { + g_warning("LPE Fillet can only be applied to shapes (not groups)."); +@@ -549,7 +550,7 @@ LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) + if (time1 == time0) { + start_arc_point = curve_it1->pointAt(time0); + } +- if (time1 != 1) { ++ if (time1 != 1 && !Geom::are_near(angle,Geom::rad_from_deg(360))) { + if (time1 != time0 || (time1 == 1 && time0 == 1)) { + if (!knot_curve_1->isDegenerate()) { + tmp_path.append(*knot_curve_1); |
