summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohan B. C. Engelen <jbc.engelen@swissonline.ch>2012-02-26 21:59:20 +0000
committerJohan Engelen <goejendaagh@zonnet.nl>2012-02-26 21:59:20 +0000
commit7fa31d75591543f64cb70b73f19533d5b7f35dba (patch)
tree737f5efabbb21c605bdf818530227cb3d3de9dc4 /src
parentImport deprecated GtkRuler API. Probably worth tidying :-) (diff)
downloadinkscape-7fa31d75591543f64cb70b73f19533d5b7f35dba.tar.gz
inkscape-7fa31d75591543f64cb70b73f19533d5b7f35dba.zip
powerstroke: work on cusps, so people can play with it a bit. it is not done yet ! so may change in future...
(partial update to latest 2geom, for reflection transform) (bzr r11024)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/transforms.cpp11
-rw-r--r--src/2geom/transforms.h11
-rw-r--r--src/live_effects/lpe-powerstroke.cpp66
3 files changed, 72 insertions, 16 deletions
diff --git a/src/2geom/transforms.cpp b/src/2geom/transforms.cpp
index b8355cadc..65df9b22f 100644
--- a/src/2geom/transforms.cpp
+++ b/src/2geom/transforms.cpp
@@ -5,8 +5,9 @@
* Authors:
* ? <?@?.?>
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Johan Engelen
*
- * Copyright ?-2009 Authors
+ * Copyright ?-2012 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -171,8 +172,16 @@ void check_transforms()
m = z * t; m = z * s; m = z * r; m = z * h; m = z * v; m = z * z;
}
+Affine reflection(Point const & vector, Point const & origin) {
+ Geom::Point vec_norm = unit_vector(vector);
+ Affine mirror ( vec_norm[X]*vec_norm[X] - vec_norm[Y]*vec_norm[Y], 2 * vec_norm[X] * vec_norm[Y] ,
+ 2 * vec_norm[X] * vec_norm[Y], vec_norm[Y]*vec_norm[Y] - vec_norm[X]*vec_norm[X] ,
+ 0 ,0 );
+ return Translate(-origin) * mirror * Translate(origin);
}
+} // namespace Geom
+
/*
Local Variables:
mode:c++
diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h
index eaf869056..869e955c7 100644
--- a/src/2geom/transforms.h
+++ b/src/2geom/transforms.h
@@ -5,8 +5,9 @@
* Authors:
* ? <?@?.?>
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Johan Engelen
*
- * Copyright ?-2009 Authors
+ * Copyright ?-2012 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -280,7 +281,7 @@ inline bool are_near(VShear const &a, VShear const &b, Coord eps=EPSILON) {
* The translation part is applied first, then the result is scaled from the new origin.
* This way when the class is used to accumulate a zoom transform, trans always points
* to the new origin in original coordinates.
- * @ingroup Transform */
+ * @ingroup Transforms */
class Zoom
: public TransformOperations< Zoom >
{
@@ -338,6 +339,12 @@ inline Translate pow(Translate const &t, int n) {
return ret;
}
+
+/** @brief Reflects objects about line.
+ * The line, defined by a vector along the line and a point on it, acts as a mirror.
+ */
+Affine reflection(Point const & vector, Point const & origin);
+
//TODO: decomposition of Affine into some finite combination of the above classes
} // end namespace Geom
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index e385febec..bb57dc2f7 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -24,7 +24,8 @@
#include <2geom/svg-elliptical-arc.h>
#include <2geom/sbasis-to-bezier.h>
#include <2geom/svg-path.h>
-
+#include <2geom/path-intersection.h>
+#include <2geom/crossing.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -56,12 +57,12 @@ static const Util::EnumDataConverter<unsigned> LineCapTypeConverter(LineCapTypeD
enum LineCuspType {
LINECUSP_BEVEL,
LINECUSP_ROUND,
- LINECUSP_SHARP
+ LINECUSP_CUSP
};
static const Util::EnumData<unsigned> LineCuspTypeData[] = {
- {LINECUSP_BEVEL , N_("Beveled"), "bevel"},
- {LINECUSP_ROUND , N_("Rounded"), "round"},
-// not yet supported {LINECUSP_SHARP , N_("Sharp"), "sharp"}
+ {LINECUSP_BEVEL , N_("Beveled"), "bevel"},
+ {LINECUSP_ROUND , N_("Rounded"), "round"},
+ {LINECUSP_CUSP , N_("Cusp"), "cusp"},
};
static const Util::EnumDataConverter<unsigned> LineCuspTypeConverter(LineCuspTypeData, sizeof(LineCuspTypeData)/sizeof(*LineCuspTypeData));
@@ -156,6 +157,7 @@ std::vector<discontinuity_data> find_discontinuities( Geom::Piecewise<Geom::D2<G
Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> > const & B,
std::vector<discontinuity_data> const & cusps,
LineCuspType cusp_linecap,
+ bool forward_direction,
double tol=Geom::EPSILON)
{
/* per definition, each discontinuity should be fixed with a cusp-ending, as defined by cusp_linecap_type
@@ -165,14 +167,16 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis>
return pb.peek().front();
}
- unsigned int cusp_i = 0;
+ double sign = forward_direction ? 1. : -1.;
+
+ unsigned int cusp_i = forward_direction ? 0 : cusps.size()-1;
Geom::Point start = B[0].at0();
pb.moveTo(start);
build_from_sbasis(pb, B[0], tol, false);
for (unsigned i=1; i < B.size(); i++) {
if (!are_near(B[i-1].at1(), B[i].at0(), tol) )
{ // discontinuity found, so fix it :-)
- discontinuity_data const &cusp = cusps[cusp_i];
+ discontinuity_data cusp = cusps[cusp_i];
switch (cusp_linecap) {
case LINECUSP_ROUND: // properly bugged ^_^
@@ -180,14 +184,50 @@ Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis>
angle_between(cusp.der0, cusp.der1), false, cusp.width < 0,
B[i].at0() );
break;
- case LINECUSP_SHARP: // no clue yet what to do here :)
+ case LINECUSP_CUSP: {
+ // first figure out whether we are on the outside or inside of the corner in the path
+ if ( sign*cusp.width*angle_between(cusp.der0, cusp.der1) < 0.) {
+ // we are on the outside, do something complicated to make it look good ;)
+
+ Geom::D2<Geom::SBasis> newcurve1 =
+ B[i-1] * Geom::reflection(rot90(derivative(B[i-1]).at1()), B[i-1].at1());
+ newcurve1 = reverse(newcurve1);
+ std::vector<Geom::Point> temp;
+ sbasis_to_bezier(temp, newcurve1, 4);
+ Geom::CubicBezier bzr1( temp );
+
+ Geom::D2<Geom::SBasis> newcurve2 =
+ B[i] * Geom::reflection(rot90(derivative(B[i]).at0()), B[i].at0());
+ newcurve2 = reverse(newcurve2);
+ sbasis_to_bezier(temp, newcurve2, 4);
+ Geom::CubicBezier bzr2( temp );
+
+ Geom::Crossings cross = crossings(bzr1, bzr2);
+ if (cross.empty()) {
+g_message("empty crossing: decide what to do...");
+ pb.curveTo(bzr1[1], bzr1[2], bzr1[3]);
+ pb.lineTo(bzr2[0]);
+ pb.curveTo(bzr2[1], bzr2[2], bzr2[3]);
+ } else {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> sub1 = bzr1.subdivide(cross[0].ta);
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> sub2 = bzr2.subdivide(cross[0].tb);
+ pb.curveTo(sub1.first[1], sub1.first[2], sub1.first[3]);
+ pb.curveTo(sub2.second[1], sub2.second[2], sub2.second[3]);
+ }
+
+ } else {
+ // we are on the inside, do a simple bevel to connect the paths
+ pb.lineTo(B[i].at0()); // default to bevel for too shallow cusp angles
+ }
+ break;
+ }
case LINECUSP_BEVEL:
default:
pb.lineTo(B[i].at0());
break;
}
- cusp_i++;
+ cusp_i += forward_direction ? 1 : -1;
}
build_from_sbasis(pb, B[i], tol, false);
}
@@ -209,8 +249,8 @@ 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();
- Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in));
- Piecewise<D2<SBasis> > n = rot90(der);
+ Piecewise<D2<SBasis> > der = derivative(pwd2_in);
+ Piecewise<D2<SBasis> > n = rot90(unitVector(der));
offset_points.set_pwd2(pwd2_in, n);
LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value());
@@ -263,8 +303,8 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in)
Piecewise<D2<SBasis> > pwd2_out = compose(pwd2_in,x) + y*compose(n,x);
Piecewise<D2<SBasis> > mirrorpath = reverse(compose(pwd2_in,x) - y*compose(n,x));
- Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, cusps, cusp_linecap, LPE_CONVERSION_TOLERANCE);
- Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, cusps, cusp_linecap, LPE_CONVERSION_TOLERANCE);
+ Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, cusps, cusp_linecap, true, LPE_CONVERSION_TOLERANCE);
+ Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, cusps, cusp_linecap, false, LPE_CONVERSION_TOLERANCE);
if (path_in[0].closed()) {
fixed_path.close(true);