summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2008-10-11 15:16:23 +0000
committerTed Gould <ted@canonical.com>2008-10-11 15:16:23 +0000
commit2f5eb047d9e05be5e68549ef6b75070d2faa7d2f (patch)
treeca2e94164b6d7aaebfc17196ca46bfc825a7665a /src/live_effects
parentMerge from trunk. (diff)
downloadinkscape-2f5eb047d9e05be5e68549ef6b75070d2faa7d2f.tar.gz
inkscape-2f5eb047d9e05be5e68549ef6b75070d2faa7d2f.zip
Merging from trunk
(bzr r6884)
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/lpe-knot.cpp64
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp2
-rw-r--r--src/live_effects/lpe-ruler.cpp66
-rw-r--r--src/live_effects/lpe-sketch.cpp4
-rw-r--r--src/live_effects/lpe-spiro.cpp65
-rw-r--r--src/live_effects/lpe-vonkoch.cpp233
-rw-r--r--src/live_effects/lpe-vonkoch.h48
-rw-r--r--src/live_effects/lpegroupbbox.cpp2
-rw-r--r--src/live_effects/lpeobject.cpp43
-rw-r--r--src/live_effects/lpeobject.h37
-rw-r--r--src/live_effects/parameter/pointparam-knotholder.cpp3
11 files changed, 399 insertions, 168 deletions
diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp
index 418f43b3c..4504f4467 100644
--- a/src/live_effects/lpe-knot.cpp
+++ b/src/live_effects/lpe-knot.cpp
@@ -86,7 +86,8 @@ findShadowedTime(Geom::Path const &patha,
cutterPath.appendNew<LineSegment> (B-width*N);
cutterPath.appendNew<LineSegment> (B+width*N);
cutterPath.appendNew<LineSegment> (A+width*N);
- cutterPath.appendNew<LineSegment> (A-width*N);
+ cutterPath.close();
+ //cutterPath.appendNew<LineSegment> (A-width*N);
cutter.push_back(cutterPath);
std::vector<Geom::Path> patha_as_vect = std::vector<Geom::Path>(1,patha);
@@ -135,16 +136,47 @@ split_at_horiz_vert_tgt (std::vector<Geom::Path> const & path_in){
//LPEKnot specific Crossing Data manipulation.
//---------------------------------------------------------------------------
-//TODO: evaluate how lpeknot specific that is. Worth being moved to 2geom?
+//TODO: Fix this in 2Geom: I think CrossingSets should not contain duplicates.
+Geom::CrossingSet crossingSet_remove_double(Geom::CrossingSet const &input){
+ Geom::CrossingSet result(input.size());
+ //Yeah, I know, there is a "unique" algorithm for that...
+ Geom::Crossing last;
+ for( unsigned i=0; i<input.size(); i++){
+ for( unsigned j=0; j<input[i].size(); j++){
+ if( j==0 || !(input[i][j]==last) ){
+ result[i].push_back(input[i][j]);
+ last = input[i][j];
+ }else{
+ g_warning("Duplicate found in a Geom::CrossingSet!");
+ }
+ }
+ }
+ return result;
+}
+
+//TODO: evaluate how usefull/lpeknot specific that is. Worth being moved to 2geom? (I doubt it)
namespace LPEKnotNS {
+//Yet another crossing data representation. Not sure at all it is usefull!
+// +: >Given a point, you immediately know which strings are meeting there,
+// and the index of the crossing along each string. This makes it easy to check
+// topology change. In a CrossingSet, you have to do some search to know the index
+// of the crossing along "the second" string (i.e. find the symetric crossing)...
+// >Each point is stored only once.
+// However, we don't have so many crossing points in general, so none of these points might be relevant.
+//
+// -: one more clumsy data representation, and "parallelism" failures to expect...
+// (in particular, duplicates are hateful with this respect...)
+
CrossingPoints::CrossingPoints(Geom::CrossingSet const &input, std::vector<Geom::Path> const &path) : std::vector<CrossingPoint>()
{
using namespace Geom;
+ g_print("JF>\nCrossing set content:\n");
for( unsigned i=0; i<input.size(); i++){
Crossings i_crossings = input[i];
for( unsigned n=0; n<i_crossings.size(); n++ ){
Crossing c = i_crossings[n];
+ g_print("JF> (%u,%u) at times (%f,%f) ----->",c.a,c.b,c.ta,c.tb);
unsigned j = c.getOther(i);
if (i<j || (i==j && c.ta<c.tb) ){
CrossingPoint cp;
@@ -163,6 +195,19 @@ CrossingPoints::CrossingPoints(Geom::CrossingSet const &input, std::vector<Geom:
cp.nj = std::find(input[j].begin(),input[j].end(),c_bar)-input[j].begin();
cp.sign = 1;
push_back(cp);
+ g_print("i=%u, ni=%u, j=%u, nj=%u\n",cp.i,cp.ni,cp.j,cp.nj);
+ }
+ else{
+ g_print("\n");
+ bool found = false;
+ for( unsigned ii=0; ii<input.size(); ii++){
+ Crossings ii_crossings = input[ii];
+ for( unsigned nn=0; nn<ii_crossings.size(); nn++ ){
+ Crossing cc = ii_crossings[nn];
+ if (cc.b==c.a && cc.a==c.b && cc.ta==c.tb && cc.tb==c.ta) found = true;
+ }
+ }
+ assert( found );
}
}
}
@@ -214,6 +259,7 @@ CrossingPoints::get(unsigned const i, unsigned const ni)
((*this)[k].j==i && (*this)[k].nj==ni)
) return (*this)[k];
}
+ g_warning("LPEKnotNS::CrossingPoints::get error. %uth crossing along string %u not found.",ni,i);
assert(false);//debug purpose...
return CrossingPoint();
}
@@ -335,6 +381,20 @@ LPEKnot::doEffect_path (std::vector<Geom::Path> const &input_path)
std::vector<Geom::Path> path_in = split_at_horiz_vert_tgt(input_path);
CrossingSet crossingTable = crossings_among(path_in);
+
+ for(unsigned i=0;i<crossingTable.size();i++){
+ for(unsigned j=0;j<crossingTable[i].size();j++){
+ g_print("JF>avant: %u,%u,%f,%f\n",crossingTable[i][j].a, crossingTable[i][j].b, crossingTable[i][j].ta, crossingTable[i][j].tb);
+ }
+ }
+ crossingTable = crossingSet_remove_double(crossingTable);
+
+ for(unsigned i=0;i<crossingTable.size();i++){
+ for(unsigned j=0;j<crossingTable[i].size();j++){
+ g_print("JF>apres: %u,%u,%f,%f\n",crossingTable[i][j].a, crossingTable[i][j].b, crossingTable[i][j].ta, crossingTable[i][j].tb);
+ }
+ }
+
crossing_points = LPEKnotNS::CrossingPoints(crossingTable, path_in);
crossing_points.inherit_signs(old_crdata);
crossing_points_vector.param_set_and_write_new_value(crossing_points.to_vector());
diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp
index bb2b908de..cd724b70e 100644
--- a/src/live_effects/lpe-mirror_symmetry.cpp
+++ b/src/live_effects/lpe-mirror_symmetry.cpp
@@ -47,7 +47,7 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem *lpeitem)
SPItem *item = SP_ITEM(lpeitem);
Geom::Matrix t = sp_item_i2d_affine(item);
- Geom::Rect bbox = to_2geom(*item->getBounds(t)); // fixme: what happens if getBounds does not return a valid rect?
+ Geom::Rect bbox = *item->getBounds(t); // fixme: what happens if getBounds does not return a valid rect?
Point A(bbox.left(), bbox.bottom());
Point B(bbox.left(), bbox.top());
diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp
index 52ccc29e1..1df0e127a 100644
--- a/src/live_effects/lpe-ruler.cpp
+++ b/src/live_effects/lpe-ruler.cpp
@@ -19,6 +19,7 @@
#include "inkscape.h"
#include "desktop.h"
+
namespace Inkscape {
namespace LivePathEffect {
@@ -110,34 +111,51 @@ LPERuler::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_i
{
using namespace Geom;
- Piecewise<D2<SBasis> > pwd2_arclength = arc_length_parametrization(pwd2_in);
- Point A(pwd2_arclength.firstValue());
- Point B(pwd2_arclength.lastValue());
- double path_length = Geom::length(pwd2_arclength);
-
- Piecewise<D2<SBasis> > n = -rot90(unitVector(derivative(pwd2_arclength)));
- Piecewise<D2<SBasis> >output(pwd2_arclength);
-
- if (mark_dir == MARKDIR_RIGHT) {
- n *= -1.0;
- }
-
- int j = 0;
const int mminterval = static_cast<int>(major_mark_steps);
- const int j_shift = static_cast<int>(shift) % mminterval;
-
- /* draw the ruler */
- if ((border_marks == BORDERMARK_START || border_marks == BORDERMARK_BOTH) && (offset != 0.0 || j_shift != 0))
- output.concat (ruler_mark(A, n.firstValue(), MARK_MAJOR));
- for (double t = offset; t < path_length; t += mark_distance, ++j) {
- if ((j % mminterval) == j_shift) {
- output.concat (ruler_mark(pwd2_arclength(t), n(t), MARK_MAJOR));
+ const int i_shift = static_cast<int>(shift) % mminterval;
+ int sign = (mark_dir == MARKDIR_RIGHT ? 1 : -1 );
+
+ Piecewise<D2<SBasis> >output(pwd2_in);
+ Piecewise<D2<SBasis> >speed = derivative(pwd2_in);
+ Piecewise<SBasis> arclength = arcLengthSb(pwd2_in);
+ double totlength = arclength.lastValue();
+
+ //find at which times to draw a mark:
+ std::vector<double> s_cuts;
+ for (double s = offset; s<totlength; s+=mark_distance){
+ s_cuts.push_back(s);
+ }
+ std::vector<std::vector<double> > roots = multi_roots(arclength, s_cuts);
+ std::vector<double> t_cuts;
+ g_warning("times:");
+ for (unsigned v=0; v<roots.size();v++){
+ //FIXME: 2geom multi_roots solver seem to sometimes "repeat" solutions.
+ //Here, we are supposed to have one and only one solution for each s.
+ if(roots[v].size()>0)
+ t_cuts.push_back(roots[v][0]);
+ }
+ //draw the marks
+ for (unsigned i=0; i<t_cuts.size(); i++){
+ Point A = pwd2_in(t_cuts[i]);
+ Point n = rot90(unit_vector(speed(t_cuts[i])))*sign;
+ if ((i % mminterval) == i_shift) {
+ output.concat (ruler_mark(A, n, MARK_MAJOR));
} else {
- output.concat (ruler_mark(pwd2_arclength(t), n(t), MARK_MINOR));
+ output.concat (ruler_mark(A, n, MARK_MINOR));
}
}
- if (border_marks == BORDERMARK_END || border_marks == BORDERMARK_BOTH)
- output.concat (ruler_mark(B, n.lastValue(), MARK_MAJOR));
+ //eventually draw a mark at start
+ if ((border_marks == BORDERMARK_START || border_marks == BORDERMARK_BOTH) && (offset != 0.0 || i_shift != 0)){
+ Point A = pwd2_in.firstValue();
+ Point n = rot90(unit_vector(speed.firstValue()))*sign;
+ output.concat (ruler_mark(A, n, MARK_MAJOR));
+ }
+ //eventually draw a mark at end
+ if (border_marks == BORDERMARK_END || border_marks == BORDERMARK_BOTH){
+ Point A = pwd2_in.lastValue();
+ Point n = rot90(unit_vector(speed.lastValue()))*sign;
+ output.concat (ruler_mark(A, n, MARK_MAJOR));
+ }
return output;
}
diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp
index 6aebcd7fa..a95d89398 100644
--- a/src/live_effects/lpe-sketch.cpp
+++ b/src/live_effects/lpe-sketch.cpp
@@ -185,8 +185,12 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_
parallel_offset.resetRandomizer();
strokelength_rdm.resetRandomizer();
strokeoverlap_rdm.resetRandomizer();
+ ends_tolerance.resetRandomizer();
+ tremble_size.resetRandomizer();
tgtlength_rdm.resetRandomizer();
+
+
// some variables for futur use (for construction lines; compute arclength only once...)
// notations will be : t = path time, s = distance from start along the path.
Piecewise<SBasis> pathlength;
diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp
index dd6c5a90a..aab62a75c 100644
--- a/src/live_effects/lpe-spiro.cpp
+++ b/src/live_effects/lpe-spiro.cpp
@@ -13,6 +13,7 @@
#include <2geom/matrix.h>
#include <2geom/bezier-curve.h>
#include <2geom/hvlinesegment.h>
+#include <2geom/isnan.h>
#include "helper/geom-nodetype.h"
#include "helper/geom-curves.h"
@@ -25,6 +26,8 @@
#include "inkscape.h"
#include "desktop.h"
+#define SPIRO_SHOW_INFINITE_COORDINATE_CALLS
+
typedef struct {
bezctx base;
SPCurve *curve;
@@ -34,39 +37,55 @@ typedef struct {
void bezctx_ink_moveto(bezctx *bc, double x, double y, int /*is_open*/)
{
bezctx_ink *bi = (bezctx_ink *) bc;
- bi->curve->moveto(x, y);
+ if ( IS_FINITE(x) && IS_FINITE(y) ) {
+ bi->curve->moveto(x, y);
+ }
+#ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS
+ else {
+ g_message("lpe moveto not finite");
+ }
+#endif
}
void bezctx_ink_lineto(bezctx *bc, double x, double y)
{
bezctx_ink *bi = (bezctx_ink *) bc;
- bi->curve->lineto(x, y);
+ if ( IS_FINITE(x) && IS_FINITE(y) ) {
+ bi->curve->lineto(x, y);
+ }
+#ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS
+ else {
+ g_message("lpe lineto not finite");
+ }
+#endif
}
void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3)
{
bezctx_ink *bi = (bezctx_ink *) bc;
- double x0, y0;
- double x1, y1;
- double x2, y2;
-
- Geom::Point last = *(bi->curve->last_point());
- x0 = last[Geom::X];
- y0 = last[Geom::Y];
- x1 = xm + (1./3) * (x0 - xm);
- y1 = ym + (1./3) * (y0 - ym);
- x2 = xm + (1./3) * (x3 - xm);
- y2 = ym + (1./3) * (y3 - ym);
-
- bi->curve->curveto(x1, y1, x2, y2, x3, y3);
+ if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) {
+ bi->curve->quadto(xm, ym, x3, y3);
+ }
+#ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS
+ else {
+ g_message("lpe quadto not finite");
+ }
+#endif
}
void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2,
double x3, double y3)
{
bezctx_ink *bi = (bezctx_ink *) bc;
- bi->curve->curveto(x1, y1, x2, y2, x3, y3);
+ if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) {
+ bi->curve->curveto(x1, y1, x2, y2, x3, y3);
+ }
+#ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS
+ else {
+ g_message("lpe curveto not finite");
+ }
+#endif
}
bezctx *
@@ -213,20 +232,6 @@ LPESpiro::doEffect(SPCurve * curve)
}
g_free (path);
-
- // FIXME: refactor the spiro code such that it cannot generate non-continous paths!
- // sometimes, the code above generates a path that is not continuous: caused by chaotic algorithm?
- // The continuity error always happens after a lot of curveto calls (a big path probably that spins to infinity?)
- // if so, undo the effect by resetting the original path.
- try {
- curve->get_pathvector() * Geom::identity(); // tests for continuity, this makes LPE Spiro slower of course :-(
- }
- catch (Geom::ContinuityError & e) {
- g_warning("Exception during LPE Spiro execution. \n %s", e.what());
- SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
- _("An exception occurred during execution of the Spiro Path Effect.") );
- curve->set_pathvector(original_pathv);
- }
}
}; //namespace LivePathEffect
diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp
index ef9d38ee4..72d96f5a2 100644
--- a/src/live_effects/lpe-vonkoch.cpp
+++ b/src/live_effects/lpe-vonkoch.cpp
@@ -7,58 +7,64 @@
*/
#include <cstdio>
-
#include "live_effects/lpe-vonkoch.h"
-#include "svg/svg.h"
-#include "ui/widget/scalar.h"
#include "nodepath.h"
+#include <2geom/transforms.h>
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-geometric.h>
-#include <2geom/bezier-to-sbasis.h>
-#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2.h>
-#include <2geom/piecewise.h>
-
-#include <algorithm>
-using std::vector;
-
-
+//using std::vector;
namespace Inkscape {
namespace LivePathEffect {
-VonKochPathParam::~VonKochPathParam()
-{
-}
-
void
VonKochPathParam::param_setup_nodepath(Inkscape::NodePath::Path *np)
-{
+{
PathParam::param_setup_nodepath(np);
sp_nodepath_make_straight_path(np);
}
-static const Util::EnumData<VonKochRefType> VonKochRefTypeData[VKREF_END] = {
- {VKREF_BBOX, N_("Bounding box"), "bbox"},
- {VKREF_SEG, N_("Last gen. segment"), "lastseg"},
-};
-static const Util::EnumDataConverter<VonKochRefType> VonKochRefTypeConverter(VonKochRefTypeData, VKREF_END);
+//FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug.
+void
+VonKochRefPathParam::param_setup_nodepath(Inkscape::NodePath::Path *np)
+{
+ PathParam::param_setup_nodepath(np);
+ sp_nodepath_make_straight_path(np);
+}
+bool
+VonKochRefPathParam::param_readSVGValue(const gchar * strvalue)
+{
+ std::vector<Geom::Path> old = _pathvector;
+ bool res = PathParam::param_readSVGValue(strvalue);
+ if (res && _pathvector.size()==1 && _pathvector.front().size()==1){
+ return true;
+ }else{
+ _pathvector = old;
+ return false;
+ }
+}
LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
+ ref_path(_("Reference segment"), _("The reference segment. Defaults to bbox diameter."), "ref_path", &wr, this, "M0,0 L10,0"),
+ //refA(_("Ref Start"), _("Left side middle of the reference box"), "refA", &wr, this),
+ //refB(_("Ref End"), _("Right side middle of the reference box"), "refB", &wr, this),
+ generator(_("Generating path"), _("Path whose segments define the iterated transforms"), "generator", &wr, this, "M0,0 L30,0 M0,10 L10,10 M 20,10 L30,10"),
+ similar_only(_("Use uniform transforms only"), _("2 consecutive segments are used to reverse/preserve orientation only (otherwise, they define a general transform)."), "similar_only", &wr, this, false),
nbgenerations(_("Nb of generations"), _("Depth of the recursion --- keep low!!"), "nbgenerations", &wr, this, 1),
- generator(_("Generating path"), _("Path whos segments define the fractal"), "generator", &wr, this, "M0,0 L3,0 M0,1 L1,1 M 2,1 L3,1"),
- similar_only(_("Use uniform scale/rotation only"), _("If off, 2segments component of generating path can be used to define a general rtansform. If on, they only affect the orientation preserving/reversing of the transform."), "similar_only", &wr, this, false),
drawall(_("Draw all generations"), _("If unchecked, draw only the last generation"), "drawall", &wr, this, true),
- reftype(_("Reference"), _("Generating path segments define transforms in reference to bbox or last segment"), "reftype", VonKochRefTypeConverter, &wr, this, VKREF_BBOX),
+ //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug.
maxComplexity(_("Max complexity"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000)
+ //,draw_boxes(_("Display boxes"), _("Display boxes instead of paths only"), "draw_boxes", &wr, this, true)
{
+ //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug.
+ registerParameter( dynamic_cast<Parameter *>(&ref_path) );
+ //registerParameter( dynamic_cast<Parameter *>(&refA) );
+ //registerParameter( dynamic_cast<Parameter *>(&refB) );
registerParameter( dynamic_cast<Parameter *>(&generator) );
+ registerParameter( dynamic_cast<Parameter *>(&similar_only) );
registerParameter( dynamic_cast<Parameter *>(&nbgenerations) );
registerParameter( dynamic_cast<Parameter *>(&drawall) );
- registerParameter( dynamic_cast<Parameter *>(&reftype) );
- registerParameter( dynamic_cast<Parameter *>(&similar_only) );
registerParameter( dynamic_cast<Parameter *>(&maxComplexity) );
+ //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) );
nbgenerations.param_make_integer();
nbgenerations.param_set_range(0, NR_HUGE);
@@ -75,28 +81,27 @@ std::vector<Geom::Path>
LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
{
using namespace Geom;
- std::vector<Geom::Path> generating_path = path_from_piecewise(generator.get_pwd2(),.01);//TODO what should that tolerance be?
+
+ std::vector<Geom::Path> generating_path = generator.get_pathvector();
+
+ if (generating_path.size()==0) {
+ return path_in;
+ }
//Collect transform matrices.
- //FIXME: fusing/cutting nodes mix up component order in the path. This is why the last segment is used.
Matrix m0;
- VonKochRefType type = reftype.get_value();
- if (type==VKREF_BBOX){
- Rect bbox = Rect(boundingbox_X,boundingbox_Y);
- m0 = Matrix(boundingbox_X.extent(),0,0,boundingbox_X.extent(), boundingbox_X.min(), boundingbox_Y.middle());
-
- }else{
- if (generating_path.size()==0) return path_in;
- Point p = generating_path.back().back().pointAt(0);
- Point u = generating_path.back().back().pointAt(1)-p;
- m0 = Matrix(u[X], u[Y],-u[Y], u[X], p[X], p[Y]);
- }
+ Geom::Path refpath = ref_path.get_pathvector().front();
+ Point A = refpath.pointAt(0);
+ Point B = refpath.pointAt(refpath.size());
+ Point u = B-A;
+ m0 = Matrix(u[X], u[Y],-u[Y], u[X], A[X], A[Y]);
+
+ //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug.
+ //Point u = refB-refA;
+ //m0 = Matrix(u[X], u[Y],-u[Y], u[X], refA[X], refA[Y]);
m0 = m0.inverse();
-
std::vector<Matrix> transforms;
- unsigned end = generating_path.size();
- if (type==VKREF_SEG) end-=1;
for (unsigned i=0; i<generating_path.size(); i++){
Matrix m;
if(generating_path[i].size()==1){
@@ -109,7 +114,7 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
Point p = generating_path[i].pointAt(1);
Point u = generating_path[i].pointAt(2)-p;
Point v = p-generating_path[i].pointAt(0);
- if (similar_only){
+ if (similar_only.get_value()){
int sign = (u[X]*v[Y]-u[Y]*v[X]>=0?1:-1);
v[X] = -u[Y]*sign;
v[Y] = u[X]*sign;
@@ -120,13 +125,15 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
}
}
- if (transforms.size()==0) return path_in;
+ if (transforms.size()==0){
+ return path_in;
+ }
- //Do nothing if the output is too complex...
+ //Do nothing if the output is too complex...
int path_in_complexity = 0;
for (unsigned k = 0; k < path_in.size(); k++){
path_in_complexity+=path_in[k].size();
- }
+ }
double complexity = pow(transforms.size(),nbgenerations)*path_in_complexity;
if (drawall.get_value()){
int k = transforms.size();
@@ -139,13 +146,14 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
complexity = pow(transforms.size(),nbgenerations)*path_in_complexity;
}
if (complexity > double(maxComplexity)){
+ g_warning("VonKoch lpe's output too complex. Effect bypassed.");
return path_in;
}
//Generate path:
std::vector<Geom::Path> pathi = path_in;
std::vector<Geom::Path> path_out = path_in;
-
+
for (unsigned i = 0; i<nbgenerations; i++){
if (drawall.get_value()){
path_out = path_in;
@@ -156,7 +164,7 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
}
for (unsigned j = 0; j<transforms.size(); j++){
for (unsigned k = 0; k<pathi.size() && complexity < maxComplexity; k++){
- path_out.push_back(pathi[k]*transforms[j]);
+ path_out.push_back(pathi[k]*transforms[j]);
complexity+=pathi[k].size();
}
}
@@ -165,10 +173,98 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
return path_out;
}
+
+//Usefull??
+//void
+//LPEVonKoch::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+/*{
+ using namespace Geom;
+ if (draw_boxes.get_value()){
+ double ratio = .5;
+ if (similar_only.get_value()) ratio = boundingbox_Y.extent()/boundingbox_X.extent()/2;
+
+ Point BB1,BB2,BB3,BB4,v;
+
+ //Draw the reference box (ref_path is supposed to consist in one line segment)
+ //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug.
+ Geom::Path refpath = ref_path.get_pathvector().front();
+ if (refpath.size()==1){
+ BB1 = BB4 = refpath.front().pointAt(0);
+ BB2 = BB3 = refpath.front().pointAt(1);
+ v = rot90(BB2 - BB1)*ratio;
+ BB1 -= v;
+ BB2 -= v;
+ BB3 += v;
+ BB4 += v;
+ Geom::Path refbox(BB1);
+ refbox.appendNew<LineSegment>(BB2);
+ refbox.appendNew<LineSegment>(BB3);
+ refbox.appendNew<LineSegment>(BB4);
+ refbox.close();
+ PathVector refbox_as_vect;
+ refbox_as_vect.push_back(refbox);
+ hp_vec.push_back(refbox_as_vect);
+ }
+ //Draw the transformed boxes
+ std::vector<Geom::Path> generating_path = generator.get_pathvector();
+ for (unsigned i=0;i<generating_path.size(); i++){
+ if (generating_path[i].size()==0){
+ //Ooops! this should not happen.
+ }else if (generating_path[i].size()==1){
+ BB1 = BB4 = generating_path[i].pointAt(0);
+ BB2 = BB3 = generating_path[i].pointAt(1);
+ v = rot90(BB2 - BB1)*ratio;
+ }else{//Only tak the first 2 segments into account.
+ BB1 = BB4 = generating_path[i].pointAt(1);
+ BB2 = BB3 = generating_path[i].pointAt(2);
+ if(similar_only.get_value()){
+ v = rot90(BB2 - BB1)*ratio;
+ }else{
+ v = (generating_path[i].pointAt(0) - BB1)*ratio;
+ }
+ }
+ BB1 -= v;
+ BB2 -= v;
+ BB3 += v;
+ BB4 += v;
+ Geom::Path path(BB1);
+ path.appendNew<LineSegment>(BB2);
+ path.appendNew<LineSegment>(BB3);
+ path.appendNew<LineSegment>(BB4);
+ path.close();
+ PathVector pathv;
+ pathv.push_back(path);
+ hp_vec.push_back(pathv);
+ }
+ }
+}
+*/
+
void
LPEVonKoch::doBeforeEffect (SPLPEItem *lpeitem)
{
+ using namespace Geom;
original_bbox(lpeitem);
+
+ std::vector<Geom::Path> paths = ref_path.get_pathvector();
+ Geom::Point A,B;
+ if (paths.size()==0||paths.front().size()==0){
+ //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug.
+ //refA.param_setValue( Geom::Point(boundingbox_X.min(), boundingbox_Y.middle()) );
+ //refB.param_setValue( Geom::Point(boundingbox_X.max(), boundingbox_Y.middle()) );
+ A = Point(boundingbox_X.min(), boundingbox_Y.middle());
+ B = Point(boundingbox_X.max(), boundingbox_Y.middle());
+ }else{
+ A = paths.front().pointAt(0);
+ B = paths.front().pointAt(paths.front().size());
+ }
+ if (paths.size()!=1||paths.front().size()!=1){
+ Geom::Path tmp_path(A);
+ tmp_path.appendNew<LineSegment>(B);
+ std::vector<Geom::Path> tmp_pathv;
+ tmp_pathv.push_back(tmp_path);
+ ref_path.set_new_value(tmp_pathv,true);
+ }
}
@@ -177,17 +273,36 @@ LPEVonKoch::resetDefaults(SPItem * item)
{
using namespace Geom;
original_bbox(SP_LPE_ITEM(item));
- Point start(boundingbox_X.min(), boundingbox_Y.middle());
- Point end(boundingbox_X.max(), boundingbox_Y.middle());
- std::vector<Geom::Path> paths;
- Geom::Path path = Geom::Path(start);
- path.appendNew<Geom::LineSegment>( end );
- paths.push_back(path * Matrix(1./3,0,0,1./3,start[X]*2./3,start[Y]*2./3 + boundingbox_Y.extent()/2));
- paths.push_back(path * Matrix(1./3,0,0,1./3, end[X]*2./3, end[Y]*2./3 + boundingbox_Y.extent()/2));
- paths.push_back(path);
+ Point A,B;
+ A[Geom::X] = boundingbox_X.min();
+ A[Geom::Y] = boundingbox_Y.middle();
+ B[Geom::X] = boundingbox_X.max();
+ B[Geom::Y] = boundingbox_Y.middle();
+
+ std::vector<Geom::Path> paths,refpaths;
+ Geom::Path path = Geom::Path(A);
+ path.appendNew<Geom::LineSegment>(B);
+ refpaths.push_back(path);
+ ref_path.set_new_value(refpaths, true);
+
+ paths.push_back(path * Matrix(1./3,0,0,1./3, A[X]*2./3, A[Y]*2./3 + boundingbox_Y.extent()/2));
+ paths.push_back(path * Matrix(1./3,0,0,1./3, B[X]*2./3, B[Y]*2./3 + boundingbox_Y.extent()/2));
generator.set_new_value(paths, true);
+
+ //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug.
+ //refA[Geom::X] = boundingbox_X.min();
+ //refA[Geom::Y] = boundingbox_Y.middle();
+ //refB[Geom::X] = boundingbox_X.max();
+ //refB[Geom::Y] = boundingbox_Y.middle();
+ //std::vector<Geom::Path> paths;
+ //Geom::Path path = Geom::Path( (Point) refA);
+ //path.appendNew<Geom::LineSegment>( (Point) refB );
+ //paths.push_back(path * Matrix(1./3,0,0,1./3, refA[X]*2./3, refA[Y]*2./3 + boundingbox_Y.extent()/2));
+ //paths.push_back(path * Matrix(1./3,0,0,1./3, refB[X]*2./3, refB[Y]*2./3 + boundingbox_Y.extent()/2));
+ //paths.push_back(path);
+ //generator.set_new_value(paths, true);
}
void
diff --git a/src/live_effects/lpe-vonkoch.h b/src/live_effects/lpe-vonkoch.h
index 011602eaf..16964f527 100644
--- a/src/live_effects/lpe-vonkoch.h
+++ b/src/live_effects/lpe-vonkoch.h
@@ -12,30 +12,38 @@
#include "live_effects/effect.h"
#include "live_effects/lpegroupbbox.h"
#include "live_effects/parameter/path.h"
-#include "live_effects/parameter/enum.h"
+#include "live_effects/parameter/point.h"
#include "live_effects/parameter/bool.h"
namespace Inkscape {
namespace LivePathEffect {
-enum VonKochRefType {
- VKREF_BBOX = 0,
- VKREF_SEG,
- VKREF_END // This must be last
-};
-
class VonKochPathParam : public PathParam{
public:
VonKochPathParam ( const Glib::ustring& label,
- const Glib::ustring& tip,
- const Glib::ustring& key,
- Inkscape::UI::Widget::Registry* wr,
- Effect* effect,
- const gchar * default_value = "M0,0 L1,1"):PathParam(label,tip,key,wr,effect,default_value){};
- virtual ~VonKochPathParam();
- virtual void param_setup_nodepath(Inkscape::NodePath::Path *np);
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const gchar * default_value = "M0,0 L1,1"):PathParam(label,tip,key,wr,effect,default_value){}
+ virtual ~VonKochPathParam(){}
+ virtual void param_setup_nodepath(Inkscape::NodePath::Path *np);
};
+ //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug.
+class VonKochRefPathParam : public PathParam{
+public:
+ VonKochRefPathParam ( const Glib::ustring& label,
+ const Glib::ustring& tip,
+ const Glib::ustring& key,
+ Inkscape::UI::Widget::Registry* wr,
+ Effect* effect,
+ const gchar * default_value = "M0,0 L1,1"):PathParam(label,tip,key,wr,effect,default_value){}
+ virtual ~VonKochRefPathParam(){}
+ virtual void param_setup_nodepath(Inkscape::NodePath::Path *np);
+ virtual bool param_readSVGValue(const gchar * strvalue);
+ };
+
class LPEVonKoch : public Effect, GroupBBoxEffect {
public:
LPEVonKoch(LivePathEffectObject *lpeobject);
@@ -49,16 +57,22 @@ public:
virtual void transform_multiply(Geom::Matrix const& postmul, bool set);
+ //Usefull??
+ // protected:
+ //virtual void addCanvasIndicators(SPLPEItem *lpeitem, std::vector<Geom::PathVector> &hp_vec);
+
private:
ScalarParam nbgenerations;
VonKochPathParam generator;
BoolParam similar_only;
BoolParam drawall;
- EnumParam<VonKochRefType> reftype;
+ //BoolParam draw_boxes;
+ //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug.
+ VonKochRefPathParam ref_path;
+ // PointParam refA;
+ // PointParam refB;
ScalarParam maxComplexity;
- //void on_pattern_pasted();
-
LPEVonKoch(const LPEVonKoch&);
LPEVonKoch& operator=(const LPEVonKoch&);
};
diff --git a/src/live_effects/lpegroupbbox.cpp b/src/live_effects/lpegroupbbox.cpp
index c11e99ecd..79e6857f0 100644
--- a/src/live_effects/lpegroupbbox.cpp
+++ b/src/live_effects/lpegroupbbox.cpp
@@ -27,7 +27,7 @@ GroupBBoxEffect::original_bbox(SPLPEItem *lpeitem, bool absolute)
transform = Geom::identity();
}
- Geom::Rect itemBBox = to_2geom(*item->getBounds(transform, SPItem::GEOMETRIC_BBOX)); // fixme: fix for when getBounds returns invalid Rect
+ Geom::Rect itemBBox = *item->getBounds(transform, SPItem::GEOMETRIC_BBOX); // fixme: fix for when getBounds returns invalid Rect
boundingbox_X = itemBBox[Geom::X];
boundingbox_Y = itemBBox[Geom::Y];
}
diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp
index ab49de14f..ec0dee0be 100644
--- a/src/live_effects/lpeobject.cpp
+++ b/src/live_effects/lpeobject.cpp
@@ -21,15 +21,6 @@
//#define LIVEPATHEFFECT_VERBOSE
-static void livepatheffect_class_init(LivePathEffectObjectClass *klass);
-static void livepatheffect_init(LivePathEffectObject *stop);
-
-static void livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
-static void livepatheffect_release(SPObject *object);
-
-static void livepatheffect_set(SPObject *object, unsigned key, gchar const *value);
-static Inkscape::XML::Node *livepatheffect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
-
static void livepatheffect_on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
static SPObjectClass *livepatheffect_parent_class;
@@ -37,7 +28,7 @@ static SPObjectClass *livepatheffect_parent_class;
* Registers the LivePathEffect class with Gdk and returns its type number.
*/
GType
-livepatheffect_get_type ()
+LivePathEffectObject::livepatheffect_get_type ()
{
static GType livepatheffect_type = 0;
@@ -45,11 +36,11 @@ livepatheffect_get_type ()
GTypeInfo livepatheffect_info = {
sizeof (LivePathEffectObjectClass),
NULL, NULL,
- (GClassInitFunc) livepatheffect_class_init,
+ (GClassInitFunc) LivePathEffectObject::livepatheffect_class_init,
NULL, NULL,
sizeof (LivePathEffectObject),
16,
- (GInstanceInitFunc) livepatheffect_init,
+ (GInstanceInitFunc) LivePathEffectObject::livepatheffect_init,
NULL,
};
livepatheffect_type = g_type_register_static (SP_TYPE_OBJECT, "LivePathEffectObject", &livepatheffect_info, (GTypeFlags)0);
@@ -69,8 +60,8 @@ static Inkscape::XML::NodeEventVector const livepatheffect_repr_events = {
/**
* Callback to initialize livepatheffect vtable.
*/
-static void
-livepatheffect_class_init(LivePathEffectObjectClass *klass)
+void
+LivePathEffectObject::livepatheffect_class_init(LivePathEffectObjectClass *klass)
{
SPObjectClass *sp_object_class = (SPObjectClass *) klass;
@@ -86,8 +77,8 @@ livepatheffect_class_init(LivePathEffectObjectClass *klass)
/**
* Callback to initialize livepatheffect object.
*/
-static void
-livepatheffect_init(LivePathEffectObject *lpeobj)
+void
+LivePathEffectObject::livepatheffect_init(LivePathEffectObject *lpeobj)
{
#ifdef LIVEPATHEFFECT_VERBOSE
g_message("Init livepatheffectobject");
@@ -101,8 +92,8 @@ livepatheffect_init(LivePathEffectObject *lpeobj)
/**
* Virtual build: set livepatheffect attributes from its associated XML node.
*/
-static void
-livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
+void
+LivePathEffectObject::livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
{
#ifdef LIVEPATHEFFECT_VERBOSE
g_message("Build livepatheffect");
@@ -126,8 +117,8 @@ livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node
/**
* Virtual release of livepatheffect members before destruction.
*/
-static void
-livepatheffect_release(SPObject *object)
+void
+LivePathEffectObject::livepatheffect_release(SPObject *object)
{
#ifdef LIVEPATHEFFECT_VERBOSE
g_print("Releasing livepatheffect");
@@ -168,8 +159,8 @@ livepatheffect_release(SPObject *object)
/**
* Virtual set: set attribute to value.
*/
-static void
-livepatheffect_set(SPObject *object, unsigned key, gchar const *value)
+void
+LivePathEffectObject::livepatheffect_set(SPObject *object, unsigned key, gchar const *value)
{
LivePathEffectObject *lpeobj = LIVEPATHEFFECT(object);
#ifdef LIVEPATHEFFECT_VERBOSE
@@ -202,8 +193,8 @@ livepatheffect_set(SPObject *object, unsigned key, gchar const *value)
/**
* Virtual write: write object attributes to repr.
*/
-static Inkscape::XML::Node *
-livepatheffect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
+Inkscape::XML::Node *
+LivePathEffectObject::livepatheffect_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
#ifdef LIVEPATHEFFECT_VERBOSE
g_print("Write livepatheffect");
@@ -243,10 +234,10 @@ livepatheffect_on_repr_attr_changed ( Inkscape::XML::Node * /*repr*/,
return;
LivePathEffectObject *lpeobj = (LivePathEffectObject*) data;
- if (!lpeobj->lpe)
+ if (!lpeobj->get_lpe())
return;
- lpeobj->lpe->setParameter(key, newval);
+ lpeobj->get_lpe()->setParameter(key, newval);
lpeobj->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
diff --git a/src/live_effects/lpeobject.h b/src/live_effects/lpeobject.h
index f141f07ca..dc631a5c1 100644
--- a/src/live_effects/lpeobject.h
+++ b/src/live_effects/lpeobject.h
@@ -12,26 +12,49 @@
#include "sp-object.h"
#include "effect.h"
-#define TYPE_LIVEPATHEFFECT (livepatheffect_get_type())
+namespace Inkscape {
+namespace XML {
+class Node;
+class Document;
+}
+}
+
+#define TYPE_LIVEPATHEFFECT (LivePathEffectObject::livepatheffect_get_type())
#define LIVEPATHEFFECT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), TYPE_LIVEPATHEFFECT, LivePathEffectObject))
#define IS_LIVEPATHEFFECT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), TYPE_LIVEPATHEFFECT))
+/// The LivePathEffect vtable.
+struct LivePathEffectObjectClass {
+ SPObjectClass parent_class;
+};
+
class LivePathEffectObject : public SPObject {
public:
Inkscape::LivePathEffect::EffectType effecttype;
- Inkscape::LivePathEffect::Effect *lpe;
bool effecttype_set;
LivePathEffectObject * fork_private_if_necessary(unsigned int nr_of_allowed_users = 1);
-};
-/// The LivePathEffect vtable.
-struct LivePathEffectObjectClass {
- SPObjectClass parent_class;
+ /* Note that the returned pointer can be NULL in a valid LivePathEffectObject contained in a valid list of lpeobjects in an lpeitem!
+ * So one should always check whether the returned value is NULL or not */
+ Inkscape::LivePathEffect::Effect * get_lpe() { return lpe; };
+
+private:
+ Inkscape::LivePathEffect::Effect *lpe; // this can be NULL in a valid LivePathEffectObject
+
+ /* C-style class functions: */
+public:
+ static GType livepatheffect_get_type();
+private:
+ static void livepatheffect_class_init(LivePathEffectObjectClass *klass);
+ static void livepatheffect_init(LivePathEffectObject *stop);
+ static void livepatheffect_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
+ static void livepatheffect_release(SPObject *object);
+ static void livepatheffect_set(SPObject *object, unsigned key, gchar const *value);
+ static Inkscape::XML::Node *livepatheffect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
};
-GType livepatheffect_get_type();
#endif
diff --git a/src/live_effects/parameter/pointparam-knotholder.cpp b/src/live_effects/parameter/pointparam-knotholder.cpp
index 34c149b4b..b814f597d 100644
--- a/src/live_effects/parameter/pointparam-knotholder.cpp
+++ b/src/live_effects/parameter/pointparam-knotholder.cpp
@@ -117,7 +117,8 @@ static void pointparam_knot_moved_handler(SPKnot */*knot*/, Geom::Point const *p
Inkscape::SVGOStringStream os;
os << pos;
- kh->lpeobject->lpe->setParameter(kh->repr_key, os.str().c_str());
+ // note: get_lpe() will always return a valid pointer?
+ kh->lpeobject->get_lpe()->setParameter(kh->repr_key, os.str().c_str());
}
static void pointparam_knot_ungrabbed_handler(SPKnot *knot, unsigned int /*state*/, PointParamKnotHolder *kh)