summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
authorRichard White <rwhite8282@gmail.com>2016-05-19 01:17:29 +0000
committerRichard White <rwhite8282@gmail.com>2016-05-19 01:17:29 +0000
commit1fe9c2603c33fddcd9f2688b30e843f91e1a86fa (patch)
tree13289cbe033a46a40eb829437e115b5393e2ca84 /src/live_effects
parentCorrected frame extension stroke and fill values on 64 bit machine. (diff)
parentGTK3: Another widget named. (diff)
downloadinkscape-1fe9c2603c33fddcd9f2688b30e843f91e1a86fa.tar.gz
inkscape-1fe9c2603c33fddcd9f2688b30e843f91e1a86fa.zip
Merge from Inkscape trunk.
(bzr r14668.1.3)
Diffstat (limited to 'src/live_effects')
-rw-r--r--src/live_effects/effect.cpp28
-rw-r--r--src/live_effects/effect.h2
-rw-r--r--src/live_effects/lpe-bendpath.cpp5
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp324
-rw-r--r--src/live_effects/lpe-copy_rotate.h20
-rw-r--r--src/live_effects/lpe-envelope.cpp4
-rw-r--r--src/live_effects/lpe-jointype.cpp2
-rw-r--r--src/live_effects/lpe-jointype.h2
-rw-r--r--src/live_effects/lpe-lattice.cpp5
-rw-r--r--src/live_effects/lpe-lattice2.cpp4
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp330
-rw-r--r--src/live_effects/lpe-mirror_symmetry.h37
-rw-r--r--src/live_effects/lpe-offset.cpp10
-rw-r--r--src/live_effects/lpe-offset.h2
-rw-r--r--src/live_effects/lpe-patternalongpath.cpp7
-rw-r--r--src/live_effects/lpe-patternalongpath.h2
-rw-r--r--src/live_effects/lpe-perspective-envelope.cpp4
-rw-r--r--src/live_effects/lpe-perspective_path.cpp3
-rw-r--r--src/live_effects/lpe-roughen.cpp4
-rw-r--r--src/live_effects/lpe-simplify.cpp4
-rw-r--r--src/live_effects/lpe-transform_2pts.cpp3
-rw-r--r--src/live_effects/lpe-vonkoch.cpp5
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp2
-rw-r--r--src/live_effects/parameter/originalpatharray.cpp8
-rw-r--r--src/live_effects/parameter/path.cpp7
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 &divider)
+{
+ 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 &divider);
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) {