diff options
| author | Andrew Higginson <at.higginson@gmail.com> | 2011-12-27 21:04:47 +0000 |
|---|---|---|
| committer | Andrew <at.higginson@gmail.com> | 2011-12-27 21:04:47 +0000 |
| commit | 80960b623a99aae1402ab651b2974ef544ed3b03 (patch) | |
| tree | ba49d42c2789e9e11f805e2d5263e10f9fedeef8 /src/live_effects | |
| parent | try to fix bug (diff) | |
| parent | GDL: Cherry-pick upstream patch 73852 (2011-03-23) - Add missing return value. (diff) | |
| download | inkscape-80960b623a99aae1402ab651b2974ef544ed3b03.tar.gz inkscape-80960b623a99aae1402ab651b2974ef544ed3b03.zip | |
merged with trunk so I can build again...
(bzr r10092.1.36)
Diffstat (limited to 'src/live_effects')
45 files changed, 889 insertions, 381 deletions
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 70e8cbaf8..94112a52e 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -1,37 +1,117 @@ -ADD_SUBDIRECTORY(parameter) -SET(live_effects_SRC -bezctx.cpp -effect.cpp -lpe-bendpath.cpp -lpe-boolops.cpp -lpe-circle_with_radius.cpp -lpe-constructgrid.cpp -lpe-curvestitch.cpp -lpe-envelope.cpp -lpe-gears.cpp -lpegroupbbox.cpp -lpe-interpolate.cpp -lpe-knot.cpp -lpe-rough-hatches.cpp -lpe-lattice.cpp -lpe-mirror_symmetry.cpp -lpeobject.cpp -lpeobject-reference.cpp -lpe-patternalongpath.cpp -lpe-perp_bisector.cpp -lpe-perspective_path.cpp -lpe-powerstroke.cpp -lpe-skeleton.cpp -lpe-sketch.cpp -lpe-spiro.cpp -lpe-tangent_to_curve.cpp -lpe-test-doEffect-stack.cpp -lpe-vonkoch.cpp -lpe-dynastroke.cpp -spiro.cpp -${live_effects_parameter_SRC} +set(live_effects_SRC + bezctx.cpp + effect.cpp + lpe-angle_bisector.cpp + lpe-bendpath.cpp + lpe-boolops.cpp + lpe-circle_3pts.cpp + lpe-circle_with_radius.cpp + lpe-constructgrid.cpp + lpe-copy_rotate.cpp + lpe-curvestitch.cpp + lpe-dynastroke.cpp + lpe-envelope.cpp + lpe-extrude.cpp + lpe-gears.cpp + lpe-interpolate.cpp + lpe-knot.cpp + lpe-lattice.cpp + lpe-line_segment.cpp + lpe-mirror_symmetry.cpp + lpe-offset.cpp + lpe-parallel.cpp + lpe-path_length.cpp + lpe-patternalongpath.cpp + lpe-perp_bisector.cpp + lpe-perspective_path.cpp + lpe-powerstroke.cpp + lpe-recursiveskeleton.cpp + lpe-rough-hatches.cpp + lpe-ruler.cpp + # lpe-skeleton.cpp + lpe-sketch.cpp + lpe-spiro.cpp + lpe-tangent_to_curve.cpp + lpe-test-doEffect-stack.cpp + lpe-text_label.cpp + lpe-vonkoch.cpp + lpegroupbbox.cpp + lpeobject-reference.cpp + lpeobject.cpp + spiro.cpp + + parameter/array.cpp + parameter/bool.cpp + parameter/parameter.cpp + parameter/path.cpp + parameter/path-reference.cpp + parameter/point.cpp + parameter/powerstrokepointarray.cpp + parameter/random.cpp + parameter/text.cpp + parameter/unit.cpp + parameter/vector.cpp + + + # ------- + # Headers + bezctx.h + bezctx_intf.h + effect-enum.h + effect.h + lpe-angle_bisector.h + lpe-bendpath.h + lpe-boolops.h + lpe-circle_3pts.h + lpe-circle_with_radius.h + lpe-constructgrid.h + lpe-copy_rotate.h + lpe-curvestitch.h + lpe-dynastroke.h + lpe-envelope.h + lpe-extrude.h + lpe-gears.h + lpe-interpolate.h + lpe-knot.h + lpe-lattice.h + lpe-line_segment.h + lpe-mirror_symmetry.h + lpe-offset.h + lpe-parallel.h + lpe-path_length.h + lpe-patternalongpath.h + lpe-perp_bisector.h + lpe-perspective_path.h + lpe-powerstroke.h + lpe-powerstroke-interpolators.h + lpe-recursiveskeleton.h + lpe-rough-hatches.h + lpe-ruler.h + lpe-skeleton.h + lpe-sketch.h + lpe-spiro.h + lpe-tangent_to_curve.h + lpe-test-doEffect-stack.h + lpe-text_label.h + lpe-vonkoch.h + lpegroupbbox.h + lpeobject-reference.h + lpeobject.h + parameter/array.h + parameter/bool.h + parameter/enum.h + parameter/parameter.h + parameter/path-reference.h + parameter/path.h + parameter/point.h + parameter/powerstrokepointarray.h + parameter/random.h + parameter/text.h + parameter/unit.h + parameter/vector.h + spiro.h ) -ADD_LIBRARY(live_effects STATIC ${live_effects_SRC}) -TARGET_LINK_LIBRARIES(live_effects -2geom ${INKSCAPE_LIBS})
\ No newline at end of file + +# add_inkscape_lib(live_effects_LIB "${live_effects_SRC}") +add_inkscape_source("${live_effects_SRC}") diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index aacabc2db..692503201 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -69,6 +69,7 @@ ink_common_sources += \ live_effects/lpe-copy_rotate.h \ live_effects/lpe-powerstroke.cpp \ live_effects/lpe-powerstroke.h \ + live_effects/lpe-powerstroke-interpolators.h \ live_effects/lpe-offset.cpp \ live_effects/lpe-offset.h \ live_effects/lpe-ruler.cpp \ diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index ed0d162ac..e040eec32 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -100,7 +100,6 @@ const Util::EnumData<EffectType> LPETypeData[] = { {PATH_LENGTH, N_("Path length"), "path_length"}, {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, - {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, @@ -121,7 +120,8 @@ const Util::EnumData<EffectType> LPETypeData[] = { {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, {SKETCH, N_("Sketch"), "sketch"}, {RULER, N_("Ruler"), "ruler"}, -/* 0.49 */ +/* 0.49 ?*/ + {POWERSTROKE, N_("[Unstable!] Power stroke"), "powerstroke"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -262,7 +262,7 @@ void Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item) Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); repr->setAttribute("effect", name); - SP_DOCUMENT_DEFS(doc)->getRepr()->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute + doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute const gchar * repr_id = repr->attribute("id"); Inkscape::GC::release(repr); @@ -436,7 +436,7 @@ Effect::readallParameters(Inkscape::XML::Node * repr) param->param_set_default(); } - it++; + ++it; } } @@ -572,7 +572,7 @@ Effect::newWidget(Gtk::Tooltips * tooltips) } } - it++; + ++it; } return dynamic_cast<Gtk::Widget *>(vbox); @@ -604,7 +604,7 @@ Effect::getParameter(const char * key) return param; } - it++; + ++it; } return NULL; @@ -671,7 +671,7 @@ void Effect::transform_multiply(Geom::Affine const& postmul, bool set) { // cycle through all parameters. Most parameters will not need transformation, but path and point params do. - for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) { + for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) { Parameter * param = *it; param->param_transform_multiply(postmul, set); } diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 7fe4e9348..48577c225 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -21,13 +21,13 @@ struct SPDocument; struct SPDesktop; -struct SPItem; -class SPNodeContext; +class SPItem; +class SPNodeContext; struct LivePathEffectObject; -class SPLPEItem; -class KnotHolder; -class KnotHolderEntity; -class SPPath; +class SPLPEItem; +class KnotHolder; +class KnotHolderEntity; +class SPPath; struct SPCurve; namespace Gtk { @@ -157,7 +157,7 @@ protected: LivePathEffectObject *lpeobj; // this boolean defaults to false, it concatenates the input path to one pwd2, - // instead of normally 'splitting' the path into continuous pwd2 paths. + // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. bool concatenate_before_pwd2; private: diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp index 4aec82377..8a32cd230 100644 --- a/src/live_effects/lpe-circle_with_radius.cpp +++ b/src/live_effects/lpe-circle_with_radius.cpp @@ -1,5 +1,6 @@ -/** @file - * @brief LPE effect that draws a circle based on two points and a radius +/** + * @file + * LPE effect that draws a circle based on two points and a radius. * - implementation */ /* Authors: diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index febe33208..9bac3b860 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -30,7 +30,6 @@ #include <2geom/affine.h> #include "ui/widget/scalar.h" -#include "libnr/nr-values.h" namespace Inkscape { namespace LivePathEffect { @@ -40,13 +39,13 @@ using namespace Geom; LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : Effect(lpeobject), strokepath(_("Stitch path:"), _("The path that will be used as stitch."), "strokepath", &wr, this, "M0,0 L1,0"), - nrofpaths(_("Number of paths:"), _("The number of paths that will be generated."), "count", &wr, this, 5), - startpoint_edge_variation(_("Start edge variance:"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0), - startpoint_spacing_variation(_("Start spacing variance:"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0), - endpoint_edge_variation(_("End edge variance:"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0), - endpoint_spacing_variation(_("End spacing variance:"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0), - prop_scale(_("Scale width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1), - scale_y_rel(_("Scale width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false) + nrofpaths(_("N_umber of paths:"), _("The number of paths that will be generated."), "count", &wr, this, 5), + startpoint_edge_variation(_("Sta_rt edge variance:"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0), + startpoint_spacing_variation(_("Sta_rt spacing variance:"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0), + endpoint_edge_variation(_("End ed_ge variance:"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0), + endpoint_spacing_variation(_("End spa_cing variance:"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0), + prop_scale(_("Scale _width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1), + scale_y_rel(_("Scale _width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false) { registerParameter( dynamic_cast<Parameter *>(&nrofpaths) ); registerParameter( dynamic_cast<Parameter *>(&startpoint_edge_variation) ); @@ -58,7 +57,7 @@ LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); nrofpaths.param_make_integer(); - nrofpaths.param_set_range(2, NR_HUGE); + nrofpaths.param_set_range(2, Geom::infinity()); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp index 97d49d83d..0fd31dccf 100644 --- a/src/live_effects/lpe-dynastroke.cpp +++ b/src/live_effects/lpe-dynastroke.cpp @@ -97,11 +97,11 @@ LPEDynastroke::LPEDynastroke(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(& round_ends) ); registerParameter( dynamic_cast<Parameter *>(& capping) ); - width.param_set_range(0, NR_HUGE); + width.param_set_range(0, Geom::infinity()); roundness.param_set_range(0.01, 1); angle.param_set_range(-360, 360); - growfor.param_set_range(0, NR_HUGE); - fadefor.param_set_range(0, NR_HUGE); + growfor.param_set_range(0, Geom::infinity()); + fadefor.param_set_range(0, Geom::infinity()); show_orig_path = true; } diff --git a/src/live_effects/lpe-extrude.cpp b/src/live_effects/lpe-extrude.cpp index 96d465569..61b61f7bf 100644 --- a/src/live_effects/lpe-extrude.cpp +++ b/src/live_effects/lpe-extrude.cpp @@ -1,6 +1,6 @@ -#define INKSCAPE_LPE_EXTRUDE_CPP -/** \file - * @brief LPE effect for extruding paths (making them "3D"). +/** + * @file + * LPE effect for extruding paths (making them "3D"). * */ /* Authors: @@ -174,10 +174,10 @@ LPEExtrude::resetDefaults(SPItem * item) using namespace Geom; - Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX); + Geom::OptRect bbox = item->geometricBounds(); if (bbox) { - Interval boundingbox_X = (*bbox)[Geom::X]; - Interval boundingbox_Y = (*bbox)[Geom::Y]; + Interval const &boundingbox_X = (*bbox)[Geom::X]; + Interval const &boundingbox_Y = (*bbox)[Geom::Y]; extrude_vector.set_and_write_new_values( Geom::Point(boundingbox_X.middle(), boundingbox_Y.middle()), (boundingbox_X.extent() + boundingbox_Y.extent())*Geom::Point(-0.05,0.2) ); } diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp index 337beb516..ac2db1716 100644 --- a/src/live_effects/lpe-gears.cpp +++ b/src/live_effects/lpe-gears.cpp @@ -244,12 +244,13 @@ LPEGears::doEffect_path (std::vector<Geom::Path> const & path_in) gear->centre(gear_centre); gear->angle(atan2((*it).initialPoint() - gear_centre)); - it++; if ( it == gearpath.end() ) return path_out; + ++it; + if ( it == gearpath.end() ) return path_out; gear->pitch_radius(Geom::distance(gear_centre, (*it).finalPoint())); path_out.push_back( gear->path()); - for (it++ ; it != gearpath.end() ; it++) { + for (++it; it != gearpath.end() ; ++it) { // iterate through Geom::Curve in path_in Gear* gearnew = new Gear(gear->spawn( (*it).finalPoint() )); path_out.push_back( gearnew->path() ); diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index 47965749e..621823546 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -28,8 +28,8 @@ namespace LivePathEffect { LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) : Effect(lpeobject), trajectory_path(_("Trajectory:"), _("Path along which intermediate steps are created."), "trajectory", &wr, this, "M0,0 L0,0"), - number_of_steps(_("Steps:"), _("Determines the number of steps from start to end path."), "steps", &wr, this, 5), - equidistant_spacing(_("Equidistant spacing"), _("If true, the spacing between intermediates is constant along the length of the path. If false, the distance depends on the location of the nodes of the trajectory path."), "equidistant_spacing", &wr, this, true) + number_of_steps(_("Steps_:"), _("Determines the number of steps from start to end path."), "steps", &wr, this, 5), + equidistant_spacing(_("E_quidistant spacing"), _("If true, the spacing between intermediates is constant along the length of the path. If false, the distance depends on the location of the nodes of the trajectory path."), "equidistant_spacing", &wr, this, true) { show_orig_path = true; @@ -38,7 +38,7 @@ LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&number_of_steps) ); number_of_steps.param_make_integer(); - number_of_steps.param_set_range(2, NR_HUGE); + number_of_steps.param_set_range(2, Geom::infinity()); } LPEInterpolate::~LPEInterpolate() diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index e45515a8e..9decdea9b 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -1,5 +1,6 @@ -/** @file - * @brief LPE knot effect implementation +/** + * @file + * LPE knot effect implementation. */ /* Authors: * Jean-Francois Barraud <jf.barraud@gmail.com> @@ -124,7 +125,7 @@ findShadowedTime(Geom::Path const &patha, std::vector<Geom::Point> const &pt_and double tmin = 0, tmax = size_nondegenerate(patha); double period = size_nondegenerate(patha); - if (times.size()>0){ + if (!times.empty()){ unsigned rk = upper_bound( times.begin(), times.end(), ta ) - times.begin(); if ( rk < times.size() ) tmax = times[rk]; @@ -213,7 +214,7 @@ CrossingPoints::CrossingPoints(std::vector<Geom::Path> const &paths) : std::vect if (cp.j == i) cuts[cp.tj] = k; } unsigned count = 0; - for ( std::map < double, unsigned >::iterator m=cuts.begin(); m!=cuts.end(); m++ ){ + for ( std::map < double, unsigned >::iterator m=cuts.begin(); m!=cuts.end(); ++m ){ if ( (*this)[m->second].i == i && (*this)[m->second].ti == m->first ){ (*this)[m->second].ni = count; }else{ @@ -340,11 +341,11 @@ CrossingPoints::inherit_signs(CrossingPoints const &other, int default_value) LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: - interruption_width(_("Fixed width:"), _("Size of hidden region of lower string"), "interruption_width", &wr, this, 3), - prop_to_stroke_width(_("In units of stroke width"), _("Consider 'Interruption width' as a ratio of stroke width"), "prop_to_stroke_width", &wr, this, true), - add_stroke_width(_("Stroke width"), _("Add the stroke width to the interruption size"), "add_stroke_width", &wr, this, true), - add_other_stroke_width(_("Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true), - switcher_size(_("Switcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15), + interruption_width(_("Fi_xed width:"), _("Size of hidden region of lower string"), "interruption_width", &wr, this, 3), + prop_to_stroke_width(_("_In units of stroke width"), _("Consider 'Interruption width' as a ratio of stroke width"), "prop_to_stroke_width", &wr, this, true), + add_stroke_width(_("St_roke width"), _("Add the stroke width to the interruption size"), "add_stroke_width", &wr, this, true), + add_other_stroke_width(_("_Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true), + switcher_size(_("S_witcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15), crossing_points_vector(_("Crossing Signs"), _("Crossings signs"), "crossing_points_vector", &wr, this), gpaths(),gstroke_widths() { @@ -464,7 +465,7 @@ LPEKnot::doEffect_path (std::vector<Geom::Path> const &path_in) } //If the all component is hidden, continue. - if ( dom.size() == 0){ + if (dom.empty()){ continue; } @@ -517,7 +518,7 @@ void collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector<Geom::Path> &p for (unsigned i=0; i<subpaths.size(); i++){ paths.push_back(subpaths[i]); //FIXME: do we have to be more carefull when trying to access stroke width? - stroke_widths.push_back(SP_ITEM(lpeitem)->style->stroke_width.computed); + stroke_widths.push_back(lpeitem->style->stroke_width.computed); } } } diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index 50ecdf04b..473469c8a 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -1,4 +1,3 @@ -#define INKSCAPE_LPE_LATTICE_CPP /** \file * LPE <lattice> implementation @@ -283,7 +282,7 @@ LPELattice::addHelperPathsImpl(SPLPEItem *lpeitem, SPDesktop *desktop) c->lineto(grid_point3); // TODO: factor this out (and remove the #include of desktop.h above) - SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, c, SP_ITEM(lpeitem), 0x009000ff); + SPCanvasItem *canvasitem = sp_nodepath_generate_helperpath(desktop, c, lpeitem, 0x009000ff); Inkscape::Display::TemporaryItem* tmpitem = desktop->add_temporary_canvasitem (canvasitem, 0); lpeitem->lpe_helperpaths.push_back(tmpitem); diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index dec8c9216..2d043ca91 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -45,9 +45,10 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem *lpeitem) { using namespace Geom; - SPItem *item = SP_ITEM(lpeitem); - Geom::Affine t = item->i2d_affine(); - Geom::Rect bbox = *item->getBounds(t); // fixme: what happens if getBounds does not return a valid rect? + // fixme: what happens if the bbox is empty? + // fixme: this is probably wrong + Geom::Affine t = lpeitem->i2dt_affine(); + Geom::Rect bbox = *lpeitem->desktopVisualBounds(); Point A(bbox.left(), bbox.bottom()); Point B(bbox.left(), bbox.top()); diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index bbcf9b1c3..0a05228d2 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -61,22 +61,22 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : pattern(_("Pattern source:"), _("Path to put along the skeleton path"), "pattern", &wr, this, "M0,0 L1,0"), copytype(_("Pattern copies:"), _("How many pattern copies to place along the skeleton path"), "copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED), - prop_scale(_("Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1), - scale_y_rel(_("Width in units of length"), + prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1), + scale_y_rel(_("Wid_th in units of length"), _("Scale the width of the pattern in units of its length"), "scale_y_rel", &wr, this, false), - spacing(_("Spacing:"), + spacing(_("Spa_cing:"), // xgettext:no-c-format _("Space between copies of the pattern. Negative values allowed, but are limited to -90% of pattern width."), "spacing", &wr, this, 0), - normal_offset(_("Normal offset:"), "", "normal_offset", &wr, this, 0), - tang_offset(_("Tangential offset:"), "", "tang_offset", &wr, this, 0), - prop_units(_("Offsets in unit of pattern size"), + normal_offset(_("No_rmal offset:"), "", "normal_offset", &wr, this, 0), + tang_offset(_("Tan_gential offset:"), "", "tang_offset", &wr, this, 0), + prop_units(_("Offsets in _unit of pattern size"), _("Spacing, tangential and normal offset are expressed as a ratio of width/height"), "prop_units", &wr, this, false), - vertical_pattern(_("Pattern is vertical"), _("Rotate pattern 90 deg before applying"), + vertical_pattern(_("Pattern is _vertical"), _("Rotate pattern 90 deg before applying"), "vertical_pattern", &wr, this, false), - fuse_tolerance(_("Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."), + fuse_tolerance(_("_Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."), "fuse_tolerance", &wr, this, 0) { registerParameter( dynamic_cast<Parameter *>(&pattern) ); @@ -139,9 +139,9 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con } //TODO: dynamical update of parameter ranges? //if (prop_units.get_value()){ - // spacing.param_set_range(-.9, NR_HUGE); + // spacing.param_set_range(-.9, Geom::infinity()); // }else{ - // spacing.param_set_range(-pattBndsX.extent()*.9, NR_HUGE); + // spacing.param_set_range(-pattBndsX.extent()*.9, Geom::infinity()); // } y0+=noffset; diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index 58efe4ef5..9208d4aeb 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -1,5 +1,6 @@ -/** @file - * @brief LPE perspective path effect implementation. +/** + * @file + * LPE perspective path effect implementation. */ /* Authors: * Maximilian Albert <maximilian.albert@gmail.com> diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h new file mode 100644 index 000000000..7f9cb3ddb --- /dev/null +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -0,0 +1,280 @@ +/** @file + * Interpolators for lists of points. + */ +/* Authors: + * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> + * + * Copyright (C) 2010-2011 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_LPE_POWERSTROKE_INTERPOLATORS_H +#define INKSCAPE_LPE_POWERSTROKE_INTERPOLATORS_H + +#include <2geom/path.h> +#include <2geom/bezier-utils.h> +#include <2geom/sbasis-to-bezier.h> + +#include "live_effects/bezctx.h" +#include "live_effects/bezctx_intf.h" +#include "live_effects/spiro.h" + + +/// @TODO Move this to 2geom? +namespace Geom { +namespace Interpolate { + +enum InterpolatorType { + INTERP_LINEAR, + INTERP_CUBICBEZIER, + INTERP_CUBICBEZIER_JOHAN, + INTERP_SPIRO +}; + +class Interpolator { +public: + Interpolator() {}; + virtual ~Interpolator() {}; + + static Interpolator* create(InterpolatorType type); + + virtual Geom::Path interpolateToPath(std::vector<Point> const &points) const = 0; + +private: + Interpolator(const Interpolator&); + Interpolator& operator=(const Interpolator&); +}; + +class Linear : public Interpolator { +public: + Linear() {}; + virtual ~Linear() {}; + + virtual Path interpolateToPath(std::vector<Point> const &points) const { + Path path; + path.start( points.at(0) ); + for (unsigned int i = 1 ; i < points.size(); ++i) { + path.appendNew<Geom::LineSegment>(points.at(i)); + } + return path; + }; + +private: + Linear(const Linear&); + Linear& operator=(const Linear&); +}; + +// this class is terrible +class CubicBezierFit : public Interpolator { +public: + CubicBezierFit() {}; + virtual ~CubicBezierFit() {}; + + virtual Path interpolateToPath(std::vector<Point> const &points) const { + unsigned int n_points = points.size(); + // worst case gives us 2 segment per point + int max_segs = 8*n_points; + Geom::Point * b = g_new(Geom::Point, max_segs); + Geom::Point * points_array = g_new(Geom::Point, 4*n_points); + for (unsigned i = 0; i < n_points; ++i) { + points_array[i] = points.at(i); + } + + double tolerance_sq = 0; // this value is just a random guess + + int const n_segs = Geom::bezier_fit_cubic_r(b, points_array, n_points, + tolerance_sq, max_segs); + + Geom::Path fit; + if ( n_segs > 0) + { + fit.start(b[0]); + for (int c = 0; c < n_segs; c++) { + fit.appendNew<Geom::CubicBezier>(b[4*c+1], b[4*c+2], b[4*c+3]); + } + } + g_free(b); + g_free(points_array); + return fit; + }; + +private: + CubicBezierFit(const CubicBezierFit&); + CubicBezierFit& operator=(const CubicBezierFit&); +}; + +/// @todo invent name for this class +class CubicBezierJohan : public Interpolator { +public: + CubicBezierJohan(double beta = 0.2) { + _beta = beta; + }; + virtual ~CubicBezierJohan() {}; + + virtual Path interpolateToPath(std::vector<Point> const &points) const { + Path fit; + fit.start(points.at(0)); + for (unsigned int i = 1; i < points.size(); ++i) { + Point p0 = points.at(i-1); + Point p1 = points.at(i); + Point dx = Point(p1[X] - p0[X], 0); + fit.appendNew<CubicBezier>(p0+_beta*dx, p1-_beta*dx, p1); + } + return fit; + }; + + void setBeta(double beta) { + _beta = beta; + } + + double _beta; + +private: + CubicBezierJohan(const CubicBezierJohan&); + CubicBezierJohan& operator=(const CubicBezierJohan&); +}; + + +#define SPIRO_SHOW_INFINITE_COORDINATE_CALLS +class SpiroInterpolator : public Interpolator { +public: + SpiroInterpolator() {}; + virtual ~SpiroInterpolator() {}; + + virtual Path interpolateToPath(std::vector<Point> const &points) const { + Path fit; + + Coord scale_y = 100.; + + guint len = points.size(); + bezctx *bc = new_bezctx_ink(&fit); + spiro_cp *controlpoints = g_new (spiro_cp, len); + for (unsigned int i = 0; i < len; ++i) { + controlpoints[i].x = points[i][X]; + controlpoints[i].y = points[i][Y] / scale_y; + controlpoints[i].ty = 'c'; + } + controlpoints[0].ty = '{'; + controlpoints[1].ty = 'v'; + controlpoints[len-2].ty = 'v'; + controlpoints[len-1].ty = '}'; + + spiro_seg *s = run_spiro(controlpoints, len); + spiro_to_bpath(s, len, bc); + free(s); + free(bc); + + fit *= Scale(1,scale_y); + return fit; + }; + +private: + typedef struct { + bezctx base; + Path *path; + int is_open; + } bezctx_ink; + + static void bezctx_ink_moveto(bezctx *bc, double x, double y, int /*is_open*/) + { + bezctx_ink *bi = (bezctx_ink *) bc; + if ( IS_FINITE(x) && IS_FINITE(y) ) { + bi->path->start(Point(x, y)); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro moveto not finite"); + } + #endif + } + + static void bezctx_ink_lineto(bezctx *bc, double x, double y) + { + bezctx_ink *bi = (bezctx_ink *) bc; + if ( IS_FINITE(x) && IS_FINITE(y) ) { + bi->path->appendNew<LineSegment>( Point(x, y) ); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro lineto not finite"); + } + #endif + } + + static void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3) + { + bezctx_ink *bi = (bezctx_ink *) bc; + + if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) { + bi->path->appendNew<QuadraticBezier>(Point(xm, ym), Point(x3, y3)); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro quadto not finite"); + } + #endif + } + + static void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2, + double x3, double y3) + { + bezctx_ink *bi = (bezctx_ink *) bc; + if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) { + bi->path->appendNew<CubicBezier>(Point(x1, y1), Point(x2, y2), Point(x3, y3)); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro curveto not finite"); + } + #endif + } + + bezctx * + new_bezctx_ink(Geom::Path *path) const { + bezctx_ink *result = g_new(bezctx_ink, 1); + result->base.moveto = bezctx_ink_moveto; + result->base.lineto = bezctx_ink_lineto; + result->base.quadto = bezctx_ink_quadto; + result->base.curveto = bezctx_ink_curveto; + result->base.mark_knot = NULL; + result->path = path; + return &result->base; + } + + SpiroInterpolator(const SpiroInterpolator&); + SpiroInterpolator& operator=(const SpiroInterpolator&); +}; + + +Interpolator* +Interpolator::create(InterpolatorType type) { + switch (type) { + case INTERP_LINEAR: + return new Geom::Interpolate::Linear(); + case INTERP_CUBICBEZIER: + return new Geom::Interpolate::CubicBezierFit(); + case INTERP_CUBICBEZIER_JOHAN: + return new Geom::Interpolate::CubicBezierJohan(); + case INTERP_SPIRO: + return new Geom::Interpolate::SpiroInterpolator(); + default: + return new Geom::Interpolate::Linear(); + } +} + +} //namespace Interpolate +} //namespace Geom + +#endif + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 5dc170e84..25cb72b42 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -1,16 +1,17 @@ -#define INKSCAPE_LPE_POWERSTROKE_CPP -/** \file - * @brief PowerStroke LPE implementation. Creates curves with modifiable stroke width. +/** + * @file + * PowerStroke LPE implementation. Creates curves with modifiable stroke width. */ /* Authors: - * Johan Engelen <j.b.c.engelen@utwente.nl> + * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> * - * Copyright (C) 2010 Authors + * Copyright (C) 2010-2011 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #include "live_effects/lpe-powerstroke.h" +#include "live_effects/lpe-powerstroke-interpolators.h" #include "sp-shape.h" #include "display/curve.h" @@ -20,123 +21,72 @@ #include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> #include <2geom/bezier-utils.h> +#include <2geom/svg-elliptical-arc.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/svg-path.h> -/// @TODO Move this to 2geom -namespace Geom { -namespace Interpolate { - -class Interpolator { -public: - Interpolator() {}; - virtual ~Interpolator() {}; - -// virtual Piecewise<D2<SBasis> > interpolateToPwD2Sb(std::vector<Point> points) = 0; - virtual Path interpolateToPath(std::vector<Point> points) = 0; +namespace Inkscape { +namespace LivePathEffect { -private: - Interpolator(const Interpolator&); - Interpolator& operator=(const Interpolator&); +static const Util::EnumData<unsigned> InterpolatorTypeData[] = { + {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, + {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, + {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"} }; +static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); -class Linear : public Interpolator { -public: - Linear() {}; - virtual ~Linear() {}; - - virtual Path interpolateToPath(std::vector<Point> points) { - Path path; - path.start( points.at(0) ); - for (unsigned int i = 1 ; i < points.size(); ++i) { - path.appendNew<Geom::LineSegment>(points.at(i)); - } - return path; - }; - -private: - Linear(const Linear&); - Linear& operator=(const Linear&); +enum LineCapType { + LINECAP_BUTT, + LINECAP_SQUARE, + LINECAP_ROUND, + LINECAP_PEAK }; - -// this class is terrible -class CubicBezierFit : public Interpolator { -public: - CubicBezierFit() {}; - virtual ~CubicBezierFit() {}; - - virtual Path interpolateToPath(std::vector<Point> points) { - unsigned int n_points = points.size(); - // worst case gives us 2 segment per point - int max_segs = 8*n_points; - Geom::Point * b = g_new(Geom::Point, max_segs); - Geom::Point * points_array = g_new(Geom::Point, 4*n_points); - for (unsigned i = 0; i < n_points; ++i) { - points_array[i] = points.at(i); - } - - double tolerance_sq = 0; // this value is just a random guess - - int const n_segs = Geom::bezier_fit_cubic_r(b, points_array, n_points, - tolerance_sq, max_segs); - - Geom::Path fit; - if ( n_segs > 0) - { - fit.start(b[0]); - for (int c = 0; c < n_segs; c++) { - fit.appendNew<Geom::CubicBezier>(b[4*c+1], b[4*c+2], b[4*c+3]); - } - } - g_free(b); - g_free(points_array); - return fit; - }; - -private: - CubicBezierFit(const CubicBezierFit&); - CubicBezierFit& operator=(const CubicBezierFit&); +static const Util::EnumData<unsigned> LineCapTypeData[] = { + {LINECAP_BUTT , N_("Butt"), "butt"}, + {LINECAP_SQUARE, N_("Square"), "square"}, + {LINECAP_ROUND , N_("Round"), "round"}, + {LINECAP_PEAK , N_("Peak"), "peak"} }; +static const Util::EnumDataConverter<unsigned> LineCapTypeConverter(LineCapTypeData, sizeof(LineCapTypeData)/sizeof(*LineCapTypeData)); -/// @todo invent name for this class -class CubicBezierJohan : public Interpolator { -public: - CubicBezierJohan() {}; - virtual ~CubicBezierJohan() {}; - - virtual Path interpolateToPath(std::vector<Point> points) { - Path fit; - fit.start(points.at(0)); - for (unsigned int i = 1; i < points.size(); ++i) { - Point p0 = points.at(i-1); - Point p1 = points.at(i); - Point dx = Point(p1[X] - p0[X], 0); - fit.appendNew<CubicBezier>(p0+0.2*dx, p1-0.2*dx, p1); - } - return fit; - }; - -private: - CubicBezierJohan(const CubicBezierJohan&); - CubicBezierJohan& operator=(const CubicBezierJohan&); +enum LineCuspType { + LINECUSP_BEVEL, + LINECUSP_ROUND, + LINECUSP_SHARP }; - -} //namespace Interpolate -} //namespace Geom - -namespace Inkscape { -namespace LivePathEffect { +static const Util::EnumData<unsigned> LineCuspTypeData[] = { + {LINECUSP_BEVEL , N_("Beveled"), "bevel"}, + {LINECUSP_ROUND , N_("Rounded"), "round"}, +// not yet supported {LINECUSP_SHARP , N_("Sharp"), "sharp"} +}; +static const Util::EnumDataConverter<unsigned> LineCuspTypeConverter(LineCuspTypeData, sizeof(LineCuspTypeData)/sizeof(*LineCuspTypeData)); LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this), - sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true) + sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true), + interpolator_type(_("Interpolator type"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path."), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN), + interpolator_beta(_("Smoothness"), _("Sets the smoothness for the CubicBezierJohan interpolator. 0 = linear interpolation, 1 = smooth"), "interpolator_beta", &wr, this, 0.2), + start_linecap_type(_("Start line cap type"), _("Determines the shape of the path's start."), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND), + cusp_linecap_type(_("Cusp line cap type"), _("Determines the shape of the cusps along the path."), "cusp_linecap_type", LineCuspTypeConverter, &wr, this, LINECUSP_ROUND), + end_linecap_type(_("End line cap type"), _("Determines the shape of the path's end."), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND) { show_orig_path = true; /// @todo offset_points are initialized with empty path, is that bug-save? + interpolator_beta.addSlider(true); + interpolator_beta.param_set_range(0.,1.); + registerParameter( dynamic_cast<Parameter *>(&offset_points) ); registerParameter( dynamic_cast<Parameter *>(&sort_points) ); + registerParameter( dynamic_cast<Parameter *>(&interpolator_type) ); + registerParameter( dynamic_cast<Parameter *>(&interpolator_beta) ); + registerParameter( dynamic_cast<Parameter *>(&start_linecap_type) ); + registerParameter( dynamic_cast<Parameter *>(&cusp_linecap_type) ); + registerParameter( dynamic_cast<Parameter *>(&end_linecap_type) ); } LPEPowerStroke::~LPEPowerStroke() @@ -156,95 +106,237 @@ LPEPowerStroke::doOnApply(SPLPEItem *lpeitem) offset_points.param_set_and_write_new_value(points); } +void +LPEPowerStroke::adjustForNewPath(std::vector<Geom::Path> const & path_in) +{ + offset_points.recalculate_controlpoints_for_new_pwd2(path_in[0].toPwSb()); +} + static bool compare_offsets (Geom::Point first, Geom::Point second) { return first[Geom::X] < second[Geom::X]; } - -Geom::Piecewise<Geom::D2<Geom::SBasis> > -LPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +// find discontinuities in input path +struct discontinuity_data { + Geom::Point der0; // unit derivative of 'left' side of cusp + Geom::Point der1; // unit derivative of 'right' side of cusp + double width; // intended stroke width at cusp +}; +std::vector<discontinuity_data> find_discontinuities( Geom::Piecewise<Geom::D2<Geom::SBasis> > const & der, + Geom::Piecewise<Geom::SBasis> const & x, + Geom::Piecewise<Geom::SBasis> const & y, + double eps=Geom::EPSILON ) { - using namespace Geom; - - offset_points.set_pwd2(pwd2_in); + std::vector<discontinuity_data> vect; + for(unsigned i = 1; i < der.size(); i++) { + if ( ! are_near(der[i-1].at1(), der[i].at0(), eps) ) { + discontinuity_data data; + data.der0 = der[i-1].at1(); + data.der1 = der[i].at0(); + double t = der.cuts[i]; + std::vector< double > rts = roots (x - t); /// @todo this has multiple solutions for general strokewidth paths (generated by spiro interpolator...), ignore for now + if (!rts.empty()) { + data.width = y(rts.front()); + } else { + data.width = 1; + } + vect.push_back(data); + } + } + return vect; +} - Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); - Piecewise<D2<SBasis> > n = rot90(der); - offset_points.set_pwd2_normal(n); - // see if we should treat the path as being closed. - bool closed_path = false; - if ( are_near(pwd2_in.firstValue(), pwd2_in.lastValue()) ) { - closed_path = true; +Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::SBasis> > const & B, + std::vector<discontinuity_data> const & cusps, + LineCuspType cusp_linecap, + double tol=Geom::EPSILON) +{ +/* per definition, each discontinuity should be fixed with a cusp-ending, as defined by cusp_linecap_type +*/ + Geom::PathBuilder pb; + if (B.size() == 0) { + return pb.peek().front(); } - Piecewise<D2<SBasis> > output; - if (!closed_path) { - // perhaps use std::list instead of std::vector? - std::vector<Geom::Point> ts(offset_points.data().size() + 2); - // first and last point coincide with input path (for now at least) - ts.front() = Point(pwd2_in.domain().min(),0); - ts.back() = Point(pwd2_in.domain().max(),0); - for (unsigned int i = 0; i < offset_points.data().size(); ++i) { - ts.at(i+1) = offset_points.data().at(i); - } + unsigned int cusp_i = 0; + 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]; + + switch (cusp_linecap) { + case LINECUSP_ROUND: // properly bugged ^_^ + pb.arcTo( abs(cusp.width), abs(cusp.width), + 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_BEVEL: + default: + pb.lineTo(B[i].at0()); + break; + } - if (sort_points) { - sort(ts.begin(), ts.end(), compare_offsets); + cusp_i++; } + build_from_sbasis(pb, B[i], tol, false); + } + pb.finish(); + return pb.peek().front(); +} + - // create stroke path where points (x,y) := (t, offset) - Geom::Interpolate::CubicBezierJohan interpolator; - Path strokepath = interpolator.interpolateToPath(ts); - Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); +std::vector<Geom::Path> +LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in) +{ + using namespace Geom; - strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS); - strokepath.close(); + std::vector<Geom::Path> path_out; + if (path_in.size() == 0) { + return path_out; + } - D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); - Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); - Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + // for now, only regard first subpath and ignore the rest + Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb(); - output = compose(pwd2_in,x) + y*compose(n,x); - } else { - // path is closed + Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); + Piecewise<D2<SBasis> > n = rot90(der); + offset_points.set_pwd2(pwd2_in, n); - // perhaps use std::list instead of std::vector? - std::vector<Geom::Point> ts = offset_points.data(); - if (sort_points) { - sort(ts.begin(), ts.end(), compare_offsets); - } + std::vector<Geom::Point> ts = offset_points.data(); + if (sort_points) { + sort(ts.begin(), ts.end(), compare_offsets); + } + if (path_in[0].closed()) { // add extra points for interpolation between first and last point Point first_point = ts.front(); Point last_point = ts.back(); ts.insert(ts.begin(), last_point - Point(pwd2_in.domain().extent() ,0)); ts.push_back( first_point + Point(pwd2_in.domain().extent() ,0) ); - // create stroke path where points (x,y) := (t, offset) - Geom::Interpolate::CubicBezierJohan interpolator; - Path strokepath = interpolator.interpolateToPath(ts); - - // output 2 separate paths - D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); - Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); - Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); - // find time values for which x lies outside path domain - // and only take portion of x and y that lies within those time values - std::vector< double > rtsmin = roots (x - pwd2_in.domain().min()); - std::vector< double > rtsmax = roots (x - pwd2_in.domain().max()); - if ( !rtsmin.empty() && !rtsmax.empty() ) { - x = portion(x, rtsmin.at(0), rtsmax.at(0)); - y = portion(y, rtsmin.at(0), rtsmax.at(0)); + } else { + // first and last point have same distance from path as second and second to last points, respectively. + ts.insert(ts.begin(), Point(pwd2_in.domain().min(), ts.front()[Geom::Y]) ); + ts.push_back( Point(pwd2_in.domain().max(), ts.back()[Geom::Y]) ); + } + // 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)) { + johan->setBeta(interpolator_beta); + } + Geom::Path strokepath = interpolator->interpolateToPath(ts); + delete interpolator; + + D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); + Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); + Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + // find time values for which x lies outside path domain + // and only take portion of x and y that lies within those time values + std::vector< double > rtsmin = roots (x - pwd2_in.domain().min()); + std::vector< double > rtsmax = roots (x - pwd2_in.domain().max()); + if ( !rtsmin.empty() && !rtsmax.empty() ) { + x = portion(x, rtsmin.at(0), rtsmax.at(0)); + y = portion(y, rtsmin.at(0), rtsmax.at(0)); + } + + std::vector<discontinuity_data> cusps = find_discontinuities(der, x, y); + LineCuspType cusp_linecap = static_cast<LineCuspType>(cusp_linecap_type.get_value()); + + 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); + + if (path_in[0].closed()) { + fixed_path.close(true); + path_out.push_back(fixed_path); + fixed_mirrorpath.close(true); + path_out.push_back(fixed_mirrorpath); + } else { + // add linecaps... + LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value()); + LineCapType start_linecap = static_cast<LineCapType>(start_linecap_type.get_value()); + switch (end_linecap) { + case LINECAP_PEAK: + { + Geom::Point end_deriv = der.lastValue(); + double radius = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); + Geom::Point midpoint = 0.5*(pwd2_out.lastValue() + mirrorpath.firstValue()) + radius*end_deriv; + fixed_path.appendNew<LineSegment>(midpoint); + fixed_path.appendNew<LineSegment>(mirrorpath.firstValue()); + break; + } + case LINECAP_SQUARE: + { + Geom::Point end_deriv = der.lastValue(); + double radius = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); + fixed_path.appendNew<LineSegment>( pwd2_out.lastValue() + radius*end_deriv ); + fixed_path.appendNew<LineSegment>( mirrorpath.firstValue() + radius*end_deriv ); + fixed_path.appendNew<LineSegment>( mirrorpath.firstValue() ); + break; + } + case LINECAP_BUTT: + { + fixed_path.appendNew<LineSegment>( mirrorpath.firstValue() ); + break; + } + case LINECAP_ROUND: + default: + { + double radius1 = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); + fixed_path.appendNew<SVGEllipticalArc>( radius1, radius1, M_PI/2., false, y.lastValue() < 0, mirrorpath.firstValue() ); + break; + } } - output = compose(pwd2_in,x) + y*compose(n,x); - x = reverse(x); - y = reverse(y); - output.concat(compose(pwd2_in,x) - y*compose(n,x)); + + fixed_path.append(fixed_mirrorpath, Geom::Path::STITCH_DISCONTINUOUS); + + switch (start_linecap) { + case LINECAP_PEAK: + { + Geom::Point start_deriv = der.firstValue(); + double radius = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); + Geom::Point midpoint = 0.5*(mirrorpath.lastValue() + pwd2_out.firstValue()) - radius*start_deriv; + fixed_path.appendNew<LineSegment>( midpoint ); + fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() ); + break; + } + case LINECAP_SQUARE: + { + Geom::Point start_deriv = der.firstValue(); + double radius = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); + fixed_path.appendNew<LineSegment>( mirrorpath.lastValue() - radius*start_deriv ); + fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() - radius*start_deriv ); + fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() ); + break; + } + case LINECAP_BUTT: + { + fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() ); + break; + } + case LINECAP_ROUND: + default: + { + double radius2 = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); + fixed_path.appendNew<SVGEllipticalArc>( radius2, radius2, M_PI/2., false, y.firstValue() < 0, pwd2_out.firstValue() ); + break; + } + } + + fixed_path.close(true); + path_out.push_back(fixed_path); } - return output; + return path_out; } + /* ######################## */ } //namespace LivePathEffect diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index 667c94f53..4c9c6d327 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -2,9 +2,9 @@ * @brief PowerStroke LPE effect, see lpe-powerstroke.cpp. */ /* Authors: - * Johan Engelen <j.b.c.engelen@utwente.nl> + * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> * - * Copyright (C) 2010 Authors + * Copyright (C) 2010-2011 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -15,6 +15,7 @@ #include "live_effects/effect.h" #include "live_effects/parameter/bool.h" #include "live_effects/parameter/powerstrokepointarray.h" +#include "live_effects/parameter/enum.h" namespace Inkscape { namespace LivePathEffect { @@ -24,13 +25,21 @@ public: LPEPowerStroke(LivePathEffectObject *lpeobject); virtual ~LPEPowerStroke(); - virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + virtual std::vector<Geom::Path> doEffect_path (std::vector<Geom::Path> const & path_in); virtual void doOnApply(SPLPEItem *lpeitem); + // methods called by path-manipulator upon edits + void adjustForNewPath(std::vector<Geom::Path> const & path_in); + private: PowerStrokePointArrayParam offset_points; BoolParam sort_points; + EnumParam<unsigned> interpolator_type; + ScalarParam interpolator_beta; + EnumParam<unsigned> start_linecap_type; + EnumParam<unsigned> cusp_linecap_type; + EnumParam<unsigned> end_linecap_type; LPEPowerStroke(const LPEPowerStroke&); LPEPowerStroke& operator=(const LPEPowerStroke&); diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp index d78ad2fcb..ac8c112d6 100644 --- a/src/live_effects/lpe-recursiveskeleton.cpp +++ b/src/live_effects/lpe-recursiveskeleton.cpp @@ -1,7 +1,5 @@ -#define INKSCAPE_LPE_RECURSIVESKELETON_CPP -/** \file - * @brief - * +/** + * @file * Inspired by Hofstadter's 'Goedel Escher Bach', chapter V. */ /* Authors: diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index 055b63661..50f50d0ae 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -31,7 +31,6 @@ #include <2geom/affine.h> #include "ui/widget/scalar.h" -#include "libnr/nr-values.h" namespace Inkscape { namespace LivePathEffect { @@ -271,13 +270,13 @@ LPERoughHatches::LPERoughHatches(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&front_thickness) ); registerParameter( dynamic_cast<Parameter *>(&back_thickness) ); - //hatch_dist.param_set_range(0.1, NR_HUGE); - growth.param_set_range(0, NR_HUGE); + //hatch_dist.param_set_range(0.1, Geom::infinity()); + growth.param_set_range(0, Geom::infinity()); dist_rdm.param_set_range(0, 99.); - stroke_width_top.param_set_range(0, NR_HUGE); - stroke_width_bot.param_set_range(0, NR_HUGE); - front_thickness.param_set_range(0, NR_HUGE); - back_thickness.param_set_range(0, NR_HUGE); + stroke_width_top.param_set_range(0, Geom::infinity()); + stroke_width_bot.param_set_range(0, Geom::infinity()); + front_thickness.param_set_range(0, Geom::infinity()); + back_thickness.param_set_range(0, Geom::infinity()); // hide the widgets for direction and bender vectorparams direction.widget_is_visible = false; @@ -331,7 +330,7 @@ LPERoughHatches::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & std::vector<std::vector<Point> > snakePoints; snakePoints = linearSnake(transformed_pwd2_in, transformed_org); - if ( snakePoints.size() > 0 ){ + if (!snakePoints.empty()){ Piecewise<D2<SBasis> >smthSnake = smoothSnake(snakePoints); smthSnake = smthSnake*mat.inverse(); if (do_bend.get_value()){ @@ -557,7 +556,7 @@ LPERoughHatches::resetDefaults(SPItem * item) { Effect::resetDefaults(item); - Geom::OptRect bbox = item->getBounds(Geom::identity(), SPItem::GEOMETRIC_BBOX); + Geom::OptRect bbox = item->geometricBounds(); Geom::Point origin(0.,0.); Geom::Point vector(50.,0.); if (bbox) { diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp index e51b03d15..d7a393197 100644 --- a/src/live_effects/lpe-ruler.cpp +++ b/src/live_effects/lpe-ruler.cpp @@ -40,14 +40,14 @@ static const Util::EnumDataConverter<BorderMarkType> BorderMarkTypeConverter(Bor LPERuler::LPERuler(LivePathEffectObject *lpeobject) : Effect(lpeobject), - mark_distance(_("Mark distance:"), _("Distance between successive ruler marks"), "mark_distance", &wr, this, 20.0), + mark_distance(_("_Mark distance:"), _("Distance between successive ruler marks"), "mark_distance", &wr, this, 20.0), unit(_("Unit:"), _("Unit"), "unit", &wr, this), - mark_length(_("Major length:"), _("Length of major ruler marks"), "mark_length", &wr, this, 14.0), - minor_mark_length(_("Minor length:"), _("Length of minor ruler marks"), "minor_mark_length", &wr, this, 7.0), - major_mark_steps(_("Major steps:"), _("Draw a major mark every ... steps"), "major_mark_steps", &wr, this, 5), - shift(_("Shift marks by:"), _("Shift marks by this many steps"), "shift", &wr, this, 0), + mark_length(_("Ma_jor length:"), _("Length of major ruler marks"), "mark_length", &wr, this, 14.0), + minor_mark_length(_("Mino_r length:"), _("Length of minor ruler marks"), "minor_mark_length", &wr, this, 7.0), + major_mark_steps(_("Major steps_:"), _("Draw a major mark every ... steps"), "major_mark_steps", &wr, this, 5), + shift(_("Shift marks _by:"), _("Shift marks by this many steps"), "shift", &wr, this, 0), mark_dir(_("Mark direction:"), _("Direction of marks (when viewing along the path from start to end)"), "mark_dir", MarkDirTypeConverter, &wr, this, MARKDIR_LEFT), - offset(_("Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0), + offset(_("_Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0), border_marks(_("Border marks:"), _("Choose whether to draw marks at the beginning and end of the path"), "border_marks", BorderMarkTypeConverter, &wr, this, BORDERMARK_BOTH) { registerParameter(dynamic_cast<Parameter *>(&unit)); diff --git a/src/live_effects/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp index daf96aa13..08f31da7e 100644 --- a/src/live_effects/lpe-skeleton.cpp +++ b/src/live_effects/lpe-skeleton.cpp @@ -1,6 +1,6 @@ -#define INKSCAPE_LPE_SKELETON_CPP -/** \file - * @brief Minimal dummy LPE effect implementation, used as an example for a base +/** + * @file + * Minimal dummy LPE effect implementation, used as an example for a base * starting class when implementing new LivePathEffects. * * In vi, three global search-and-replaces will let you rename everything diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index 9488da84a..e39b82f20 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -1,5 +1,6 @@ -/** @file - * @brief LPE sketch effect implementation +/** + * @file + * LPE sketch effect implementation. */ /* Authors: * Jean-Francois Barraud <jf.barraud@gmail.com> @@ -89,24 +90,24 @@ LPESketch::LPESketch(LivePathEffectObject *lpeobject) : #endif nbiter_approxstrokes.param_make_integer(); - nbiter_approxstrokes.param_set_range(0, NR_HUGE); - strokelength.param_set_range(1, NR_HUGE); + nbiter_approxstrokes.param_set_range(0, Geom::infinity()); + strokelength.param_set_range(1, Geom::infinity()); strokelength.param_set_increments(1., 5.); strokelength_rdm.param_set_range(0, 1.); strokeoverlap.param_set_range(0, 1.); strokeoverlap.param_set_increments(0.1, 0.30); ends_tolerance.param_set_range(0., 1.); - parallel_offset.param_set_range(0, NR_HUGE); + parallel_offset.param_set_range(0, Geom::infinity()); tremble_frequency.param_set_range(0.01, 100.); tremble_frequency.param_set_increments(.5, 1.5); strokeoverlap_rdm.param_set_range(0, 1.); #ifdef LPE_SKETCH_USE_CONSTRUCTION_LINES nbtangents.param_make_integer(); - nbtangents.param_set_range(0, NR_HUGE); - tgtscale.param_set_range(0, NR_HUGE); + nbtangents.param_set_range(0, Geom::infinity()); + tgtscale.param_set_range(0, Geom::infinity()); tgtscale.param_set_increments(.1, .5); - tgtlength.param_set_range(0, NR_HUGE); + tgtlength.param_set_range(0, Geom::infinity()); tgtlength.param_set_increments(1., 5.); tgtlength_rdm.param_set_range(0, 1.); tgt_places_rdmness.param_set_range(0, 1.); @@ -271,7 +272,7 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ } } times = roots(piecelength-s1); - if (times.size()==0) break;//we should not be there. + if (times.empty()) break;//we should not be there. t1 = times[0]; //pick a rdm perturbation, and collect the perturbed piece into output. diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp index 54554ebb2..22974fe13 100644 --- a/src/live_effects/lpe-spiro.cpp +++ b/src/live_effects/lpe-spiro.cpp @@ -12,7 +12,6 @@ #include <2geom/affine.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> -#include <2geom/isnan.h> #include "helper/geom-nodetype.h" #include "helper/geom-curves.h" diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 56d66d137..953c2d443 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -43,16 +43,16 @@ VonKochRefPathParam::param_readSVGValue(const gchar * strvalue) LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : Effect(lpeobject), - nbgenerations(_("Nb of generations:"), _("Depth of the recursion --- keep low!!"), "nbgenerations", &wr, this, 1), + nbgenerations(_("N_r of generations:"), _("Depth of the recursion --- keep low!!"), "nbgenerations", &wr, this, 1), 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), - drawall(_("Draw all generations"), _("If unchecked, draw only the last generation"), "drawall", &wr, this, true), + 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), + drawall(_("Dra_w all generations"), _("If unchecked, draw only the last generation"), "drawall", &wr, this, true), //,draw_boxes(_("Display boxes"), _("Display boxes instead of paths only"), "draw_boxes", &wr, this, true) ref_path(_("Reference segment:"), _("The reference segment. Defaults to the horizontal midline of the bbox."), "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), //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) + maxComplexity(_("_Max complexity:"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000) { //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug. registerParameter( dynamic_cast<Parameter *>(&ref_path) ); @@ -66,9 +66,9 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) ); nbgenerations.param_make_integer(); - nbgenerations.param_set_range(0, NR_HUGE); + nbgenerations.param_set_range(0, Geom::infinity()); maxComplexity.param_make_integer(); - maxComplexity.param_set_range(0, NR_HUGE); + maxComplexity.param_set_range(0, Geom::infinity()); } LPEVonKoch::~LPEVonKoch() @@ -83,7 +83,7 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in) std::vector<Geom::Path> generating_path = generator.get_pathvector(); - if (generating_path.size()==0) { + if (generating_path.empty()) { return path_in; } @@ -124,7 +124,7 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in) } } - if (transforms.size()==0){ + if (transforms.empty()){ return path_in; } @@ -247,7 +247,7 @@ LPEVonKoch::doBeforeEffect (SPLPEItem *lpeitem) std::vector<Geom::Path> paths = ref_path.get_pathvector(); Geom::Point A,B; - if (paths.size()==0||paths.front().size()==0){ + if (paths.empty()||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()) ); diff --git a/src/live_effects/lpegroupbbox.cpp b/src/live_effects/lpegroupbbox.cpp index 2678509a4..e2378265a 100644 --- a/src/live_effects/lpegroupbbox.cpp +++ b/src/live_effects/lpegroupbbox.cpp @@ -13,30 +13,27 @@ namespace Inkscape { namespace LivePathEffect { /** - * \brief Updates the \c boundingbox_X and \c boundingbox_Y values from the geometric bounding box of \c lpeitem. + * Updates the \c boundingbox_X and \c boundingbox_Y values from the geometric bounding box of \c lpeitem. * - * \pre lpeitem must have an existing geometric boundingbox (usually this is guaranteed when: \code SP_SHAPE(lpeitem)->curve != NULL \endcode ) - It's not possible to run LPEs on items without their original-d having a bbox. - * \param lpeitem This is not allowed to be NULL. - * \param absolute Determines whether the bbox should be calculated of the untransformed lpeitem (\c absolute = \c false) + * @pre lpeitem must have an existing geometric boundingbox (usually this is guaranteed when: \code SP_SHAPE(lpeitem)->curve != NULL \endcode ) + * It's not possible to run LPEs on items without their original-d having a bbox. + * @param lpeitem This is not allowed to be NULL. + * @param absolute Determines whether the bbox should be calculated of the untransformed lpeitem (\c absolute = \c false) * or of the transformed lpeitem (\c absolute = \c true) using sp_item_i2doc_affine. - * \post Updated values of boundingbox_X and boundingbox_Y. These intervals are set to empty intervals when the precondition is not met. + * @post Updated values of boundingbox_X and boundingbox_Y. These intervals are set to empty intervals when the precondition is not met. */ -void -GroupBBoxEffect::original_bbox(SPLPEItem *lpeitem, bool absolute) +void GroupBBoxEffect::original_bbox(SPLPEItem *lpeitem, bool absolute) { // Get item bounding box - SPItem* item = SP_ITEM(lpeitem); - Geom::Affine transform; if (absolute) { - transform = item->i2doc_affine(); + transform = lpeitem->i2doc_affine(); } else { transform = Geom::identity(); } - Geom::OptRect bbox = item->getBounds(transform, SPItem::GEOMETRIC_BBOX); + Geom::OptRect bbox = lpeitem->geometricBounds(transform); if (bbox) { boundingbox_X = (*bbox)[Geom::X]; boundingbox_Y = (*bbox)[Geom::Y]; diff --git a/src/live_effects/lpeobject-reference.h b/src/live_effects/lpeobject-reference.h index 8d2b406eb..571c3b1f1 100644 --- a/src/live_effects/lpeobject-reference.h +++ b/src/live_effects/lpeobject-reference.h @@ -9,7 +9,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information. */ -#include <forward.h> #include <uri-references.h> #include <stddef.h> #include <sigc++/sigc++.h> diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp index 1b5ed1d49..3e4e40198 100644 --- a/src/live_effects/lpeobject.cpp +++ b/src/live_effects/lpeobject.cpp @@ -253,7 +253,7 @@ LivePathEffectObject *LivePathEffectObject::fork_private_if_necessary(unsigned i Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *dup_repr = this->getRepr()->duplicate(xml_doc); - SP_DOCUMENT_DEFS(doc)->getRepr()->addChild(dup_repr, NULL); + doc->getDefs()->getRepr()->addChild(dup_repr, NULL); LivePathEffectObject *lpeobj_new = LIVEPATHEFFECT( doc->getObjectByRepr(dup_repr) ); Inkscape::GC::release(dup_repr); diff --git a/src/live_effects/parameter/CMakeLists.txt b/src/live_effects/parameter/CMakeLists.txt deleted file mode 100644 index 8657b2bec..000000000 --- a/src/live_effects/parameter/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -SET(live_effects_parameter_SRC -array.cpp -bool.cpp -parameter.cpp -path.cpp -path-reference.cpp -point.cpp -powerstrokepointarray.cpp -random.cpp -text.cpp -unit.cpp -vector.cpp -) diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index 89c344594..45db19e7f 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -11,7 +11,7 @@ #include <vector> -#include <glib/gtypes.h> +#include <glib.h> #include <gtkmm/tooltips.h> diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index 8f5196dad..851476f13 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include "live_effects/parameter/parameter.h" diff --git a/src/live_effects/parameter/enum.h b/src/live_effects/parameter/enum.h index 05f3bdd57..2d2268ea9 100644 --- a/src/live_effects/parameter/enum.h +++ b/src/live_effects/parameter/enum.h @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include "ui/widget/registered-enums.h" #include <gtkmm/tooltips.h> diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 57d583ba6..cc8982860 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -9,7 +9,6 @@ #include "live_effects/parameter/parameter.h" #include "live_effects/effect.h" #include "svg/svg.h" -#include "libnr/nr-values.h" #include "xml/repr.h" #include <gtkmm.h> #include "ui/widget/registered-widget.h" @@ -53,13 +52,14 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, gdouble default_value) : Parameter(label, tip, key, wr, effect), value(default_value), - min(-NR_HUGE), - max(NR_HUGE), + min(-Geom::infinity()), + max(Geom::infinity()), integer(false), defvalue(default_value), digits(2), inc_step(0.1), - inc_page(1) + inc_page(1), + add_slider(false) { } @@ -135,6 +135,9 @@ ScalarParam::param_newWidget(Gtk::Tooltips * /*tooltips*/) rsu->setIncrements(inc_step, inc_page); rsu->setRange(min, max); rsu->setProgrammatically = false; + if (add_slider) { + rsu->addSlider(); + } rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index cee10bc70..92c2c8b41 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -15,8 +15,8 @@ class KnotHolder; class SPLPEItem; -struct SPDesktop; -struct SPItem; +class SPDesktop; +class SPItem; namespace Gtk { class Widget; @@ -109,6 +109,8 @@ public: void param_set_digits(unsigned digits); void param_set_increments(double step, double page); + void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; }; + virtual Gtk::Widget * param_newWidget(Gtk::Tooltips * tooltips); inline operator gdouble() @@ -123,6 +125,7 @@ protected: unsigned digits; double inc_step; double inc_page; + bool add_slider; private: ScalarParam(const ScalarParam&); diff --git a/src/live_effects/parameter/path-reference.h b/src/live_effects/parameter/path-reference.h index 26fce952a..d24f05a4f 100644 --- a/src/live_effects/parameter/path-reference.h +++ b/src/live_effects/parameter/path-reference.h @@ -10,7 +10,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information. */ -#include <forward.h> #include "sp-item.h" #include <uri-references.h> #include <stddef.h> diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index d652dfd0c..32da0a426 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -15,7 +15,7 @@ #include "ui/widget/point.h" #include "widgets/icon.h" -#include <gtk/gtkstock.h> +#include <gtk/gtk.h> #include "selection-chemistry.h" #include "xml/repr.h" #include "desktop.h" @@ -208,7 +208,7 @@ PathParam::param_editOncanvas(SPItem *item, SPDesktop * dt) ShapeRecord r; r.role = SHAPE_ROLE_LPE_PARAM; - r.edit_transform = item->i2d_affine(); // TODO is it right? + r.edit_transform = item->i2dt_affine(); // TODO is it right? if (!href) { r.item = reinterpret_cast<SPItem*>(param_effect->getLPEObj()); r.lpe_key = param_key; diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index 8c4de7cff..0a35014ab 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include <2geom/path.h> #include <gtkmm/tooltips.h> diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index 2d4e942c0..9ea06bce8 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include <2geom/point.h> #include <gtkmm/tooltips.h> diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index 9d43e8447..fccbad7e5 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -70,13 +70,48 @@ PowerStrokePointArrayParam::param_newWidget(Gtk::Tooltips * /*tooltips*/) } -void -PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) +void PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) { // param_set_and_write_new_value( (*this) * postmul ); } +/** call this method to recalculate the controlpoints such that they stay at the same location relative to the new path. Useful after adding/deleting nodes to the path.*/ +void +PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +{ + if (!last_pwd2.empty()) { + if (last_pwd2.size() > pwd2_in.size()) { + // Path has become shorter: rescale offsets + double factor = (double)pwd2_in.size() / (double)last_pwd2.size(); + for (unsigned int i = 0; i < _vector.size(); ++i) { + _vector[i][Geom::X] *= factor; + } + } else if (last_pwd2.size() < pwd2_in.size()) { + // Path has become longer: probably node added, maintain position of knots + Geom::Piecewise<Geom::D2<Geom::SBasis> > normal = rot90(unitVector(derivative(pwd2_in))); + for (unsigned int i = 0; i < _vector.size(); ++i) { + Geom::Point pt = _vector[i]; + Geom::Point position = last_pwd2.valueAt(pt[Geom::X]) + pt[Geom::Y] * last_pwd2_normal.valueAt(pt[Geom::X]); + + double t = nearest_point(position, pwd2_in); + double offset = dot(position - pwd2_in.valueAt(t), normal.valueAt(t)); + _vector[i] = Geom::Point(t, offset); + } + } + + write_to_SVG(); + } +} + +void +PowerStrokePointArrayParam::set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in) +{ + last_pwd2 = pwd2_in; + last_pwd2_normal = pwd2_normal_in; +} + + void PowerStrokePointArrayParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) { @@ -94,6 +129,11 @@ public: virtual Geom::Point knot_get(); virtual void knot_click(guint state); + /** Checks whether the index falls within the size of the parameter's vector */ + bool valid_index(unsigned int index) { + return (_pparam->_vector.size() > index); + }; + private: PowerStrokePointArrayParam *_pparam; unsigned int _index; @@ -108,8 +148,13 @@ PowerStrokePointArrayParamKnotHolderEntity::PowerStrokePointArrayParamKnotHolder void PowerStrokePointArrayParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/) { -/// @todo how about item transforms??? using namespace Geom; + + if (!valid_index(_index)) { + return; + } + + /// @todo how about item transforms??? Piecewise<D2<SBasis> > const & pwd2 = _pparam->get_pwd2(); Piecewise<D2<SBasis> > const & n = _pparam->get_pwd2_normal(); @@ -124,6 +169,11 @@ Geom::Point PowerStrokePointArrayParamKnotHolderEntity::knot_get() { using namespace Geom; + + if (!valid_index(_index)) { + return Geom::Point(infinity(), infinity()); + } + Piecewise<D2<SBasis> > const & pwd2 = _pparam->get_pwd2(); Piecewise<D2<SBasis> > const & n = _pparam->get_pwd2_normal(); @@ -136,15 +186,22 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_get() void PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state) { - g_print ("This is the %d handle associated to parameter '%s'\n", _index, _pparam->param_key.c_str()); +//g_print ("This is the %d handle associated to parameter '%s'\n", _index, _pparam->param_key.c_str()); if (state & GDK_CONTROL_MASK) { - std::vector<Geom::Point> & vec = _pparam->_vector; - vec.insert(vec.begin() + _index, 1, vec.at(_index)); - _pparam->param_set_and_write_new_value(vec); - g_print ("Added handle %d associated to parameter '%s'\n", _index, _pparam->param_key.c_str()); - /// @todo this BUGS ! the knot stuff should be reloaded when adding a new node! - } + if (state & GDK_MOD1_MASK) { + // delete the clicked knot + std::vector<Geom::Point> & vec = _pparam->_vector; + vec.erase(vec.begin() + _index); + _pparam->param_set_and_write_new_value(vec); + } else { + // add a knot + std::vector<Geom::Point> & vec = _pparam->_vector; + vec.insert(vec.begin() + _index, 1, vec.at(_index)); + _pparam->param_set_and_write_new_value(vec); + } + } + } void diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index d984a7de5..b00e69e76 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include <2geom/point.h> #include <gtkmm/tooltips.h> @@ -43,11 +43,12 @@ public: virtual bool providesKnotHolderEntities() { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); - void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { last_pwd2 = pwd2_in; } + void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in); Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2() { return last_pwd2; } - void set_pwd2_normal(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { last_pwd2_normal = pwd2_in; } Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2_normal() { return last_pwd2_normal; } + void recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + friend class PowerStrokePointArrayParamKnotHolderEntity; private: diff --git a/src/live_effects/parameter/random.cpp b/src/live_effects/parameter/random.cpp index 889e5375b..d5a6e9291 100644 --- a/src/live_effects/parameter/random.cpp +++ b/src/live_effects/parameter/random.cpp @@ -9,7 +9,6 @@ #include "live_effects/parameter/random.h" #include "live_effects/effect.h" #include "svg/svg.h" -#include "libnr/nr-values.h" #include "ui/widget/registered-widget.h" #include <gtkmm.h> #include "ui/widget/random.h" @@ -32,8 +31,8 @@ RandomParam::RandomParam( const Glib::ustring& label, const Glib::ustring& tip, { defvalue = default_value; value = defvalue; - min = -NR_HUGE; - max = NR_HUGE; + min = -Geom::infinity(); + max = Geom::infinity(); integer = false; defseed = default_seed; diff --git a/src/live_effects/parameter/text.h b/src/live_effects/parameter/text.h index 8539a8046..82654303b 100644 --- a/src/live_effects/parameter/text.h +++ b/src/live_effects/parameter/text.h @@ -13,7 +13,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include "display/canvas-bpath.h" #include "live_effects/parameter/parameter.h" diff --git a/src/live_effects/parameter/vector.cpp b/src/live_effects/parameter/vector.cpp index 9086ab376..6d0824ae0 100644 --- a/src/live_effects/parameter/vector.cpp +++ b/src/live_effects/parameter/vector.cpp @@ -53,9 +53,12 @@ bool VectorParam::param_readSVGValue(const gchar * strvalue) { gchar ** strarray = g_strsplit(strvalue, ",", 4); + if (!strarray) { + return false; + } double val[4]; unsigned int i = 0; - while (strarray[i] && i < 4) { + while (i < 4 && strarray[i]) { if (sp_svg_number_read_d(strarray[i], &val[i]) != 0) { i++; } else { diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h index cb7094b7f..8afc05699 100644 --- a/src/live_effects/parameter/vector.h +++ b/src/live_effects/parameter/vector.h @@ -9,7 +9,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib/gtypes.h> +#include <glib.h> #include <2geom/point.h> #include <gtkmm/tooltips.h> diff --git a/src/live_effects/spiro.cpp b/src/live_effects/spiro.cpp index abc9c94ca..b98e12213 100644 --- a/src/live_effects/spiro.cpp +++ b/src/live_effects/spiro.cpp @@ -631,8 +631,6 @@ add_mat_line(bandmat *m, double *v, double derivs[4], double x, double y, int j, int jj, int jinc, int nmat) { - int k; - if (jj >= 0) { int joff = (j + 5 - jj + nmat) % nmat; if (nmat < 6) { @@ -644,7 +642,7 @@ add_mat_line(bandmat *m, double *v, printf("add_mat_line j=%d jj=%d jinc=%d nmat=%d joff=%d\n", j, jj, jinc, nmat, joff); #endif v[jj] += x; - for (k = 0; k < jinc; k++) + for (int k = 0; k < jinc; k++) m[jj].a[joff + k] += y * derivs[k]; } } @@ -831,9 +829,6 @@ spiro_seg_to_bpath(const double ks[4], double xy[2]; double ch, th; double scale, rot; - double th_even, th_odd; - double ul, vl; - double ur, vr; integrate_spiro(ks, xy); ch = hypot(xy[0], xy[1]); @@ -841,6 +836,9 @@ spiro_seg_to_bpath(const double ks[4], scale = seg_ch / ch; rot = seg_th - th; if (depth > 5 || bend < 1.) { + double ul, vl; + double ur, vr; + double th_even, th_odd; th_even = (1./384) * ks[3] + (1./8) * ks[1] + rot; th_odd = (1./48) * ks[2] + .5 * ks[0]; ul = (scale * (1./3)) * cos(th_even - th_odd); @@ -944,7 +942,6 @@ test_integ(void) { double ks[] = {1, 2, 3, 4}; double xy[2]; double xynom[2]; - double ch, th; int i, j; int nsubdiv; @@ -963,9 +960,10 @@ test_integ(void) { en = get_time(); err = hypot(xy[0] - xynom[0], xy[1] - xynom[1]); printf("%d %d %g %g\n", ORDER, n, (en - st) / n_iter, err); +#if 0 + double ch, th; ch = hypot(xy[0], xy[1]); th = atan2(xy[1], xy[0]); -#if 0 printf("n = %d: integ(%g %g %g %g) = %g %g, ch = %g, th = %g\n", n, ks[0], ks[1], ks[2], ks[3], xy[0], xy[1], ch, th); printf("%d: %g %g\n", n, xy[0] - xynom[0], xy[1] - xynom[1]); @@ -988,9 +986,6 @@ print_seg(const double ks[4], double x0, double y0, double x1, double y1) double xy[2]; double ch, th; double scale, rot; - double th_even, th_odd; - double ul, vl; - double ur, vr; integrate_spiro(ks, xy); ch = hypot(xy[0], xy[1]); @@ -998,6 +993,9 @@ print_seg(const double ks[4], double x0, double y0, double x1, double y1) scale = seg_ch / ch; rot = seg_th - th; if (bend < 1.) { + double th_even, th_odd; + double ul, vl; + double ur, vr; th_even = (1./384) * ks[3] + (1./8) * ks[1] + rot; th_odd = (1./48) * ks[2] + .5 * ks[0]; ul = (scale * (1./3)) * cos(th_even - th_odd); |
