diff options
| author | Richard White <rwhite8282@gmail.com> | 2016-05-19 01:17:29 +0000 |
|---|---|---|
| committer | Richard White <rwhite8282@gmail.com> | 2016-05-19 01:17:29 +0000 |
| commit | 1fe9c2603c33fddcd9f2688b30e843f91e1a86fa (patch) | |
| tree | 13289cbe033a46a40eb829437e115b5393e2ca84 /src/live_effects | |
| parent | Corrected frame extension stroke and fill values on 64 bit machine. (diff) | |
| parent | GTK3: Another widget named. (diff) | |
| download | inkscape-1fe9c2603c33fddcd9f2688b30e843f91e1a86fa.tar.gz inkscape-1fe9c2603c33fddcd9f2688b30e843f91e1a86fa.zip | |
Merge from Inkscape trunk.
(bzr r14668.1.3)
Diffstat (limited to 'src/live_effects')
25 files changed, 677 insertions, 147 deletions
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index fe7bf3a97..732c67304 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -104,16 +104,15 @@ const Util::EnumData<EffectType> LPETypeData[] = { {EXTRUDE, N_("Extrude"), "extrude"}, {LATTICE, N_("Lattice Deformation"), "lattice"}, {LINE_SEGMENT, N_("Line Segment"), "line_segment"}, - {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, {OFFSET, N_("Offset"), "offset"}, {PARALLEL, N_("Parallel"), "parallel"}, {PATH_LENGTH, N_("Path length"), "path_length"}, {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, - {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, + {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, #endif /* 0.46 */ {BEND_PATH, N_("Bend"), "bend_path"}, @@ -133,25 +132,25 @@ const Util::EnumData<EffectType> LPETypeData[] = { /* 0.91 */ {POWERSTROKE, N_("Power stroke"), "powerstroke"}, {CLONE_ORIGINAL, N_("Clone original path"), "clone_original"}, -/* EXPERIMENTAL */ +/* 0.92 */ + {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, + {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, + {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, + {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, {SHOW_HANDLES, N_("Show handles"), "show_handles"}, {ROUGHEN, N_("Roughen"), "roughen"}, {BSPLINE, N_("BSpline"), "bspline"}, {JOIN_TYPE, N_("Join type"), "join_type"}, {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, -/* Ponyscape */ + {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, + {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, +/* Ponyscape -> Inkscape 0.92*/ {ATTACH_PATH, N_("Attach path"), "attach_path"}, {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, -/* 0.91 */ - {SIMPLIFY, N_("Simplify"), "simplify"}, - {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, - {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, - {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, - {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -356,7 +355,8 @@ Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item) } Effect::Effect(LivePathEffectObject *lpeobject) - : _provides_knotholder_entities(false), + : apply_to_clippath_and_mask(false), + _provides_knotholder_entities(false), oncanvasedit_it(0), is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true), show_orig_path(false), @@ -467,6 +467,10 @@ void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) pathvector_before_effect = sp_curve->get_pathvector(); } doBeforeEffect(lpeitem); + if (apply_to_clippath_and_mask && SP_IS_GROUP(sp_lpe_item)) { + sp_lpe_item->apply_to_clippath(sp_lpe_item); + sp_lpe_item->apply_to_mask(sp_lpe_item); + } } /** diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index ea57ff243..898e089b7 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -121,6 +121,7 @@ public: inline bool isVisible() const { return is_visible; } void editNextParamOncanvas(SPItem * item, SPDesktop * desktop); + bool apply_to_clippath_and_mask; protected: Effect(LivePathEffectObject *lpeobject); @@ -144,6 +145,7 @@ protected: std::vector<Parameter *> param_vector; bool _provides_knotholder_entities; + int oncanvasedit_it; BoolParam is_visible; diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp index d7c0b69a4..bc112285f 100644 --- a/src/live_effects/lpe-bendpath.cpp +++ b/src/live_effects/lpe-bendpath.cpp @@ -81,6 +81,7 @@ LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) : prop_scale.param_set_increments(0.01, 0.10); _provides_knotholder_entities = true; + apply_to_clippath_and_mask = true; concatenate_before_pwd2 = true; } @@ -95,10 +96,6 @@ LPEBendPath::doBeforeEffect (SPLPEItem const* lpeitem) // get the item bounding box original_bbox(lpeitem); original_height = boundingbox_Y.max() - boundingbox_Y.min(); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - - item->apply_to_clippath(item); - item->apply_to_mask(item); } Geom::Piecewise<Geom::D2<Geom::SBasis> > diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 87d8f05a9..efea76039 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -5,7 +5,7 @@ * Authors: * Maximilian Albert <maximilian.albert@gmail.com> * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> - * + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> * Copyright (C) Authors 2007-2012 * * Released under GNU GPL, read the file 'COPYING' for more information @@ -13,7 +13,8 @@ #include <glibmm/i18n.h> #include <gdk/gdk.h> - +#include <2geom/path-intersection.h> +#include <2geom/sbasis-to-bezier.h> #include "live_effects/lpe-copy_rotate.h" #include <2geom/path.h> #include <2geom/transforms.h> @@ -41,34 +42,45 @@ public: virtual Geom::Point knot_get() const; }; -class KnotHolderEntityOrigin : public LPEKnotHolderEntity { -public: - KnotHolderEntityOrigin(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; - } // namespace CR +bool +pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) +{ + //http://totologic.blogspot.com.es/2014/01/accurate-point-in-triangle-test.html + using Geom::X; + using Geom::Y; + double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]); + double t1 = (p[X]*(p3[Y] - p1[Y]) + p[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator; + double t2 = (p[X]*(p2[Y] - p1[Y]) + p[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator; + double s = t1 + t2; + + return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && s <= 1; +} + + LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : Effect(lpeobject), origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"), starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), - rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0), - num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 5), - copiesTo360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copiesTo360", &wr, this, true), + rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0), + num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 6), + copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true), + fuse_paths(_("Fuse paths"), _("Fuse paths by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false), dist_angle_handle(100.0) { show_orig_path = true; _provides_knotholder_entities = true; + apply_to_clippath_and_mask = true; // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter(&copiesTo360); + registerParameter(&copies_to_360); + registerParameter(&fuse_paths); registerParameter(&starting_angle); registerParameter(&rotation_angle); registerParameter(&num_copies); registerParameter(&origin); - + num_copies.param_make_integer(true); num_copies.param_set_range(0, 1000); } @@ -92,15 +104,46 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) dir = unit_vector(B - A); } +void +LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set) +{ + if(fuse_paths) { + Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0])); + angle += starting_angle; + starting_angle.param_set_value(angle); + } + // 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) { + Parameter * param = *it; + param->param_transform_multiply(postmul, set); + } +} void LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); - if(copiesTo360 ){ + if (copies_to_360) { rotation_angle.param_set_value(360.0/(double)num_copies); - } + } + if (fuse_paths && rotation_angle * num_copies > 360 && rotation_angle > 0) { + num_copies.param_set_value(floor(360/rotation_angle)); + } + if (fuse_paths && copies_to_360) { + num_copies.param_set_increments(2,2); + if ((int)num_copies%2 !=0) { + num_copies.param_set_value(num_copies+1); + rotation_angle.param_set_value(360.0/(double)num_copies); + } + } else { + num_copies.param_set_increments(1,1); + } + + if (dist_angle_handle < 1.0) { + dist_angle_handle = 1.0; + } A = Point(boundingbox_X.min(), boundingbox_Y.middle()); B = Point(boundingbox_X.middle(), boundingbox_Y.middle()); dir = unit_vector(B - A); @@ -108,31 +151,251 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) // likely due to SVG's choice of coordinate system orientation (max) start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle; rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle; - if(copiesTo360 ){ + if ( fuse_paths || copies_to_360 ) { rot_pos = origin; } SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); item->apply_to_clippath(item); item->apply_to_mask(item); +} +void +LPECopyRotate::split(Geom::PathVector &path_on, Geom::Path const ÷r) +{ + Geom::PathVector tmp_path; + double time_start = 0.0; + Geom::Path original = path_on[0]; + int position = 0; + Geom::Crossings cs = crossings(original,divider); + std::vector<double> crossed; + for(unsigned int i = 0; i < cs.size(); i++) { + crossed.push_back(cs[i].ta); + } + std::sort(crossed.begin(), crossed.end()); + for (unsigned int i = 0; i < crossed.size(); i++) { + double time_end = crossed[i]; + if (time_start == time_end || time_end - time_start < Geom::EPSILON) { + continue; + } + Geom::Path portion_original = original.portion(time_start,time_end); + if (!portion_original.empty()) { + Geom::Point side_checker = portion_original.pointAt(0.0001); + position = Geom::sgn(Geom::cross(divider[1].finalPoint() - divider[0].finalPoint(), side_checker - divider[0].finalPoint())); + if (rotation_angle != 180) { + position = pointInTriangle(side_checker, divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint()); + } + if (position == 1) { + tmp_path.push_back(portion_original); + } + portion_original.clear(); + time_start = time_end; + } + } + position = Geom::sgn(Geom::cross(divider[1].finalPoint() - divider[0].finalPoint(), original.finalPoint() - divider[0].finalPoint())); + if (rotation_angle != 180) { + position = pointInTriangle(original.finalPoint(), divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint()); + } + if (cs.size() > 0 && position == 1) { + Geom::Path portion_original = original.portion(time_start, original.size()); + if(!portion_original.empty()){ + if (!original.closed()) { + tmp_path.push_back(portion_original); + } else { + if (tmp_path.size() > 0 && tmp_path[0].size() > 0 ) { + portion_original.setFinal(tmp_path[0].initialPoint()); + portion_original.append(tmp_path[0]); + tmp_path[0] = portion_original; + } else { + tmp_path.push_back(portion_original); + } + } + portion_original.clear(); + } + } + if (cs.size()==0 && position == 1) { + tmp_path.push_back(original); + } + path_on = tmp_path; } +void +LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double size_divider) +{ + split(path_on,divider); + Geom::PathVector tmp_path; + Geom::Affine pre = Geom::Translate(-origin); + for (Geom::PathVector::const_iterator path_it = path_on.begin(); path_it != path_on.end(); ++path_it) { + Geom::Path original = *path_it; + if (path_it->empty()) { + continue; + } + Geom::PathVector tmp_path_helper; + Geom::Path append_path = original; + + for (int i = 0; i < num_copies; ++i) { + Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i))); + Geom::Affine m = pre * rot * Geom::Translate(origin); + if (i%2 != 0) { + Geom::Point A = (Geom::Point)origin; + Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; + Geom::Translate m1(A[0], A[1]); + double hyp = Geom::distance(A, B); + double c = (B[0] - A[0]) / hyp; // cos(alpha) + double s = (B[1] - A[1]) / hyp; // sin(alpha) + + Geom::Affine m2(c, -s, s, c, 0.0, 0.0); + Geom::Scale sca(1.0, -1.0); + + Geom::Affine tmp_m = m1.inverse() * m2; + m = tmp_m; + m = m * sca; + m = m * m2.inverse(); + m = m * m1; + } else { + append_path = original; + } + append_path *= m; + if (tmp_path_helper.size() > 0) { + if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) { + Geom::Path tmp_append = append_path.reversed(); + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.initialPoint())) { + Geom::Path tmp_append = append_path; + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.initialPoint())) { + Geom::Path tmp_append = append_path; + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.finalPoint())) { + Geom::Path tmp_append = append_path.reversed(); + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[0].finalPoint(), append_path.finalPoint())) { + Geom::Path tmp_append = append_path.reversed(); + tmp_append.setInitial(tmp_path_helper[0].finalPoint()); + tmp_path_helper[0].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[0].initialPoint(), append_path.initialPoint())) { + Geom::Path tmp_append = append_path; + tmp_path_helper[0] = tmp_path_helper[0].reversed(); + tmp_append.setInitial(tmp_path_helper[0].finalPoint()); + tmp_path_helper[0].append(tmp_append); + } else { + tmp_path_helper.push_back(append_path); + } + if ( Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),tmp_path_helper[tmp_path_helper.size()-1].initialPoint())) { + tmp_path_helper[tmp_path_helper.size()-1].close(); + } + } else { + tmp_path_helper.push_back(append_path); + } + } + if (tmp_path_helper.size() > 0) { + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1]; + tmp_path_helper[0] = tmp_path_helper[0]; + if (rotation_angle * num_copies != 360) { + Geom::Ray base_a(divider.pointAt(1),divider.pointAt(0)); + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); + Geom::Point base_point = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle * num_copies) + starting_angle)) * size_divider; + Geom::Ray base_b(divider.pointAt(1), base_point); + if (Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) && + Geom::are_near(tmp_path_helper[0].finalPoint(),base_a)) + { + tmp_path_helper[0].close(); + if (tmp_path_helper.size() > 1) { + tmp_path_helper[tmp_path_helper.size()-1].close(); + } + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(),base_b) && + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) + { + tmp_path_helper[0].close(); + if (tmp_path_helper.size() > 1) { + tmp_path_helper[tmp_path_helper.size()-1].close(); + } + } else if ((Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) && + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) || + (Geom::are_near(tmp_path_helper[0].initialPoint(),base_b) && + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_a))) + { + Geom::Path close_path = Geom::Path(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + close_path.appendNew<Geom::LineSegment>((Geom::Point)origin); + close_path.appendNew<Geom::LineSegment>(tmp_path_helper[0].initialPoint()); + tmp_path_helper[0].append(close_path); + } + } + + if (Geom::are_near(tmp_path_helper[0].finalPoint(),tmp_path_helper[0].initialPoint())) { + tmp_path_helper[0].close(); + } + } + tmp_path.insert(tmp_path.end(), tmp_path_helper.begin(), tmp_path_helper.end()); + tmp_path_helper.clear(); + } + path_on = tmp_path; + tmp_path.clear(); +} Geom::Piecewise<Geom::D2<Geom::SBasis> > LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { using namespace Geom; - if(num_copies == 1){ + if (num_copies == 1 && !fuse_paths) { return pwd2_in; } + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); + Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider; + Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider; + //Note:: beter way to do this + //Whith AppendNew have problems whith the crossing order + Geom::Path divider = Geom::Path(line_start); + divider.appendNew<Geom::LineSegment>((Geom::Point)origin); + divider.appendNew<Geom::LineSegment>(line_end); Piecewise<D2<SBasis> > output; Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle)); - for (int i = 0; i < num_copies; ++i) { - Rotate rot(-rad_from_deg(rotation_angle * i)); - Affine t = pre * rot * Translate(origin); - output.concat(pwd2_in * t); + if (fuse_paths) { + Geom::PathVector path_out; + Geom::PathVector tmp_path; + PathVector const original_pathv = path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + if (path_it->empty()) { + continue; + } + bool end_open = false; + if (path_it->closed()) { + const Geom::Curve &closingline = path_it->back_closed(); + if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { + end_open = true; + } + } + Geom::Path original = (Geom::Path)(*path_it); + if (end_open && path_it->closed()) { + original.close(false); + original.appendNew<Geom::LineSegment>( original.initialPoint() ); + original.close(true); + } + tmp_path.push_back(original); + setFusion(tmp_path, divider, size_divider); + path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); + tmp_path.clear(); + } + if (path_out.size()>0) { + output = paths_to_pw(path_out); + } + } else { + for (int i = 0; i < num_copies; ++i) { + Rotate rot(-rad_from_deg(rotation_angle * i)); + Affine t = pre * rot * Translate(origin); + output.concat(pwd2_in * t); + } } return output; } @@ -151,8 +414,16 @@ LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geo hp_vec.push_back(pathv); } +void +LPECopyRotate::resetDefaults(SPItem const* item) +{ + Effect::resetDefaults(item); + original_bbox(SP_LPE_ITEM(item)); +} -void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { +void +LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ { KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, @@ -165,13 +436,6 @@ void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *des _("Adjust the rotation angle")); knotholder->add(e); } -} - -void -LPECopyRotate::resetDefaults(SPItem const* item) -{ - Effect::resetDefaults(item); - original_bbox(SP_LPE_ITEM(item)); }; namespace CR { diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index 9392026a7..87af867df 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -22,24 +22,22 @@ namespace Inkscape { namespace LivePathEffect { namespace CR { - // we need a separate namespace to avoid clashes with LPEPerpBisector - class KnotHolderEntityStartingAngle; - class KnotHolderEntityRotationAngle; +// we need a separate namespace to avoid clashes with LPEPerpBisector +class KnotHolderEntityStartingAngle; +class KnotHolderEntityRotationAngle; } class LPECopyRotate : public Effect, GroupBBoxEffect { public: LPECopyRotate(LivePathEffectObject *lpeobject); virtual ~LPECopyRotate(); - virtual void doOnApply (SPLPEItem const* lpeitem); - virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); - + virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); + virtual void split(Geom::PathVector &path_in, Geom::Path const ÷r); virtual void resetDefaults(SPItem const* item); - + virtual void transform_multiply(Geom::Affine const& postmul, bool set); /* the knotholder entity classes must be declared friends */ friend class CR::KnotHolderEntityStartingAngle; friend class CR::KnotHolderEntityRotationAngle; @@ -53,16 +51,14 @@ private: ScalarParam starting_angle; ScalarParam rotation_angle; ScalarParam num_copies; - BoolParam copiesTo360; - + BoolParam copies_to_360; + BoolParam fuse_paths; Geom::Point A; Geom::Point B; Geom::Point dir; - Geom::Point start_pos; Geom::Point rot_pos; double dist_angle_handle; - LPECopyRotate(const LPECopyRotate&); LPECopyRotate& operator=(const LPECopyRotate&); }; diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp index 05a672ae8..e873c0b15 100644 --- a/src/live_effects/lpe-envelope.cpp +++ b/src/live_effects/lpe-envelope.cpp @@ -42,6 +42,7 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&bend_path3) ); registerParameter( dynamic_cast<Parameter *>(&bend_path4) ); concatenate_before_pwd2 = true; + apply_to_clippath_and_mask = true; } LPEEnvelope::~LPEEnvelope() @@ -54,9 +55,6 @@ LPEEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) { // get the item bounding box original_bbox(lpeitem); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); } Geom::Piecewise<Geom::D2<Geom::SBasis> > diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 2eef315dd..fe42932be 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -4,7 +4,7 @@ * * Copyright (C) 2014 Authors * -* Released under GNU GPL v2, read the file 'COPYING' for more information +* Released under GNU GPL v2+, read the file 'COPYING' for more information */ #include "live_effects/parameter/enum.h" diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h index fddaeb619..ef7abdcc7 100644 --- a/src/live_effects/lpe-jointype.h +++ b/src/live_effects/lpe-jointype.h @@ -3,7 +3,7 @@ *
* Copyright (C) 2014 Authors
*
- * Released under GNU GPL v2, read the file COPYING for more information
+ * Released under GNU GPL v2+, read the file COPYING for more information
*/
#ifndef INKSCAPE_LPE_JOINTYPE_H
diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index c05bae7e1..3c23e349e 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -78,7 +78,7 @@ LPELattice::LPELattice(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&grid_point14) ); registerParameter( dynamic_cast<Parameter *>(&grid_point15) ); - + apply_to_clippath_and_mask = true; } LPELattice::~LPELattice() @@ -176,9 +176,6 @@ void LPELattice::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); } void diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index b749370fa..0c403daec 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -103,6 +103,7 @@ LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) : registerParameter(&grid_point_28x30); registerParameter(&grid_point_29x31); registerParameter(&grid_point_32x33x34x35); + apply_to_clippath_and_mask = true; } LPELattice2::~LPELattice2() @@ -358,9 +359,6 @@ LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem) horizontal(grid_point_17, grid_point_19,horiz); horizontal(grid_point_20x21, grid_point_22x23,horiz); } - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); } void diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 783053df2..9f3070ff4 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -6,36 +6,84 @@ * Maximilian Albert * Johan Engelen * Abhishek Sharma + * Jabiertxof * * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> * Copyright (C) Maximilin Albert 2008 <maximilian.albert@gmail.com> * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include <gtkmm.h> #include <glibmm/i18n.h> #include "live_effects/lpe-mirror_symmetry.h" #include <sp-path.h> #include <display/curve.h> #include <svg/path-string.h> - +#include "helper/geom.h" #include <2geom/path.h> +#include <2geom/path-intersection.h> #include <2geom/transforms.h> #include <2geom/affine.h> +#include "knot-holder-entity.h" +#include "knotholder.h" +#include "inkscape.h" namespace Inkscape { namespace LivePathEffect { +static const Util::EnumData<ModeType> ModeTypeData[MT_END] = { + { MT_V, N_("Vertical Page Center"), "Vertical Page Center, use select tool to move item instead line" }, + { MT_H, N_("Horizontal Page Center"), "Horizontal Page Center, use select tool to move item instead line" }, + { MT_FREE, N_("Free from reflection line"), "Free from path" }, + { MT_X, N_("X from middle knot"), "X from middle knot" }, + { MT_Y, N_("Y from middle knot"), "Y from middle knot" } +}; +static const Util::EnumDataConverter<ModeType> +MTConverter(ModeTypeData, MT_END); + +namespace MS { + +class KnotHolderEntityCenterMirrorSymmetry : public LPEKnotHolderEntity { +public: + KnotHolderEntityCenterMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){}; + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; +}; + +class KnotHolderEntityStartMirrorSymmetry : public LPEKnotHolderEntity { +public: + KnotHolderEntityStartMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){}; + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; +}; + +class KnotHolderEntityEndMirrorSymmetry : public LPEKnotHolderEntity { +public: + KnotHolderEntityEndMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){}; + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; +}; + +} // namespace MS + LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) : Effect(lpeobject), + mode(_("Mode"), _("Symmetry move mode"), "mode", MTConverter, &wr, this, MT_FREE), discard_orig_path(_("Discard original path?"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false), - reflection_line(_("Reflection line:"), _("Line which serves as 'mirror' for the reflection"), "reflection_line", &wr, this, "M0,0 L100,100") + fuse_paths(_("Fuse paths"), _("Fuse original and the reflection into a single path"), "fuse_paths", &wr, this, false), + oposite_fuse(_("Opposite fuse"), _("Picks the other side of the mirror as the original"), "oposite_fuse", &wr, this, false), + start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, "Adjust the start of mirroring"), + end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, "Adjust end of mirroring") { show_orig_path = true; - - registerParameter( dynamic_cast<Parameter *>(&discard_orig_path) ); - registerParameter( dynamic_cast<Parameter *>(&reflection_line) ); + registerParameter(&mode); + registerParameter( &discard_orig_path); + registerParameter( &fuse_paths); + registerParameter( &oposite_fuse); + registerParameter( &start_point); + registerParameter( &end_point); + apply_to_clippath_and_mask = true; } LPEMirrorSymmetry::~LPEMirrorSymmetry() @@ -43,11 +91,65 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry() } void + LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) { - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); + using namespace Geom; + + Point point_a(boundingbox_X.max(), boundingbox_Y.min()); + Point point_b(boundingbox_X.max(), boundingbox_Y.max()); + Point point_c(boundingbox_X.max(), boundingbox_Y.middle()); + if (mode == MT_Y) { + point_a = Geom::Point(boundingbox_X.min(),center_point[Y]); + point_b = Geom::Point(boundingbox_X.max(),center_point[Y]); + } + if (mode == MT_X) { + point_a = Geom::Point(center_point[X],boundingbox_Y.min()); + point_b = Geom::Point(center_point[X],boundingbox_Y.max()); + } + line_separation.setPoints(point_a, point_b); + if ( mode == MT_X || mode == MT_Y ) { + start_point.param_setValue(point_a); + end_point.param_setValue(point_b); + center_point = Geom::middle_point(point_a, point_b); + } else if ( mode == MT_FREE) { + if(!are_near(previous_center,center_point, 0.01)) { + Geom::Point trans = center_point - previous_center; + start_point.param_setValue(start_point * trans); + end_point.param_setValue(end_point * trans); + line_separation.setPoints(start_point, end_point); + } else { + center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); + line_separation.setPoints(start_point, end_point); + } + } else if ( mode == MT_V){ + if(SP_ACTIVE_DESKTOP){ + SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument(); + Geom::Rect view_box_rect = doc->getViewBox(); + Geom::Point sp = Geom::Point(view_box_rect.width()/2.0, 0); + sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + start_point.param_setValue(sp); + Geom::Point ep = Geom::Point(view_box_rect.width()/2.0, view_box_rect.height()); + ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + end_point.param_setValue(ep); + center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); + line_separation.setPoints(start_point, end_point); + } + } else { //horizontal page + if(SP_ACTIVE_DESKTOP){ + SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument(); + Geom::Rect view_box_rect = doc->getViewBox(); + Geom::Point sp = Geom::Point(0, view_box_rect.height()/2.0); + sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + start_point.param_setValue(sp); + Geom::Point ep = Geom::Point(view_box_rect.width(), view_box_rect.height()/2.0); + ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse(); + end_point.param_setValue(ep); + center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); + line_separation.setPoints(start_point, end_point); + } + } + previous_center = center_point; } void @@ -55,56 +157,210 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) { using namespace Geom; - // 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()); - A *= t; - B *= t; - Piecewise<D2<SBasis> > rline = Piecewise<D2<SBasis> >(D2<SBasis>(SBasis(A[X], B[X]), SBasis(A[Y], B[Y]))); - reflection_line.set_new_value(rline, true); + original_bbox(lpeitem); + + Point point_a(boundingbox_X.max(), boundingbox_Y.min()); + Point point_b(boundingbox_X.max(), boundingbox_Y.max()); + Point point_c(boundingbox_X.max(), boundingbox_Y.middle()); + start_point.param_setValue(point_a); + start_point.param_update_default(point_a); + end_point.param_setValue(point_b); + end_point.param_update_default(point_b); + center_point = point_c; + previous_center = center_point; } + Geom::PathVector LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) { - // Don't allow empty path parameter: - if ( reflection_line.get_pathvector().empty() ) { - return path_in; - } - + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in); Geom::PathVector path_out; - if (!discard_orig_path) { - path_out = path_in; + + if (!discard_orig_path && !fuse_paths) { + path_out = pathv_to_linear_and_cubic_beziers(path_in); } - Geom::PathVector mline(reflection_line.get_pathvector()); - Geom::Point A(mline.front().initialPoint()); - Geom::Point B(mline.back().finalPoint()); + Geom::Point point_a(line_separation.initialPoint()); + Geom::Point point_b(line_separation.finalPoint()); - Geom::Affine m1(1.0, 0.0, 0.0, 1.0, A[0], A[1]); - double hyp = Geom::distance(A, B); - double c = (B[0] - A[0]) / hyp; // cos(alpha) - double s = (B[1] - A[1]) / hyp; // sin(alpha) + Geom::Translate m1(point_a[0], point_a[1]); + double hyp = Geom::distance(point_a, point_b); + double c = (point_b[0] - point_a[0]) / hyp; // cos(alpha) + double s = (point_b[1] - point_a[1]) / hyp; // sin(alpha) Geom::Affine m2(c, -s, s, c, 0.0, 0.0); - Geom::Affine sca(1.0, 0.0, 0.0, -1.0, 0.0, 0.0); + Geom::Scale sca(1.0, -1.0); Geom::Affine m = m1.inverse() * m2; m = m * sca; m = m * m2.inverse(); m = m * m1; - for (int i = 0; i < static_cast<int>(path_in.size()); ++i) { - path_out.push_back(path_in[i] * m); + if (fuse_paths && !discard_orig_path) { + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); + path_it != original_pathv.end(); ++path_it) + { + if (path_it->empty()) { + continue; + } + Geom::PathVector tmp_path; + double time_start = 0.0; + int position = 0; + bool end_open = false; + if (path_it->closed()) { + const Geom::Curve &closingline = path_it->back_closed(); + if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { + end_open = true; + } + } + Geom::Path original = *path_it; + if (end_open && path_it->closed()) { + original.close(false); + original.appendNew<Geom::LineSegment>( original.initialPoint() ); + original.close(true); + } + Geom::Point s = start_point; + Geom::Point e = end_point; + double dir = line_separation.angle(); + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + double size_divider = Geom::distance(center_point, bbox) + diagonal; + s = Geom::Point::polar(dir,size_divider) + center_point; + e = Geom::Point::polar(dir + Geom::rad_from_deg(180),size_divider) + center_point; + Geom::Path divider = Geom::Path(s); + divider.appendNew<Geom::LineSegment>(e); + Geom::Crossings cs = crossings(original, divider); + std::vector<double> crossed; + for(unsigned int i = 0; i < cs.size(); i++) { + crossed.push_back(cs[i].ta); + } + std::sort(crossed.begin(), crossed.end()); + for (unsigned int i = 0; i < crossed.size(); i++) { + double time_end = crossed[i]; + if (time_start != time_end && time_end - time_start > Geom::EPSILON) { + Geom::Path portion = original.portion(time_start, time_end); + if (!portion.empty()) { + Geom::Point middle = portion.pointAt((double)portion.size()/2.0); + position = Geom::sgn(Geom::cross(e - s, middle - s)); + if (!oposite_fuse) { + position *= -1; + } + if (position == 1) { + Geom::Path mirror = portion.reversed() * m; + mirror.setInitial(portion.finalPoint()); + portion.append(mirror); + if(i!=0) { + portion.setFinal(portion.initialPoint()); + portion.close(); + } + tmp_path.push_back(portion); + } + portion.clear(); + } + } + time_start = time_end; + } + position = Geom::sgn(Geom::cross(e - s, original.finalPoint() - s)); + if (!oposite_fuse) { + position *= -1; + } + if (cs.size()!=0 && position == 1) { + if (time_start != original.size() && original.size() - time_start > Geom::EPSILON) { + Geom::Path portion = original.portion(time_start, original.size()); + if (!portion.empty()) { + portion = portion.reversed(); + Geom::Path mirror = portion.reversed() * m; + mirror.setInitial(portion.finalPoint()); + portion.append(mirror); + portion = portion.reversed(); + if (!original.closed()) { + tmp_path.push_back(portion); + } else { + if (cs.size() > 1 && tmp_path.size() > 0 && tmp_path[0].size() > 0 ) { + portion.setFinal(tmp_path[0].initialPoint()); + portion.setInitial(tmp_path[0].finalPoint()); + tmp_path[0].append(portion); + } else { + tmp_path.push_back(portion); + } + tmp_path[0].close(); + } + portion.clear(); + } + } + } + if (cs.size() == 0 && position == 1) { + tmp_path.push_back(original); + tmp_path.push_back(original * m); + } + path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); + tmp_path.clear(); + } + } + + if (!fuse_paths || discard_orig_path) { + for (int i = 0; i < static_cast<int>(path_in.size()); ++i) { + path_out.push_back(path_in[i] * m); + } } return path_out; } +void +LPEMirrorSymmetry::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + using namespace Geom; + hp_vec.clear(); + Geom::Path path; + Geom::Point s = start_point; + Geom::Point e = end_point; + path.start( s ); + path.appendNew<Geom::LineSegment>( e ); + Geom::PathVector helper; + helper.push_back(path); + hp_vec.push_back(helper); +} + +void +LPEMirrorSymmetry::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ + SPKnotShapeType knot_shape = SP_KNOT_SHAPE_CIRCLE; + SPKnotModeType knot_mode = SP_KNOT_MODE_XOR; + guint32 knot_color = 0x0000ff00; + { + KnotHolderEntity *c = new MS::KnotHolderEntityCenterMirrorSymmetry(this); + c->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, + _("Adjust the center"), knot_shape, knot_mode, knot_color ); + knotholder->add(c); + } +}; + +namespace MS { + +using namespace Geom; + +void +KnotHolderEntityCenterMirrorSymmetry::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) +{ + LPEMirrorSymmetry* lpe = dynamic_cast<LPEMirrorSymmetry *>(_effect); + Geom::Point const s = snap_knot_position(p, state); + lpe->center_point = s; + + // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. + sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); +} + +Geom::Point +KnotHolderEntityCenterMirrorSymmetry::knot_get() const +{ + LPEMirrorSymmetry const *lpe = dynamic_cast<LPEMirrorSymmetry const*>(_effect); + return lpe->center_point; +} + +} // namespace CR + } //namespace LivePathEffect } /* namespace Inkscape */ diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index 7a484a473..3a244cb7e 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -8,6 +8,7 @@ * Authors: * Maximilian Albert * Johan Engelen + * Jabiertxof * * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> * Copyright (C) Maximilin Albert 2008 <maximilian.albert@gmail.com> @@ -19,24 +20,50 @@ #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/point.h" #include "live_effects/parameter/path.h" +#include "live_effects/parameter/enum.h" +#include "live_effects/lpegroupbbox.h" namespace Inkscape { namespace LivePathEffect { -class LPEMirrorSymmetry : public Effect { +namespace MS { +// we need a separate namespace to avoid clashes with LPEPerpBisector +class KnotHolderEntityCenterMirrorSymmetry; +} + +enum ModeType { + MT_V, + MT_H, + MT_FREE, + MT_X, + MT_Y, + MT_END +}; + +class LPEMirrorSymmetry : public Effect, GroupBBoxEffect { public: LPEMirrorSymmetry(LivePathEffectObject *lpeobject); virtual ~LPEMirrorSymmetry(); - virtual void doOnApply (SPLPEItem const* lpeitem); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); - virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); + /* the knotholder entity classes must be declared friends */ + friend class MS::KnotHolderEntityCenterMirrorSymmetry; + void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + +protected: + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); private: + EnumParam<ModeType> mode; BoolParam discard_orig_path; - PathParam reflection_line; + BoolParam fuse_paths; + BoolParam oposite_fuse; + PointParam start_point; + PointParam end_point; + Geom::Line line_separation; + Geom::Point previous_center; + Geom::Point center_point; LPEMirrorSymmetry(const LPEMirrorSymmetry&); LPEMirrorSymmetry& operator=(const LPEMirrorSymmetry&); diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index dd7af92a2..d611b88a1 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -31,7 +31,7 @@ LPEOffset::LPEOffset(LivePathEffectObject *lpeobject) : offset_pt(_("Offset"), _("Handle to control the distance of the offset from the curve"), "offset_pt", &wr, this) { show_orig_path = true; - + apply_to_clippath_and_mask = true; registerParameter(dynamic_cast<Parameter *>(&offset_pt)); } @@ -57,14 +57,6 @@ static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, pwd2.continuousConcat(cap_pwd2); } -void -LPEOffset::doBeforeEffect (SPLPEItem const* lpeitem) -{ - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); -} - Geom::Piecewise<Geom::D2<Geom::SBasis> > LPEOffset::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { diff --git a/src/live_effects/lpe-offset.h b/src/live_effects/lpe-offset.h index 997311c7d..9966fd45d 100644 --- a/src/live_effects/lpe-offset.h +++ b/src/live_effects/lpe-offset.h @@ -28,8 +28,6 @@ public: virtual void doOnApply (SPLPEItem const* lpeitem); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); - virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); private: diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index 9397d848f..911c410f9 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -259,9 +259,16 @@ LPEPatternAlongPath::transform_multiply(Geom::Affine const& postmul, bool set) // overriding the Effect class default method, disabling transform forwarding to the parameters. // only take translations into account + // Check if proportional stroke-width scaling is on + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool transform_stroke = prefs ? prefs->getBool("/options/transform/stroke", true) : true; + if (transform_stroke && !scale_y_rel) { + prop_scale.param_set_value(prop_scale * ((postmul.expansionX() + postmul.expansionY()) / 2)); + } if (postmul.isTranslation()) { pattern.param_transform_multiply(postmul, set); } + sp_lpe_item_update_patheffect (sp_lpe_item, false, true); } void diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h index 3b9a17ab0..3d7fc02bc 100644 --- a/src/live_effects/lpe-patternalongpath.h +++ b/src/live_effects/lpe-patternalongpath.h @@ -42,7 +42,7 @@ public: virtual void transform_multiply(Geom::Affine const& postmul, bool set); void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); - + virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item); PathParam pattern; diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 72c1b0e99..5b29df4a7 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -56,6 +56,7 @@ LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject) registerParameter(&up_right_point); registerParameter(&down_left_point); registerParameter(&down_right_point); + apply_to_clippath_and_mask = true; } LPEPerspectiveEnvelope::~LPEPerspectiveEnvelope() @@ -371,9 +372,6 @@ LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) horizontal(up_left_point, down_left_point,horiz); horizontal(up_right_point, down_right_point,horiz); } - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); setDefaults(); } diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index 901519b4f..c8cdd7912 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -64,6 +64,7 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; + apply_to_clippath_and_mask = true; } LPEPerspectivePath::~LPEPerspectivePath() @@ -100,8 +101,6 @@ LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem) Geom::Affine doc2d = Geom::Scale(1, -1) * Geom::Translate(0, item->document->getHeight().value("px")); pmat = pmat * doc2d; pmat.copy_tmat(tmat); - item->apply_to_clippath(item); - item->apply_to_mask(item); } void LPEPerspectivePath::refresh(Gtk::Entry* perspective) { diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index b4ee54f1a..105fe2fc4 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -87,6 +87,7 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) segments.param_set_increments(1, 1); segments.param_set_digits(0); seed = 0; + apply_to_clippath_and_mask = true; } LPERoughen::~LPERoughen() {} @@ -102,9 +103,6 @@ void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem) displace_y.resetRandomizer(); global_randomize.resetRandomizer(); srand(1); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); } Gtk::Widget *LPERoughen::newWidget() diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 4b62c6c65..f807bdc8d 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -60,6 +60,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) helper_size.param_set_digits(2); radius_helper_nodes = 6.0; + apply_to_clippath_and_mask = true; } LPESimplify::~LPESimplify() {} @@ -71,10 +72,7 @@ LPESimplify::doBeforeEffect (SPLPEItem const* lpeitem) hp.clear(); } bbox = SP_ITEM(lpeitem)->visualBounds(); - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); radius_helper_nodes = helper_size; - item->apply_to_clippath(item); - item->apply_to_mask(item); } Gtk::Widget * diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp index dd1a29689..1cd59b7fa 100644 --- a/src/live_effects/lpe-transform_2pts.cpp +++ b/src/live_effects/lpe-transform_2pts.cpp @@ -78,6 +78,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) : strech.param_set_range(0, 999.0); strech.param_set_increments(0.01, 0.01); strech.param_set_digits(4); + apply_to_clippath_and_mask = true; } LPETransform2Pts::~LPETransform2Pts() @@ -167,8 +168,6 @@ LPETransform2Pts::doBeforeEffect (SPLPEItem const* lpeitem) previous_angle = transformed.angle(); previous_lenght = Geom::distance((Geom::Point)start, (Geom::Point)end); previous_start = start; - splpeitem->apply_to_clippath(splpeitem); - splpeitem->apply_to_mask(splpeitem); } void diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 7b424e019..7eda7446e 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -64,7 +64,7 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&drawall) ); registerParameter( dynamic_cast<Parameter *>(&maxComplexity) ); //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) ); - + apply_to_clippath_and_mask = true; nbgenerations.param_make_integer(); nbgenerations.param_set_range(0, Geom::infinity()); maxComplexity.param_make_integer(); @@ -262,9 +262,6 @@ LPEVonKoch::doBeforeEffect (SPLPEItem const* lpeitem) tmp_pathv.push_back(tmp_path); ref_path.set_new_value(tmp_pathv,true); } - SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); - item->apply_to_clippath(item); - item->apply_to_mask(item); } diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 117d57460..b321a5831 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -491,7 +491,7 @@ std::vector<double> FilletChamferPointArrayParam::get_times(int index, Geom::Pat curve_it1 = subpaths[positions.first][positions.second].duplicate(); Coord it1_length = (*curve_it1).length(tolerance); double time_it1, time_it2, time_it1_B, intpart; - if(_vector.size() <= index){ + if (static_cast<int>(_vector.size()) <= index){ std::vector<double> out; out.push_back(0); out.push_back(1); diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 7e3a6f5fe..4ee068ebf 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -144,7 +144,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget() { // Paste path to link button - Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_PASTE, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("gtk-stock", Inkscape::ICON_SIZE_BUTTON) ); Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); pButton->set_relief(Gtk::RELIEF_NONE); pIcon->show(); @@ -156,7 +156,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget() } { // Remove linked path - Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_REMOVE, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("gtk-remove", Inkscape::ICON_SIZE_BUTTON) ); Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); pButton->set_relief(Gtk::RELIEF_NONE); pIcon->show(); @@ -168,7 +168,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget() } { // Move Down - Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_DOWN, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( "gtk-go-down", Inkscape::ICON_SIZE_BUTTON) ); Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); pButton->set_relief(Gtk::RELIEF_NONE); pIcon->show(); @@ -180,7 +180,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget() } { // Move Down - Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( GTK_STOCK_GO_UP, Inkscape::ICON_SIZE_BUTTON) ); + Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( "gtk-go-up", Inkscape::ICON_SIZE_BUTTON) ); Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); pButton->set_relief(Gtk::RELIEF_NONE); pIcon->show(); diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index e0369e662..7ea1d465c 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -294,7 +294,12 @@ void PathParam::set_new_value (Geom::PathVector const &newpath, bool write_to_svg) { remove_link(); - _pathvector = newpath; + if (newpath.empty()) { + param_set_and_write_default(); + return; + } else { + _pathvector = newpath; + } must_recalculate_pwd2 = true; if (write_to_svg) { |
