summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2016-06-16 20:29:40 +0000
committerjabiertxof <info@marker.es>2016-06-16 20:29:40 +0000
commit5d388f13644b59e355e0980c74695247b2191562 (patch)
treea1c3b13bb56679d508bfd5f65087591e435ff0bb /src
parentfix a bat file (diff)
downloadinkscape-5d388f13644b59e355e0980c74695247b2191562.tar.gz
inkscape-5d388f13644b59e355e0980c74695247b2191562.zip
Fixes some bugs related to powerstroke 'Powerstroke infinite loop'
Fixed bugs: - https://launchpad.net/bugs/1535444 - https://launchpad.net/bugs/1236320 - https://launchpad.net/bugs/1586973 (bzr r14991)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/sbasis-geometric.cpp9
-rw-r--r--src/live_effects/lpe-powerstroke.cpp25
-rw-r--r--src/ui/tools/freehand-base.cpp40
3 files changed, 23 insertions, 51 deletions
diff --git a/src/2geom/sbasis-geometric.cpp b/src/2geom/sbasis-geometric.cpp
index 8aaa15144..19eccc451 100644
--- a/src/2geom/sbasis-geometric.cpp
+++ b/src/2geom/sbasis-geometric.cpp
@@ -101,7 +101,7 @@ static SBasis divide_by_t1k(SBasis const &a, int k) {
static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1.e-4){
D2<SBasis> M = MM;
//TODO: divide by all the s at once!!!
- while ((M[0].size()>0||M[1].size()>0) &&
+ while ((M[0].size()>1||M[1].size()>1) &&
fabs(M[0].at0())<ZERO &&
fabs(M[1].at0())<ZERO &&
fabs(M[0].at1())<ZERO &&
@@ -109,12 +109,12 @@ static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1
M[0] = divide_by_sk(M[0],1);
M[1] = divide_by_sk(M[1],1);
}
- while ((M[0].size()>0||M[1].size()>0) &&
+ while ((M[0].size()>1||M[1].size()>1) &&
fabs(M[0].at0())<ZERO && fabs(M[1].at0())<ZERO){
M[0] = divide_by_t0k(M[0],1);
M[1] = divide_by_t0k(M[1],1);
}
- while ((M[0].size()>0||M[1].size()>0) &&
+ while ((M[0].size()>1||M[1].size()>1) &&
fabs(M[0].at1())<ZERO && fabs(M[1].at1())<ZERO){
M[0] = divide_by_t1k(M[0],1);
M[1] = divide_by_t1k(M[1],1);
@@ -227,9 +227,9 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){
// -This approach is numerically bad. Find a stable way to rescale V_in to have non vanishing ends.
// -This done, unitVector will have jumps at zeros: fill the gaps with arcs of circles.
D2<SBasis> V = RescaleForNonVanishingEnds(V_in);
-
if (V[0].isZero(0) && V[1].isZero(0))
return Piecewise<D2<SBasis> >(D2<SBasis>(Linear(1),SBasis()));
+
SBasis x = V[0], y = V[1];
SBasis r_eqn1, r_eqn2;
@@ -242,7 +242,6 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){
r_eqn1 = -(a*x+b*y);
r_eqn2 = Linear(1.)-(a*a+b*b);
-
for (unsigned k=1; k<=order; k++){
double r0 = (k<r_eqn1.size())? r_eqn1.at(k).at0() : 0;
double r1 = (k<r_eqn1.size())? r_eqn1.at(k).at1() : 0;
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index 03102a84a..66c8776b5 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -35,6 +35,7 @@
#include <2geom/ellipse.h>
#include <2geom/circle.h>
#include <2geom/math-utils.h>
+#include "helper/geom.h"
#include <math.h>
#include "spiro.h"
@@ -205,14 +206,13 @@ LPEPowerStroke::~LPEPowerStroke()
}
-
void
LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem)
{
- if (SP_IS_SHAPE(lpeitem)) {
+ if (SP_IS_SHAPE(lpeitem) && offset_points.data().empty()) {
SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem);
std::vector<Geom::Point> points;
- Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector();
+ Geom::PathVector const &pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeitem)->_curve->get_pathvector());
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
@@ -565,12 +565,11 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
if (path_in.empty()) {
return path_out;
}
-
- // for now, only regard first subpath and ignore the rest
- Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb();
-
+ Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = pathv[0].toPwSb();
Piecewise<D2<SBasis> > der = derivative(pwd2_in);
- Piecewise<D2<SBasis> > n = rot90(unitVector(der));
+ Piecewise<D2<SBasis> > n = unitVector(der,0.0001);
+ n = rot90(n);
offset_points.set_pwd2(pwd2_in, n);
LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value());
@@ -583,7 +582,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
if (sort_points) {
sort(ts.begin(), ts.end(), compare_offsets);
}
- if (path_in[0].closed()) {
+ if (pathv[0].closed()) {
// add extra points for interpolation between first and last point
Point first_point = ts.front();
Point last_point = ts.back();
@@ -605,7 +604,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
for (std::size_t i = 0, e = ts.size(); i < e; ++i) {
ts[i][Geom::X] *= xcoord_scaling;
}
-
// create stroke path where points (x,y) := (t, offset)
Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value()));
if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast<Geom::Interpolate::CubicBezierJohan*>(interpolator)) {
@@ -631,7 +629,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
x = portion(x, rtsmin.at(0), rtsmax.at(0));
y = portion(y, rtsmin.at(0), rtsmax.at(0));
}
-
LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value());
Piecewise<D2<SBasis> > pwd2_out = compose(pwd2_in,x) + y*compose(n,x);
@@ -639,8 +636,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE);
Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE);
-
- if (path_in[0].closed()) {
+ if (pathv[0].closed()) {
fixed_path.close(true);
path_out.push_back(fixed_path);
fixed_mirrorpath.close(true);
@@ -684,7 +680,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
}
fixed_path.append(fixed_mirrorpath);
-
switch (start_linecap) {
case LINECAP_ZERO_WIDTH:
// do nothing
@@ -720,11 +715,9 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in)
break;
}
}
-
fixed_path.close(true);
path_out.push_back(fixed_path);
}
-
return path_out;
}
diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp
index c98ecb686..7697cd59c 100644
--- a/src/ui/tools/freehand-base.cpp
+++ b/src/ui/tools/freehand-base.cpp
@@ -236,38 +236,14 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points
Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points);
- // find out stroke width (TODO: is there an easier way??)
- SPDesktop *desktop = dc->desktop;
- Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
- Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
- Inkscape::GC::release(repr);
-
- char const* tool = SP_IS_PEN_CONTEXT(dc) ? "/tools/freehand/pen" : "/tools/freehand/pencil";
-
- // apply the tool's current style
- sp_desktop_apply_style_tool(desktop, repr, tool, false);
-
- double stroke_width = 1.0;
- char const *style_str = NULL;
- style_str = repr->attribute("style");
- if (style_str) {
- SPStyle style(SP_ACTIVE_DOCUMENT);
- style.mergeString(style_str);
- stroke_width = style.stroke_width.computed;
- }
-
- std::ostringstream s;
- s.imbue(std::locale::classic());
- s << points[0][Geom::X] << "," << stroke_width / 2.;
-
// write powerstroke parameters:
lpe->getRepr()->setAttribute("start_linecap_type", "zerowidth");
lpe->getRepr()->setAttribute("end_linecap_type", "zerowidth");
- lpe->getRepr()->setAttribute("cusp_linecap_type", "round");
lpe->getRepr()->setAttribute("sort_points", "true");
lpe->getRepr()->setAttribute("interpolator_type", "CubicBezierJohan");
lpe->getRepr()->setAttribute("interpolator_beta", "0.2");
- lpe->getRepr()->setAttribute("offset_points", s.str().c_str());
+ lpe->getRepr()->setAttribute("miter_limit", "4");
+ lpe->getRepr()->setAttribute("linejoin_type", "extrp_arc");
}
static void spdc_apply_bend_shape(gchar const *svgd, FreehandBase *dc, SPItem *item)
@@ -341,12 +317,14 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
bool shape_applied = false;
SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
const char *cstroke = sp_repr_css_property(css_item, "stroke", "none");
+ const char *stroke_width = sp_repr_css_property(css_item, "stroke-width", "0");
+ double swidth;
+ sp_svg_number_read_d(stroke_width, &swidth);
static SPItem *bend_item;
#define SHAPE_LENGTH 10
#define SHAPE_HEIGHT 10
-
if(shape == LAST_APPLIED){
shape = previous_shape_type;
@@ -363,7 +341,8 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
{
// "triangle in"
std::vector<Geom::Point> points(1);
- points[0] = Geom::Point(0., SHAPE_HEIGHT/2);
+ points[0] = Geom::Point(0., swidth/2);
+ points[0] *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL).inverse();
spdc_apply_powerstroke_shape(points, dc, item);
shape_applied = true;
@@ -374,7 +353,9 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
// "triangle out"
guint curve_length = curve->get_segment_count();
std::vector<Geom::Point> points(1);
- points[0] = Geom::Point((double)curve_length, SHAPE_HEIGHT/2);
+ points[0] = Geom::Point(0, swidth/2);
+ points[0] *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL).inverse();
+ points[0][Geom::X] = (double)curve_length;
spdc_apply_powerstroke_shape(points, dc, item);
shape_applied = true;
@@ -455,7 +436,6 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
if(previous_shape_type == CLIPBOARD){
if(previous_shape_pathv.size() != 0){
spdc_paste_curve_as_freehand_shape(previous_shape_pathv, dc, item);
-
shape_applied = true;
shape = CLIPBOARD;
} else{