summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2016-03-19 20:10:36 +0000
committerJabiertxof <jtx@jtx.marker.es>2016-03-19 20:10:36 +0000
commit968cf01eb9a0b5248a91a697c502383e8dd7b00d (patch)
tree63eaa397c29b2a562c585b1e924feb7c8e0f2329 /src
parentStart fixing Krzysztof review (diff)
parentMerge lp:~inkscape.dev/inkscape/copy-rotate-lpe-improvements (diff)
downloadinkscape-968cf01eb9a0b5248a91a697c502383e8dd7b00d.tar.gz
inkscape-968cf01eb9a0b5248a91a697c502383e8dd7b00d.zip
update to trunk
(bzr r13682.1.35)
Diffstat (limited to 'src')
-rw-r--r--src/desktop-style.cpp6
-rw-r--r--src/extension/implementation/implementation.h24
-rw-r--r--src/extension/implementation/script.cpp24
-rw-r--r--src/extension/init.cpp2
-rw-r--r--src/extension/output.cpp3
-rw-r--r--src/live_effects/effect.cpp6
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp330
-rw-r--r--src/live_effects/lpe-copy_rotate.h20
-rw-r--r--src/live_effects/parameter/path.cpp7
-rw-r--r--src/sp-lpe-item.cpp21
-rw-r--r--src/sp-lpe-item.h2
-rw-r--r--src/sp-text.cpp4
-rw-r--r--src/ui/tool/path-manipulator.cpp2
-rw-r--r--src/widgets/text-toolbar.cpp8
14 files changed, 365 insertions, 94 deletions
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index c28302d22..d10c75cd8 100644
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
@@ -1004,10 +1004,10 @@ objects_query_paintorder (const std::vector<SPItem*> &objects, SPStyle *style_re
n_order ++;
- if (!prev_order.empty() && prev_order.compare( style->paint_order.value ) != 0) {
- same_order = false;
- }
if (style->paint_order.set) {
+ if (!prev_order.empty() && prev_order.compare( style->paint_order.value ) != 0) {
+ same_order = false;
+ }
prev_order = style->paint_order.value;
}
}
diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h
index f6f933aaf..1232ae0c8 100644
--- a/src/extension/implementation/implementation.h
+++ b/src/extension/implementation/implementation.h
@@ -18,7 +18,7 @@
#include <2geom/forward.h>
namespace Gtk {
- class Widget;
+ class Widget;
}
class SPDocument;
@@ -33,7 +33,7 @@ class View;
} // namespace UI
namespace XML {
- class Node;
+ class Node;
} // namespace XML
namespace Extension {
@@ -51,18 +51,18 @@ namespace Implementation {
*/
class ImplementationDocumentCache {
- /**
+ /**
* The document that this instance is working on.
*/
- Inkscape::UI::View::View * _view;
+ Inkscape::UI::View::View * _view;
public:
- ImplementationDocumentCache (Inkscape::UI::View::View * view) :
- _view(view)
- {
- return;
- };
- virtual ~ImplementationDocumentCache ( ) { return; };
- Inkscape::UI::View::View const * view ( ) { return _view; };
+ ImplementationDocumentCache (Inkscape::UI::View::View * view) :
+ _view(view)
+ {
+ return;
+ };
+ virtual ~ImplementationDocumentCache ( ) { return; };
+ Inkscape::UI::View::View const * view ( ) { return _view; };
};
/**
@@ -116,7 +116,7 @@ public:
// ----- Effect functions -----
/** Find out information about the file. */
virtual Gtk::Widget * prefs_effect(Inkscape::Extension::Effect *module,
- Inkscape::UI::View::View *view,
+ Inkscape::UI::View::View *view,
sigc::signal<void> *changeSignal,
ImplementationDocumentCache *docCache);
virtual void effect(Inkscape::Extension::Effect * /*module*/,
diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp
index 4cb0c9b73..2ec17f947 100644
--- a/src/extension/implementation/script.cpp
+++ b/src/extension/implementation/script.cpp
@@ -152,7 +152,7 @@ Script::Script() :
}
/**
- * brief Destructor
+ * \brief Destructor
*/
Script::~Script()
{
@@ -232,11 +232,7 @@ bool Script::check_existence(const std::string &command)
//Don't search when it is an absolute path. */
if (Glib::path_is_absolute(command)) {
- if (Glib::file_test(command, Glib::FILE_TEST_EXISTS)) {
- return true;
- } else {
- return false;
- }
+ return Glib::file_test(command, Glib::FILE_TEST_EXISTS);
}
// First search in the current directory
@@ -280,9 +276,9 @@ bool Script::check_existence(const std::string &command)
/**
\return none
- \brief This function 'loads' an extention, basically it determines
- the full command for the extention and stores that.
- \param module The extention to be loaded.
+ \brief This function 'loads' an extension, basically it determines
+ the full command for the extension and stores that.
+ \param module The extension to be loaded.
The most difficult part about this function is finding the actual
command through all of the Reprs. Basically it is hidden down a
@@ -292,7 +288,7 @@ bool Script::check_existence(const std::string &command)
At that point all of the loops are exited, and there is an
if statement to make sure they didn't exit because of not finding
- the command. If that's the case, the extention doesn't get loaded
+ the command. If that's the case, the extension doesn't get loaded
and should error out at a higher level.
*/
@@ -545,17 +541,17 @@ SPDocument *Script::open(Inkscape::Extension::Input *module,
/**
\return none
- \brief This function uses an extention to save a document. It first
+ \brief This function uses an extension to save a document. It first
creates an SVG file of the document, and then runs it through
the script.
- \param module Extention to be used
+ \param module Extension to be used
\param doc Document to be saved
\param filename The name to save the final file as
\return false in case of any failure writing the file, otherwise true
Well, at some point people need to save - it is really what makes
the entire application useful. And, it is possible that someone
- would want to use an extetion for this, so we need a function to
+ would want to use an extension for this, so we need a function to
do that eh?
First things first, the document is saved to a temporary file that
@@ -563,7 +559,7 @@ SPDocument *Script::open(Inkscape::Extension::Input *module,
ink_ext_ as a prefix. Don't worry, this file gets deleted at the
end of the function.
- After we have the SVG file, then extention_execute is called with
+ After we have the SVG file, then Script::execute is called with
the temporary file name and the final output filename. This should
put the output of the script into the final output file. We then
delete the temporary file.
diff --git a/src/extension/init.cpp b/src/extension/init.cpp
index c16a5a899..af7af2cb1 100644
--- a/src/extension/init.cpp
+++ b/src/extension/init.cpp
@@ -1,6 +1,6 @@
/*
* This is what gets executed to initialize all of the modules. For
- * the internal modules this invovles executing their initialization
+ * the internal modules this involves executing their initialization
* functions, for external ones it involves reading their .spmodule
* files and bringing them into Sodipodi.
*
diff --git a/src/extension/output.cpp b/src/extension/output.cpp
index 8de5583c7..83f0fed2f 100644
--- a/src/extension/output.cpp
+++ b/src/extension/output.cpp
@@ -192,8 +192,7 @@ Output::prefs (void)
delete dialog;
- if (response == Gtk::RESPONSE_OK) return true;
- return false;
+ return (response == Gtk::RESPONSE_OK);
}
/**
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index 22fa32bda..437aed5bd 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -109,7 +109,6 @@ const Util::EnumData<EffectType> LPETypeData[] = {
{PATH_LENGTH, N_("Path length"), "path_length"},
{PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"},
{PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"},
- {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"},
@@ -145,6 +144,7 @@ const Util::EnumData<EffectType> LPETypeData[] = {
{JOIN_TYPE, N_("Join type"), "join_type"},
{TAPER_STROKE, N_("Taper stroke"), "taper_stroke"},
{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"},
@@ -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/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp
index 8dfaf7525..f204f8608 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,22 +42,39 @@ 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
+int
+pointSideOfLine(Geom::Point const &A, Geom::Point const &B, Geom::Point const &X)
+{
+ //http://stackoverflow.com/questions/1560492/how-to-tell-whether-a-point-is-to-the-right-or-left-side-of-a-line
+ double pos = (B[Geom::X]-A[Geom::X])*(X[Geom::Y]-A[Geom::Y]) - (B[Geom::Y]-A[Geom::Y])*(X[Geom::X]-A[Geom::X]);
+ return (pos < 0) ? -1 : (pos > 0);
+}
+
+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),
+ 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"), "fuse_paths", &wr, this, false),
dist_angle_handle(100.0)
{
show_orig_path = true;
@@ -64,12 +82,13 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
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);
}
@@ -93,15 +112,45 @@ 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);
+ }
+ } 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);
@@ -109,27 +158,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];
+ Geom::Path portion_original = original.portion(time_start,time_end);
+ if (!portion_original.empty()) {
+ Geom::Point side_checker = portion_original.pointAt(0.001);
+ position = pointSideOfLine(divider[0].finalPoint(), divider[1].finalPoint(), side_checker);
+ 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 = pointSideOfLine(divider[0].finalPoint(), divider[1].finalPoint(), original.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::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::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::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);
+ tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed();
+ } 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);
+ tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed();
+ } 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);
+ tmp_path_helper[0] = tmp_path_helper[0].reversed();
+ } 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;
}
@@ -148,8 +421,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,
@@ -162,13 +443,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/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) {
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index e2afbb55b..fdc2949d5 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -209,7 +209,7 @@ Inkscape::XML::Node* SPLPEItem::write(Inkscape::XML::Document *xml_doc, Inkscape
/**
* returns true when LPE was successful.
*/
-bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) {
+bool SPLPEItem::performPathEffect(SPCurve *curve, bool is_clip_or_mask) {
if (!this) {
return false;
}
@@ -217,7 +217,6 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) {
if (!curve) {
return false;
}
- bool apply_to_clippath_and_mask = false;
if (this->hasPathEffect() && this->pathEffectsEnabled()) {
for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it)
{
@@ -237,17 +236,13 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) {
g_warning("SPLPEItem::performPathEffect - lpeobj with invalid lpe in the stack!");
return false;
}
-
if (lpe->isVisible()) {
- if(lpe->apply_to_clippath_and_mask){
- apply_to_clippath_and_mask = true;
- }
if (lpe->acceptsNumClicks() > 0 && !lpe->isReady()) {
// if the effect expects mouse input before being applied and the input is not finished
// yet, we don't alter the path
return false;
}
- if (clip_paths || lpe->apply_to_clippath_and_mask) {
+ if (!is_clip_or_mask || (is_clip_or_mask && lpe->apply_to_clippath_and_mask)) {
// Groups have their doBeforeEffect called elsewhere
if (!SP_IS_GROUP(this)) {
lpe->doBeforeEffect_impl(this);
@@ -270,10 +265,10 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) {
}
}
}
- }
- if(apply_to_clippath_and_mask && clip_paths){
- this->apply_to_clippath((SPItem *)this);
- this->apply_to_mask((SPItem *)this);
+ if(!SP_IS_GROUP(this) && !is_clip_or_mask){
+ this->apply_to_clippath(this);
+ this->apply_to_mask(this);
+ }
}
return true;
}
@@ -698,10 +693,10 @@ SPLPEItem::apply_to_clip_or_mask(SPItem *clip_mask, SPItem *item)
try {
if(SP_IS_GROUP(this)){
c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)));
- success = this->performPathEffect(c, false);
+ success = this->performPathEffect(c, true);
c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse());
} else {
- success = this->performPathEffect(c, false);
+ success = this->performPathEffect(c, true);
}
} catch (std::exception & e) {
g_warning("Exception during LPE execution. \n %s", e.what());
diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h
index d5e868b2e..9e5cb3329 100644
--- a/src/sp-lpe-item.h
+++ b/src/sp-lpe-item.h
@@ -69,7 +69,7 @@ public:
virtual void update_patheffect(bool write);
- bool performPathEffect(SPCurve *curve, bool clip_paths = true);
+ bool performPathEffect(SPCurve *curve, bool is_clip_or_mask = false);
bool pathEffectsEnabled() const;
bool hasPathEffect() const;
diff --git a/src/sp-text.cpp b/src/sp-text.cpp
index 4a5b1b1d6..7d4348d19 100644
--- a/src/sp-text.cpp
+++ b/src/sp-text.cpp
@@ -819,8 +819,8 @@ void TextTagAttributes::setFirstXY(Geom::Point &point)
attributes.x.resize(1, zero_length);
if (attributes.y.empty())
attributes.y.resize(1, zero_length);
- attributes.x[0].computed = point[Geom::X];
- attributes.y[0].computed = point[Geom::Y];
+ attributes.x[0] = point[Geom::X];
+ attributes.y[0] = point[Geom::Y];
}
void TextTagAttributes::mergeInto(Inkscape::Text::Layout::OptionalTextTagAttrs *output, Inkscape::Text::Layout::OptionalTextTagAttrs const &parent_attrs, unsigned parent_attrs_offset, bool copy_xy, bool copy_dxdyrotate) const
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index f4790c317..3b25439f3 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -1492,7 +1492,6 @@ void PathManipulator::_getGeometry()
void PathManipulator::_setGeometry()
{
using namespace Inkscape::LivePathEffect;
- if (empty()) return;
if (!_lpe_key.empty()) {
// copied from nodepath.cpp
@@ -1505,6 +1504,7 @@ void PathManipulator::_setGeometry()
LIVEPATHEFFECT(_path)->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
} else {
+ if (empty()) return;
//XML Tree being used here directly while it shouldn't be.
if (_path->getRepr()->attribute("inkscape:original-d"))
_path->set_original_curve(_spcurve, false, false);
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index c49f0bc05..60e932338 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -1106,9 +1106,11 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
lh_unit = unit_table.getUnit("%");
height = query.line_height.value * 100;
} else {
- lh_unit = tracker->getActiveUnit();
- // Can get unit like this: unit_table.getUnit(query.line_height.unit);
- height = Inkscape::Util::Quantity::convert(query.line_height.computed, "px", lh_unit);
+ //Unit const *active = tracker->getActiveUnit();
+ // This allows us to show the unit stored to the user, but right now
+ // it's always px (because Tav said other units are broken/2016)
+ lh_unit = unit_table.getUnit(query.line_height.unit);
+ height = query.line_height.computed;
}
// Set before value is set