summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2017-01-24 09:32:24 +0000
committerjabiertxof <info@marker.es>2017-01-24 09:32:24 +0000
commit7fecbddd1fb8b57f9c6efd3204645e33d9b38d09 (patch)
treece9f038347327a219b55fae5be1f6b30d91d1522 /src
parentRemove some code and make dependant of rotate copies (diff)
downloadinkscape-7fecbddd1fb8b57f9c6efd3204645e33d9b38d09.tar.gz
inkscape-7fecbddd1fb8b57f9c6efd3204645e33d9b38d09.zip
update to trunk
(bzr r15356.1.18)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/intersection-graph.cpp6
-rw-r--r--src/helper/geom.cpp7
-rw-r--r--src/helper/geom.h2
-rw-r--r--src/live_effects/effect.cpp88
-rw-r--r--src/live_effects/effect.h20
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp306
-rw-r--r--src/live_effects/lpe-copy_rotate.h14
-rw-r--r--src/live_effects/lpe-measure-line.cpp66
-rw-r--r--src/live_effects/lpe-measure-line.h8
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp342
-rw-r--r--src/live_effects/lpe-mirror_symmetry.h13
-rw-r--r--src/live_effects/parameter/bool.cpp3
-rw-r--r--src/live_effects/parameter/text.cpp3
-rw-r--r--src/sp-item-group.cpp43
-rw-r--r--src/sp-lpe-item.cpp35
-rw-r--r--src/sp-lpe-item.h5
-rw-r--r--src/sp-object.cpp15
-rw-r--r--src/sp-object.h3
-rw-r--r--src/sp-path.cpp31
-rw-r--r--src/ui/dialog/polar-arrange-tab.cpp4
20 files changed, 812 insertions, 202 deletions
diff --git a/src/2geom/intersection-graph.cpp b/src/2geom/intersection-graph.cpp
index d469d3ffc..cac010942 100644
--- a/src/2geom/intersection-graph.cpp
+++ b/src/2geom/intersection-graph.cpp
@@ -410,10 +410,10 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b)
assert(!result.back().empty());
}
- /*if (n_processed != size() * 2) {
+ if (n_processed != size() * 2) {
std::cerr << "Processed " << n_processed << " intersections, expected " << (size() * 2) << std::endl;
- }*/
- assert(n_processed == size() * 2);
+ }
+ //assert(n_processed == size() * 2);
return result;
}
diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp
index 42c494c00..e1f05c3ce 100644
--- a/src/helper/geom.cpp
+++ b/src/helper/geom.cpp
@@ -843,6 +843,13 @@ recursive_bezier4(const double x1, const double y1,
recursive_bezier4(x1234, y1234, x234, y234, x34, y34, x4, y4, m_points, level + 1);
}
+void
+swap(Geom::Point &A, Geom::Point &B){
+ Geom::Point tmp = A;
+ A = B;
+ B = tmp;
+}
+
/*
Local Variables:
mode:c++
diff --git a/src/helper/geom.h b/src/helper/geom.h
index d49e2070c..b3d907e51 100644
--- a/src/helper/geom.h
+++ b/src/helper/geom.h
@@ -32,7 +32,7 @@ void recursive_bezier4(const double x1, const double y1, const double x2, const
const double x3, const double y3, const double x4, const double y4,
std::vector<Geom::Point> &pointlist,
int level);
-
+void swap(Geom::Point &A, Geom::Point &B);
#endif // INKSCAPE_HELPER_GEOM_H
/*
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index 9d9381294..50e2aa353 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -70,6 +70,8 @@
#include "ui/tools/node-tool.h"
#include "ui/tools-switch.h"
#include "knotholder.h"
+#include "path-chemistry.h"
+#include "xml/sp-css-attr.h"
#include "live_effects/lpeobject.h"
#include "display/curve.h"
@@ -356,6 +358,7 @@ Effect::Effect(LivePathEffectObject *lpeobject)
sp_lpe_item(NULL),
current_zoom(1),
upd_params(true),
+ sp_shape(NULL),
sp_curve(NULL),
provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden
is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden
@@ -392,15 +395,15 @@ Effect::doOnApply (SPLPEItem const*/*lpeitem*/)
}
void
-Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP)
+Effect::setCurrentZoom(double cZ)
{
- selectedNodesPoints = sNP;
+ current_zoom = cZ;
}
void
-Effect::setCurrentZoom(double cZ)
+Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP)
{
- current_zoom = cZ;
+ selectedNodesPoints = sNP;
}
bool
@@ -423,6 +426,74 @@ Effect::isNodePointSelected(Geom::Point const &nodePoint) const
return false;
}
+void
+Effect::processObjects(LpeAction lpe_action)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ for (std::vector<const char *>::iterator el_it = items.begin();
+ el_it != items.end(); ++el_it) {
+ const char * id = *el_it;
+ if (!id || strlen(id) == 0) {
+ return;
+ }
+ SPObject *elemref = NULL;
+ if (elemref = document->getObjectById(id)) {
+ Inkscape::XML::Node * elemnode = elemref->getRepr();
+ std::vector<SPItem*> item_list;
+ item_list.push_back(SP_ITEM(elemref));
+ std::vector<Inkscape::XML::Node*> item_to_select;
+ std::vector<SPItem*> item_selected;
+ SPCSSAttr *css;
+ Glib::ustring css_str;
+ switch (lpe_action){
+ case LPE_TO_OBJECTS:
+ if (SP_ITEM(elemref)->isHidden()) {
+ elemref->deleteObject();
+ } else {
+ if (elemnode->attribute("inkscape:path-effect")) {
+ sp_item_list_to_curves(item_list, item_selected, item_to_select);
+ }
+ elemnode->setAttribute("sodipodi:insensitive", NULL);
+ }
+ break;
+
+ case LPE_ERASE:
+ elemref->deleteObject();
+ break;
+
+ case LPE_VISIBILITY:
+ css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, elemref->getRepr()->attribute("style"));
+ if (!this->isVisible()/* && std::strcmp(elemref->getId(),sp_lpe_item->getId()) != 0*/) {
+ css->setAttribute("display", "none");
+ } else {
+ css->setAttribute("display", NULL);
+ }
+ sp_repr_css_write_string(css,css_str);
+ elemnode->setAttribute("style", css_str.c_str());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ if (lpe_action == LPE_ERASE || lpe_action == LPE_TO_OBJECTS) {
+ items.clear();
+ }
+}
+
+void Effect::setCurrentShape(SPShape * shape){
+ if(shape){
+ sp_shape = shape;
+ if (!(sp_curve = sp_shape->getCurve())) {
+ // oops
+ return;
+ }
+ pathvector_before_effect = sp_curve->get_pathvector();
+ }
+}
+
/**
* Is performed each time before the effect is updated.
*/
@@ -446,8 +517,12 @@ void Effect::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
void Effect::doOnApply_impl(SPLPEItem const* lpeitem)
{
sp_lpe_item = const_cast<SPLPEItem *>(lpeitem);
- /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve();
- pathvector_before_effect = sp_curve->get_pathvector();*/
+ sp_curve = SP_SHAPE(sp_lpe_item)->getCurve();
+ pathvector_before_effect = sp_curve->get_pathvector();
+ SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item);
+ if(shape){
+ setCurrentShape(shape);
+ }
doOnApply(lpeitem);
}
@@ -457,6 +532,7 @@ void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem)
//printf("(SPLPEITEM*) %p\n", sp_lpe_item);
SPShape * shape = dynamic_cast<SPShape *>(sp_lpe_item);
if(shape){
+ setCurrentShape(shape);
sp_curve = shape->getCurve();
pathvector_before_effect = sp_curve->get_pathvector();
}
diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h
index 1997ff0ca..f5e41d50e 100644
--- a/src/live_effects/effect.h
+++ b/src/live_effects/effect.h
@@ -19,7 +19,7 @@
class SPDocument;
class SPDesktop;
class SPItem;
-class LivePathEffectObject;
+class LivePathEffectObject;
class SPLPEItem;
class KnotHolder;
class KnotHolderEntity;
@@ -44,6 +44,12 @@ enum LPEPathFlashType {
DEFAULT
};
+enum LpeAction {
+ LPE_ERASE = 0,
+ LPE_TO_OBJECTS,
+ LPE_VISIBILITY
+};
+
class Effect {
public:
static Effect* New(EffectType lpenr, LivePathEffectObject *lpeobj);
@@ -73,6 +79,9 @@ public:
static int acceptsNumClicks(EffectType type);
int acceptsNumClicks() const { return acceptsNumClicks(effectType()); }
void doAcceptPathPreparations(SPLPEItem *lpeitem);
+ SPShape * getCurrentShape(){ return sp_shape; };
+ void setCurrentShape(SPShape * shape);
+ void processObjects(LpeAction lpe_action);
/*
* isReady() indicates whether all preparations which are necessary to apply the LPE are done,
@@ -125,7 +134,9 @@ public:
bool apply_to_clippath_and_mask;
bool erase_extra_objects; // set this to false allow retain extra generated objects, see measure line LPE
bool upd_params;
-
+ BoolParam is_visible;
+ SPCurve * sp_curve;
+ Geom::PathVector pathvector_before_effect;
protected:
Effect(LivePathEffectObject *lpeobject);
@@ -150,7 +161,6 @@ protected:
bool _provides_knotholder_entities;
int oncanvasedit_it;
- BoolParam is_visible;
bool show_orig_path; // set this to true in derived effects to automatically have the original
// path displayed as helperpath
@@ -164,10 +174,10 @@ protected:
bool concatenate_before_pwd2;
SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them.
+ SPShape * sp_shape; // these get stored in doBeforeEffect_impl before doEffect chain, or in performPathEffects on groups, and derived classes may do as they please with them.
+ std::vector<const char *> items;
double current_zoom;
std::vector<Geom::Point> selectedNodesPoints;
- SPCurve * sp_curve;
- Geom::PathVector pathvector_before_effect;
private:
bool provides_own_flash_paths; // if true, the standard flash path is suppressed
diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp
index 813f25d3d..fbc7933e7 100644
--- a/src/live_effects/lpe-copy_rotate.cpp
+++ b/src/live_effects/lpe-copy_rotate.cpp
@@ -17,6 +17,13 @@
#include <2geom/sbasis-to-bezier.h>
#include <2geom/intersection-graph.h>
#include "live_effects/lpe-copy_rotate.h"
+#include "display/curve.h"
+#include "svg/path-string.h"
+#include "svg/svg.h"
+#include "style.h"
+#include "helper/geom.h"
+#include "xml/sp-css-attr.h"
+#include "path-chemistry.h"
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
@@ -45,9 +52,11 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
starting_angle(_("Starting angle"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
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),
+ split_gap(_("Gap on split"), _("Gap on split"), "split_gap", &wr, this, -0.001),
copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true),
fuse_paths(_("Kaleidoskope"), _("Kaleidoskope by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false),
join_paths(_("Join paths"), _("Join paths, use fill-rule: evenodd for best result"), "join_paths", &wr, this, false),
+ split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false),
dist_angle_handle(100.0)
{
show_orig_path = true;
@@ -56,15 +65,21 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
registerParameter(&copies_to_360);
registerParameter(&fuse_paths);
registerParameter(&join_paths);
+ registerParameter(&split_items);
registerParameter(&starting_angle);
registerParameter(&starting_point);
registerParameter(&rotation_angle);
registerParameter(&num_copies);
+ registerParameter(&split_gap);
registerParameter(&origin);
-
+ split_gap.param_set_range(-999999.0, 999999.0);
+ split_gap.param_set_increments(0.1, 0.1);
+ split_gap.param_set_digits(5);
+ num_copies.param_set_range(0, 999999);
num_copies.param_make_integer(true);
- num_copies.param_set_range(0, 1000);
apply_to_clippath_and_mask = true;
+ previous_num_copies = num_copies;
+ reset = false;
}
LPECopyRotate::~LPECopyRotate()
@@ -72,6 +87,207 @@ LPECopyRotate::~LPECopyRotate()
}
+void
+LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem)
+{
+ if (split_items) {
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ items.clear();
+ container = dynamic_cast<SPObject *>(sp_lpe_item->parent);
+ SPDocument * doc = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = doc->getReprRoot();
+ if (root_origin != root) {
+ return;
+ }
+ if (previous_num_copies != num_copies) {
+ gint numcopies_gap = previous_num_copies - num_copies;
+ if (numcopies_gap > 0 && num_copies != 0) {
+ guint counter = num_copies - 1;
+ while (numcopies_gap > 0) {
+ const char * id = g_strdup(Glib::ustring("rotated-").append(std::to_string(counter)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ if (!id || strlen(id) == 0) {
+ return;
+ }
+ SPObject *elemref = NULL;
+ if (elemref = document->getObjectById(id)) {
+ SP_ITEM(elemref)->setHidden(true);
+ }
+ counter++;
+ numcopies_gap--;
+ }
+ }
+ previous_num_copies = num_copies;
+ }
+ SPObject *elemref = NULL;
+ char * id = g_strdup(Glib::ustring("rotated-").append("1").append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ guint counter = 0;
+ while(elemref = document->getObjectById(id)) {
+ if (SP_ITEM(elemref)->isHidden()) {
+ items.push_back(id);
+ }
+ id = g_strdup(Glib::ustring("rotated-").append(std::to_string(counter)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ counter++;
+ }
+ g_free(id);
+ 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 * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider;
+ Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider;
+ Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle)));
+ if (fuse_paths) {
+ size_t rest = 0;
+ for (size_t i = 1; i < num_copies; ++i) {
+ Geom::Affine r = Geom::identity();
+ Geom::Point dir = unit_vector((Geom::Point)origin - Geom::middle_point(line_start,line_end));
+ if( rest%2 == 0) {
+ r *= Geom::Rotate(Geom::Angle(dir)).inverse();
+ r *= Geom::Scale(1, -1);
+ r *= Geom::Rotate(Geom::Angle(dir));
+ }
+ Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i)));
+ Geom::Affine t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ if( rest%2 == 0) {
+ t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin);
+ }
+ t *= sp_lpe_item->transform;
+ toItem(t, i-1, reset);
+ rest ++;
+ }
+ } else {
+ for (size_t i = 1; i < num_copies; ++i) {
+ Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i)));
+ Geom::Affine t = m * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
+ t *= sp_lpe_item->transform;
+ toItem(t, i - 1, reset);
+ }
+ }
+ reset = false;
+ } else {
+ processObjects(LPE_ERASE);
+ items.clear();
+ }
+
+ std::cout << previous_num_copies << "previous_num_copies\n";
+ std::cout << num_copies << "num_copies\n";
+}
+
+void
+LPECopyRotate::cloneD(SPObject *origin, SPObject *dest, bool root, bool reset)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ if ( SP_IS_GROUP(origin) && SP_IS_GROUP(dest) && SP_GROUP(origin)->getItemCount() == SP_GROUP(dest)->getItemCount() ) {
+ std::vector< SPObject * > childs = origin->childList(true);
+ size_t index = 0;
+ for (std::vector<SPObject * >::iterator obj_it = childs.begin();
+ obj_it != childs.end(); ++obj_it) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneD(*obj_it, dest_child, false, reset);
+ index++;
+ }
+ }
+ SPShape * shape = SP_SHAPE(origin);
+ SPPath * path = SP_PATH(dest);
+ if (!path && !SP_IS_GROUP(dest)) {
+ Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0);
+ dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL);
+ path = SP_PATH(dest);
+ }
+ if (path && shape) {
+ SPCurve *c = NULL;
+ if (root) {
+ c = new SPCurve();
+ c->set_pathvector(pathvector_before_effect);
+ } else {
+ c = shape->getCurve();
+ }
+ if (c) {
+ path->setCurve(c, TRUE);
+ c->unref();
+ } else {
+ dest->getRepr()->setAttribute("d", NULL);
+ }
+ if (reset) {
+ dest->getRepr()->setAttribute("style", shape->getRepr()->attribute("style"));
+ }
+ }
+}
+
+void
+LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ const char * elemref_id = g_strdup(Glib::ustring("rotated-").append(std::to_string(i)).append("-").append(sp_lpe_item->getRepr()->attribute("id")).c_str());
+ items.push_back(elemref_id);
+ SPObject *elemref= NULL;
+ Inkscape::XML::Node *phantom = NULL;
+ if (elemref = document->getObjectById(elemref_id)) {
+ phantom = elemref->getRepr();
+ } else {
+ phantom = sp_lpe_item->getRepr()->duplicate(xml_doc);
+ std::vector<const char *> attrs;
+ attrs.push_back("inkscape:path-effect");
+ attrs.push_back("inkscape:original-d");
+ attrs.push_back("sodipodi:type");
+ attrs.push_back("sodipodi:rx");
+ attrs.push_back("sodipodi:ry");
+ attrs.push_back("sodipodi:cx");
+ attrs.push_back("sodipodi:cy");
+ attrs.push_back("sodipodi:end");
+ attrs.push_back("sodipodi:start");
+ attrs.push_back("inkscape:flatsided");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:rounded");
+ attrs.push_back("sodipodi:arg1");
+ attrs.push_back("sodipodi:arg2");
+ attrs.push_back("sodipodi:r1");
+ attrs.push_back("sodipodi:r2");
+ attrs.push_back("sodipodi:sides");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("sodipodi:argument");
+ attrs.push_back("sodipodi:expansion");
+ attrs.push_back("sodipodi:radius");
+ attrs.push_back("sodipodi:revolution");
+ attrs.push_back("sodipodi:t0");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("x");
+ attrs.push_back("y");
+ attrs.push_back("rx");
+ attrs.push_back("ry");
+ attrs.push_back("width");
+ attrs.push_back("height");
+ phantom->setAttribute("id", elemref_id);
+ for(const char * attr : attrs) {
+ phantom->setAttribute(attr, NULL);
+ }
+ }
+ if (!elemref) {
+ elemref = container->appendChildRepr(phantom);
+ Inkscape::GC::release(phantom);
+ }
+ cloneD(SP_OBJECT(sp_lpe_item), elemref, true, reset);
+ elemref->getRepr()->setAttribute("transform" , sp_svg_transform_write(transform));
+ SP_ITEM(elemref)->setHidden(false);
+ if (elemref->parent != container) {
+ Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
+ copy->setAttribute("id", elemref_id);
+ container->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ }
+}
+
+void
+LPECopyRotate::resetStyles(){
+ reset = true;
+ doAfterEffect(sp_lpe_item);
+}
+
Gtk::Widget * LPECopyRotate::newWidget()
{
// use manage here, because after deletion of Effect object, others might
@@ -81,7 +297,15 @@ Gtk::Widget * LPECopyRotate::newWidget()
vbox->set_border_width(5);
vbox->set_homogeneous(false);
vbox->set_spacing(2);
-
+ Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
+ Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
+ vbox_expander->set_border_width(0);
+ vbox_expander->set_spacing(2);
+ Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset styles"))));
+ reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPECopyRotate::resetStyles));
+ reset_button->set_size_request(140,30);
+ vbox->pack_start(*hbox, true,true,2);
+ hbox->pack_start(*reset_button, false, false,2);
std::vector<Parameter *>::iterator it = param_vector.begin();
while (it != param_vector.end()) {
if ((*it)->widget_is_visible) {
@@ -125,11 +349,11 @@ void
LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set)
{
// cycle through all parameters. Most parameters will not need transformation, but path and point params do.
-
for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
Parameter * param = *it;
param->param_transform_multiply(postmul, set);
}
+ sp_lpe_item_update_patheffect(sp_lpe_item, false, false);
}
void
@@ -140,17 +364,17 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem)
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) {
+ if (fuse_paths && rotation_angle * num_copies > 360.1 && 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);
+ num_copies.param_set_increments(2.0,10.0);
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);
+ num_copies.param_set_increments(1.0, 10.0);
}
if (dist_angle_handle < 1.0) {
@@ -352,12 +576,57 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s
tmp_path.clear();
}
+Geom::PathVector
+LPECopyRotate::doEffect_path (Geom::PathVector const & path_in)
+{
+ Geom::PathVector path_out;
+ if (split_items && (fuse_paths || join_paths)) {
+ if (num_copies == 0) {
+ return path_out;
+ }
+ path_out = pathv_to_linear_and_cubic_beziers(path_in);
+ double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max()));
+ Geom::OptRect bbox = sp_lpe_item->geometricBounds();
+ double size_divider = Geom::distance(origin,bbox) + (diagonal * 2);
+ Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider;
+ Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider;
+ Geom::Path divider = Geom::Path(line_start);
+ divider.appendNew<Geom::LineSegment>((Geom::Point)origin);
+ divider.appendNew<Geom::LineSegment>(line_end);
+ divider.close();
+ Geom::PathVector triangle;
+ triangle.push_back(divider);
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(triangle, path_out);
+ if (pig && ! path_out.empty() && !triangle.empty()) {
+ //TODO: Here can produce a crash because some knows problems in new boolops code
+ path_out = pig->getIntersection();
+ }
+ Geom::Affine r = Geom::identity();
+ Geom::Point dir = unit_vector(Geom::middle_point(line_start,line_end) - (Geom::Point)origin);
+ Geom::Point gap = dir * split_gap;
+ r *= Geom::Translate(gap);
+ path_out *= r;
+ } else {
+ // default behavior
+ for (unsigned int i=0; i < path_in.size(); i++) {
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb();
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in);
+ Geom::PathVector path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE);
+ // add the output path vector to the already accumulated vector:
+ for (unsigned int j=0; j < path.size(); j++) {
+ path_out.push_back(path[j]);
+ }
+ }
+ }
+ return pathv_to_linear_and_cubic_beziers(path_out);
+}
+
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 && !fuse_paths) {
+ if ((num_copies == 1 && !fuse_paths) || split_items) {
return pwd2_in;
}
@@ -373,10 +642,10 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
divider.appendNew<Geom::LineSegment>(line_end);
Piecewise<D2<SBasis> > output;
Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle));
+ PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001));
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;
@@ -403,7 +672,7 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
output = paths_to_pw(path_out);
}
} else {
- Geom::PathVector output_pv = path_from_piecewise(output , 0.01);
+ Geom::PathVector output_pv;
for (int i = 0; i < num_copies; ++i) {
Rotate rot(-rad_from_deg(rotation_angle * i));
Affine t = pre * rot * Translate(origin);
@@ -449,6 +718,23 @@ LPECopyRotate::resetDefaults(SPItem const* item)
original_bbox(SP_LPE_ITEM(item));
}
+void
+LPECopyRotate::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+{
+ processObjects(LPE_VISIBILITY);
+}
+
+void
+LPECopyRotate::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ //unset "erase_extra_objects" hook on sp-lpe-item.cpp
+ if (!erase_extra_objects) {
+ processObjects(LPE_TO_OBJECTS);
+ return;
+ }
+ processObjects(LPE_ERASE);
+}
+
} //namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h
index c2ae2daf1..dbec2e1c3 100644
--- a/src/live_effects/lpe-copy_rotate.h
+++ b/src/live_effects/lpe-copy_rotate.h
@@ -15,6 +15,8 @@
*/
#include "live_effects/effect.h"
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/text.h"
#include "live_effects/parameter/point.h"
#include "live_effects/lpegroupbbox.h"
@@ -26,13 +28,20 @@ public:
LPECopyRotate(LivePathEffectObject *lpeobject);
virtual ~LPECopyRotate();
virtual void doOnApply (SPLPEItem const* lpeitem);
+ virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
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 doAfterEffect (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);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
virtual Gtk::Widget * newWidget();
+ void toItem(Geom::Affine transform, size_t i, bool reset);
+ void cloneD(SPObject *origin, SPObject *dest, bool root, bool reset);
+ void resetStyles();
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
@@ -42,9 +51,11 @@ private:
ScalarParam starting_angle;
ScalarParam rotation_angle;
ScalarParam num_copies;
+ ScalarParam split_gap;
BoolParam copies_to_360;
BoolParam fuse_paths;
BoolParam join_paths;
+ BoolParam split_items;
Geom::Point A;
Geom::Point B;
Geom::Point dir;
@@ -52,6 +63,9 @@ private:
Geom::Point rot_pos;
Geom::Point previous_start_point;
double dist_angle_handle;
+ double previous_num_copies;
+ bool reset;
+ SPObject * container;
LPECopyRotate(const LPECopyRotate&);
LPECopyRotate& operator=(const LPECopyRotate&);
};
diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp
index af2a8e919..ef87be81c 100644
--- a/src/live_effects/lpe-measure-line.cpp
+++ b/src/live_effects/lpe-measure-line.cpp
@@ -21,7 +21,9 @@
#include "svg/svg-color.h"
#include "svg/svg.h"
#include "display/curve.h"
+#include "helper/geom.h"
#include "2geom/affine.h"
+#include "path-chemistry.h"
#include "style.h"
#include "sp-root.h"
#include "sp-defs.h"
@@ -165,12 +167,6 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
LPEMeasureLine::~LPEMeasureLine() {}
-void swap(Geom::Point &A, Geom::Point &B){
- Geom::Point tmp = A;
- A = B;
- B = tmp;
-}
-
void
LPEMeasureLine::createArrowMarker(const char * mode)
{
@@ -229,7 +225,7 @@ LPEMeasureLine::createArrowMarker(const char * mode)
elemref = SP_OBJECT(document->getDefs()->appendChildRepr(arrow));
Inkscape::GC::release(arrow);
}
- elements.push_back(mode);
+ items.push_back(mode);
}
void
@@ -369,7 +365,7 @@ LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angl
copy->setAttribute("id", id);
elemref = elemref_copy;
}
- elements.push_back(id);
+ items.push_back(id);
Geom::OptRect bounds = SP_ITEM(elemref)->bounds(SPItem::GEOMETRIC_BBOX);
if (bounds) {
anotation_width = bounds->width() * 1.4;
@@ -483,7 +479,7 @@ LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, const char * id, b
elemref->deleteObject();
copy->setAttribute("id", id);
}
- elements.push_back(id);
+ items.push_back(id);
}
void
@@ -535,7 +531,7 @@ LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem)
sp_lpe_item->getCurrentLPE() != this){
return;
}
- elements.clear();
+ items.clear();
start_stored = start;
end_stored = end;
Geom::Point hstart = start;
@@ -680,60 +676,12 @@ LPEMeasureLine::doOnRemove (SPLPEItem const* /*lpeitem*/)
//unset "erase_extra_objects" hook on sp-lpe-item.cpp
if (!erase_extra_objects) {
processObjects(LPE_TO_OBJECTS);
- elements.clear();
+ items.clear();
return;
}
processObjects(LPE_ERASE);
}
-void
-LPEMeasureLine::processObjects(LpeAction lpe_action)
-{
- SPDocument * document = SP_ACTIVE_DOCUMENT;
- for (std::vector<const char *>::iterator el_it = elements.begin();
- el_it != elements.end(); ++el_it) {
- const char * id = *el_it;
- if (!id || strlen(id) == 0) {
- return;
- }
- SPObject *elemref = NULL;
- if (elemref = document->getObjectById(id)) {
- SPCSSAttr *css;
- Glib::ustring css_str;
- switch (lpe_action){
- case LPE_TO_OBJECTS:
- elemref->getRepr()->setAttribute("inkscape:path-effect", NULL);
- elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
- break;
-
- case LPE_ERASE:
- if (std::strcmp(elemref->getId(),id_origin.param_getSVGValue()) != 0) {
- elemref->deleteObject();
- }
- break;
-
- case LPE_VISIBILITY:
- css = sp_repr_css_attr_new();
- sp_repr_css_attr_add_from_string(css, elemref->getRepr()->attribute("style"));
- if (!this->isVisible() && std::strcmp(elemref->getId(),id_origin.param_getSVGValue()) != 0) {
- css->setAttribute("display", "none");
- } else {
- css->setAttribute("display", NULL);
- }
- sp_repr_css_write_string(css,css_str);
- elemref->getRepr()->setAttribute("style", css_str.c_str());
- break;
-
- default:
- break;
- }
- }
- }
- if (lpe_action == LPE_ERASE) {
- elements.clear();
- }
-}
-
Gtk::Widget *LPEMeasureLine::newWidget()
{
// use manage here, because after deletion of Effect object, others might
diff --git a/src/live_effects/lpe-measure-line.h b/src/live_effects/lpe-measure-line.h
index c69921a4d..724c0d924 100644
--- a/src/live_effects/lpe-measure-line.h
+++ b/src/live_effects/lpe-measure-line.h
@@ -35,12 +35,6 @@ enum OrientationMethod {
OM_END
};
-enum LpeAction {
- LPE_ERASE = 0,
- LPE_TO_OBJECTS,
- LPE_VISIBILITY
-};
-
class LPEMeasureLine : public Effect {
public:
LPEMeasureLine(LivePathEffectObject *lpeobject);
@@ -51,7 +45,6 @@ public:
virtual void doEffect (SPCurve * curve){}; //stop the chain
virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
- void processObjects(LpeAction lpe_action);
void createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows = false);
void createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid);
void onExpanderChanged();
@@ -92,7 +85,6 @@ private:
double arrow_gap;
Geom::Point start_stored;
Geom::Point end_stored;
- std::vector<const char *> elements;
/* Geom::Affine affine_over;*/
LPEMeasureLine(const LPEMeasureLine &);
LPEMeasureLine &operator=(const LPEMeasureLine &);
diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp
index 61b2b8b5c..7f0a93c52 100644
--- a/src/live_effects/lpe-mirror_symmetry.cpp
+++ b/src/live_effects/lpe-mirror_symmetry.cpp
@@ -15,11 +15,22 @@
*/
#include <gtkmm.h>
+#include "live_effects/lpeobject.h"
+#include "live_effects/lpeobject-reference.h"
#include "live_effects/lpe-mirror_symmetry.h"
-#include <display/curve.h>
-#include <svg/path-string.h>
+#include "display/curve.h"
+#include "svg/path-string.h"
+#include "svg/svg.h"
+#include "sp-defs.h"
#include "helper/geom.h"
-#include <2geom/path-intersection.h>
+#include "2geom/intersection-graph.h"
+#include "2geom/path-intersection.h"
+#include "2geom/affine.h"
+#include "helper/geom.h"
+#include "sp-lpe-item.h"
+#include "path-chemistry.h"
+#include "style.h"
+#include "xml/sp-css-attr.h"
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
@@ -40,73 +51,69 @@ MTConverter(ModeTypeData, MT_END);
LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
mode(_("Mode"), _("Symmetry move mode"), "mode", MTConverter, &wr, this, MT_FREE),
+ split_gap(_("Gap on split"), _("Gap on split"), "split_gap", &wr, this, -0.001),
discard_orig_path(_("Discard original path"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false),
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),
+ split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false),
start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, _("Adjust start of mirroring")),
end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, _("Adjust end of mirroring")),
- center_point(_("Center mirror line"), _("Center mirror line"), "center_point", &wr, this, _("Adjust center of mirroring"))
+ center_point(_("Center mirror line"), _("Center mirror line"), "center_point", &wr, this, _("Adjust center of mirroring")),
+ id_origin("id origin", "store the id of the first LPEItem", "id_origin", &wr, this,"")
{
show_orig_path = true;
registerParameter(&mode);
- registerParameter( &discard_orig_path);
- registerParameter( &fuse_paths);
- registerParameter( &oposite_fuse);
- registerParameter( &start_point);
- registerParameter( &end_point);
- registerParameter( &center_point);
- previous_center = Geom::Point(0,0);
+ registerParameter(&split_gap);
+ registerParameter(&discard_orig_path);
+ registerParameter(&fuse_paths);
+ registerParameter(&oposite_fuse);
+ registerParameter(&split_items);
+ registerParameter(&start_point);
+ registerParameter(&end_point);
+ registerParameter(&center_point);
+ registerParameter(&id_origin);
+ id_origin.param_hide_canvas_text();
+ split_gap.param_set_range(-999999.0, 999999.0);
+ split_gap.param_set_increments(0.1, 0.1);
+ split_gap.param_set_digits(5);
apply_to_clippath_and_mask = true;
+ previous_center = Geom::Point(0,0);
}
LPEMirrorSymmetry::~LPEMirrorSymmetry()
{
}
-Gtk::Widget * LPEMirrorSymmetry::newWidget()
+void
+LPEMirrorSymmetry::doAfterEffect (SPLPEItem const* lpeitem)
{
- // use manage here, because after deletion of Effect object, others might
- // still be pointing to this widget.
- Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
-
- vbox->set_border_width(5);
- vbox->set_homogeneous(false);
- vbox->set_spacing(2);
-
- std::vector<Parameter *>::iterator it = param_vector.begin();
- while (it != param_vector.end()) {
- if ((*it)->widget_is_visible) {
- Parameter *param = *it;
- Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
- Glib::ustring *tip = param->param_getTooltip();
- if (widg) {
- if (param->param_key != "center_point") {
- vbox->pack_start(*widg, true, true, 2);
- if (tip) {
- widg->set_tooltip_text(*tip);
- } else {
- widg->set_tooltip_text("");
- widg->set_has_tooltip(false);
- }
- }
- }
+ if (split_items && !discard_orig_path) {
+ container = dynamic_cast<SPObject *>(sp_lpe_item->parent);
+ SPDocument * doc = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Node *root = sp_lpe_item->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = doc->getReprRoot();
+ if (root_origin != root) {
+ return;
}
-
- ++it;
+ Geom::Line ls((Geom::Point)start_point, (Geom::Point)end_point);
+ Geom::Affine m = Geom::reflection (ls.vector(), (Geom::Point)start_point);
+ m = m * sp_lpe_item->transform;
+ toMirror(m);
+ } else {
+ processObjects(LPE_ERASE);
+ items.clear();
}
- return dynamic_cast<Gtk::Widget *>(vbox);
}
-
void
LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
{
+
using namespace Geom;
original_bbox(lpeitem);
//center_point->param_set_liveupdate(false);
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]);
@@ -173,6 +180,172 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
}
void
+LPEMirrorSymmetry::cloneD(SPObject *origin, SPObject *dest, bool live, bool root)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ if ( SP_IS_GROUP(origin) && SP_IS_GROUP(dest) && SP_GROUP(origin)->getItemCount() == SP_GROUP(dest)->getItemCount() ) {
+ std::vector< SPObject * > childs = origin->childList(true);
+ size_t index = 0;
+ for (std::vector<SPObject * >::iterator obj_it = childs.begin();
+ obj_it != childs.end(); ++obj_it) {
+ SPObject *dest_child = dest->nthChild(index);
+ cloneD(*obj_it, dest_child, live, false);
+ index++;
+ }
+ }
+ SPShape * shape = SP_SHAPE(origin);
+ SPPath * path = SP_PATH(dest);
+ if (!path && !SP_IS_GROUP(dest)) {
+ Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0);
+ dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL);
+ path = SP_PATH(dest);
+ }
+ if (path && shape) {
+ if ( live) {
+ SPCurve *c = NULL;
+ if (root) {
+ c = new SPCurve();
+ c->set_pathvector(pathvector_before_effect);
+ } else {
+ c = shape->getCurve();
+ }
+ if (c) {
+ path->setCurve(c, TRUE);
+ c->unref();
+ } else {
+ dest->getRepr()->setAttribute("d", NULL);
+ }
+ } else {
+ dest->getRepr()->setAttribute("d", origin->getRepr()->attribute("d"));
+ }
+ }
+}
+
+void
+LPEMirrorSymmetry::toMirror(Geom::Affine transform)
+{
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ const char * id_origin_char = id_origin.param_getSVGValue();
+ const char * elemref_id = g_strdup(Glib::ustring("mirror-").append(id_origin_char).c_str());
+ items.clear();
+ items.push_back(elemref_id);
+ SPObject *elemref= NULL;
+ Inkscape::XML::Node *phantom = NULL;
+ if (elemref = document->getObjectById(elemref_id)) {
+ phantom = elemref->getRepr();
+ } else {
+ phantom = sp_lpe_item->getRepr()->duplicate(xml_doc);
+ std::vector<const char *> attrs;
+ attrs.push_back("inkscape:path-effect");
+ attrs.push_back("inkscape:original-d");
+ attrs.push_back("sodipodi:type");
+ attrs.push_back("sodipodi:rx");
+ attrs.push_back("sodipodi:ry");
+ attrs.push_back("sodipodi:cx");
+ attrs.push_back("sodipodi:cy");
+ attrs.push_back("sodipodi:end");
+ attrs.push_back("sodipodi:start");
+ attrs.push_back("inkscape:flatsided");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:rounded");
+ attrs.push_back("sodipodi:arg1");
+ attrs.push_back("sodipodi:arg2");
+ attrs.push_back("sodipodi:r1");
+ attrs.push_back("sodipodi:r2");
+ attrs.push_back("sodipodi:sides");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("sodipodi:argument");
+ attrs.push_back("sodipodi:expansion");
+ attrs.push_back("sodipodi:radius");
+ attrs.push_back("sodipodi:revolution");
+ attrs.push_back("sodipodi:t0");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("inkscape:randomized");
+ attrs.push_back("x");
+ attrs.push_back("y");
+ attrs.push_back("rx");
+ attrs.push_back("ry");
+ attrs.push_back("width");
+ attrs.push_back("height");
+ for(const char * attr : attrs) {
+ phantom->setAttribute(attr, NULL);
+ }
+ }
+ phantom->setAttribute("id", elemref_id);
+ if (!elemref) {
+ elemref = container->appendChildRepr(phantom);
+ Inkscape::GC::release(phantom);
+ }
+ cloneD(SP_OBJECT(sp_lpe_item), elemref, true, true);
+ elemref->getRepr()->setAttribute("transform" , sp_svg_transform_write(transform));
+ if (elemref->parent != container) {
+ Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
+ copy->setAttribute("id", elemref_id);
+ container->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ }
+}
+
+Gtk::Widget *
+LPEMirrorSymmetry::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter * param = *it;
+ if (param->param_key == "id_origin" || param->param_key == "center_point") {
+ ++it;
+ continue;
+ }
+ Gtk::Widget * widg = param->param_newWidget();
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ this->upd_params = false;
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+//TODO: Migrate the tree next function to effect.cpp/h to avoid duplication
+void
+LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+{
+ processObjects(LPE_VISIBILITY);
+}
+
+void
+LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ //unset "erase_extra_objects" hook on sp-lpe-item.cpp
+ if (!erase_extra_objects) {
+ processObjects(LPE_TO_OBJECTS);
+ return;
+ }
+ processObjects(LPE_ERASE);
+}
+
+void
LPEMirrorSymmetry::transform_multiply(Geom::Affine const& postmul, bool set)
{
// cycle through all parameters. Most parameters will not need transformation, but path and point params do.
@@ -193,18 +366,26 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* 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, true);
+ start_point.param_setValue(point_a);
start_point.param_update_default(point_a);
- end_point.param_setValue(point_b, true);
+ end_point.param_setValue(point_b);
end_point.param_update_default(point_b);
center_point.param_setValue(point_c, true);
previous_center = center_point;
+ SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem);
+ if (!lpeitem->hasPathEffectOfType(this->effectType(), false) ){ //first applied not ready yet
+ id_origin.param_setValue(lpeitem->getRepr()->attribute("id"));
+ id_origin.write_to_SVG();
+ }
}
Geom::PathVector
LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
{
+ if (split_items && !fuse_paths) {
+ return path_in;
+ }
Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
Geom::PathVector path_out;
@@ -214,15 +395,51 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point);
Geom::Affine m = Geom::reflection (line_separation.vector(), (Geom::Point)start_point);
-
- if (fuse_paths && !discard_orig_path) {
+ if (split_items && fuse_paths) {
+ Geom::OptRect bbox = sp_lpe_item->geometricBounds();
+ Geom::Path p(Geom::Point(bbox->left(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top()));
+ p.close();
+ p *= Geom::Translate(bbox->midpoint()).inverse();
+ p *= Geom::Scale(1.2);
+ p *= Geom::Rotate(line_separation.angle());
+ p *= Geom::Translate(bbox->midpoint());
+ bbox = p.boundsFast();
+ p.clear();
+ p.start(Geom::Point(bbox->left(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->top()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->right(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->bottom()));
+ p.appendNew<Geom::LineSegment>(Geom::Point(bbox->left(), bbox->top()));
+ p.close();
+ p *= Geom::Translate(bbox->midpoint()).inverse();
+ p *= Geom::Rotate(line_separation.angle());
+ p *= Geom::Translate(bbox->midpoint());
+ Geom::Point base(p.pointAt(3));
+ if (oposite_fuse) {
+ base = p.pointAt(0);
+ }
+ p *= Geom::Translate(line_separation.pointAt(line_separation.nearestTime(base)) - base);
+ Geom::PathVector pv_bbox;
+ pv_bbox.push_back(p);
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(pv_bbox, original_pathv);
+ if (pig && !original_pathv.empty() && !pv_bbox.empty()) {
+ path_out = pig->getBminusA();
+ }
+ Geom::Point dir = rot90(unit_vector((Geom::Point)end_point - (Geom::Point)start_point));
+ Geom::Point gap = dir * split_gap;
+ path_out *= Geom::Translate(gap);
+ } else 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;
+ Geom::PathVector tmp_pathvector;
double time_start = 0.0;
int position = 0;
bool end_open = false;
@@ -268,11 +485,11 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
Geom::Path mirror = portion.reversed() * m;
mirror.setInitial(portion.finalPoint());
portion.append(mirror);
- if(i!=0) {
+ if(i != 0) {
portion.setFinal(portion.initialPoint());
portion.close();
}
- tmp_path.push_back(portion);
+ tmp_pathvector.push_back(portion);
}
portion.clear();
}
@@ -293,36 +510,33 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
portion.append(mirror);
portion = portion.reversed();
if (!original.closed()) {
- tmp_path.push_back(portion);
+ tmp_pathvector.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);
+ if (cs.size() > 1 && tmp_pathvector.size() > 0 && tmp_pathvector[0].size() > 0 ) {
+ portion.setFinal(tmp_pathvector[0].initialPoint());
+ portion.setInitial(tmp_pathvector[0].finalPoint());
+ tmp_pathvector[0].append(portion);
} else {
- tmp_path.push_back(portion);
+ tmp_pathvector.push_back(portion);
}
- tmp_path[0].close();
+ tmp_pathvector[0].close();
}
portion.clear();
}
}
}
if (cs.size() == 0 && position == 1) {
- tmp_path.push_back(original);
- tmp_path.push_back(original * m);
+ tmp_pathvector.push_back(original);
+ tmp_pathvector.push_back(original * m);
}
- path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end());
- tmp_path.clear();
+ path_out.insert(path_out.end(), tmp_pathvector.begin(), tmp_pathvector.end());
+ tmp_pathvector.clear();
}
- }
-
- if (!fuse_paths || discard_orig_path) {
+ } else if (!fuse_paths || discard_orig_path) {
for (size_t i = 0; i < original_pathv.size(); ++i) {
path_out.push_back(original_pathv[i] * m);
}
}
-
return path_out;
}
diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h
index b4967173a..592a11894 100644
--- a/src/live_effects/lpe-mirror_symmetry.h
+++ b/src/live_effects/lpe-mirror_symmetry.h
@@ -18,8 +18,8 @@
#include "live_effects/effect.h"
#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/text.h"
#include "live_effects/parameter/point.h"
-#include "live_effects/parameter/path.h"
#include "live_effects/parameter/enum.h"
#include "live_effects/lpegroupbbox.h"
@@ -41,23 +41,32 @@ public:
virtual ~LPEMirrorSymmetry();
virtual void doOnApply (SPLPEItem const* lpeitem);
virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+ virtual void doAfterEffect (SPLPEItem const* lpeitem);
virtual void transform_multiply(Geom::Affine const& postmul, bool set);
virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
virtual Gtk::Widget * newWidget();
+ void toMirror(Geom::Affine transform);
+ // void cloneAttrbutes(Inkscape::XML::Node * origin, Inkscape::XML::Node * dest, const char * first_attribute, ...);
+ void cloneD(SPObject *origin, SPObject *dest, bool live, bool root);
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
private:
EnumParam<ModeType> mode;
+ ScalarParam split_gap;
BoolParam discard_orig_path;
BoolParam fuse_paths;
BoolParam oposite_fuse;
+ BoolParam split_items;
PointParam start_point;
PointParam end_point;
PointParam center_point;
+ TextParam id_origin;
Geom::Point previous_center;
-
+ SPObject * container;
LPEMirrorSymmetry(const LPEMirrorSymmetry&);
LPEMirrorSymmetry& operator=(const LPEMirrorSymmetry&);
};
diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp
index af99ef362..813c06b4e 100644
--- a/src/live_effects/parameter/bool.cpp
+++ b/src/live_effects/parameter/bool.cpp
@@ -72,7 +72,7 @@ BoolParam::param_newWidget()
checkwdg->setActive(value);
checkwdg->setProgrammatically = false;
checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter"));
-
+ param_effect->upd_params = false;
return dynamic_cast<Gtk::Widget *> (checkwdg);
} else {
return NULL;
@@ -82,6 +82,7 @@ BoolParam::param_newWidget()
void
BoolParam::param_setValue(bool newvalue)
{
+ param_effect->upd_params = true;
value = newvalue;
}
diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp
index 8cab68ad0..5c4cdf4c6 100644
--- a/src/live_effects/parameter/text.cpp
+++ b/src/live_effects/parameter/text.cpp
@@ -125,13 +125,14 @@ TextParam::param_newWidget()
rsu->setProgrammatically = false;
rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change text parameter"));
-
+ param_effect->upd_params = false;
return dynamic_cast<Gtk::Widget *> (rsu);
}
void
TextParam::param_setValue(const Glib::ustring newvalue)
{
+ param_effect->upd_params = true;
value = newvalue;
if (!_hide_canvas_text) {
sp_canvastext_set_text (canvas_text, newvalue.c_str());
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index 7b2507b5e..f2c0d2f2c 100644
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
@@ -925,6 +925,15 @@ void SPGroup::update_patheffect(bool write) {
}
sp_group_perform_patheffect(this, this, write);
+
+ for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it)
+ {
+ LivePathEffectObject *lpeobj = (*it)->lpeobject;
+
+ if (lpeobj && lpeobj->get_lpe()) {
+ lpeobj->get_lpe()->doAfterEffect(this);
+ }
+ }
}
}
@@ -950,25 +959,35 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write)
} else {
c = subShape->getCurve();
}
-
+ bool success = false;
// only run LPEs when the shape has a curve defined
if (c) {
c->transform(i2anc_affine(subitem, topgroup));
- topgroup->performPathEffect(c);
+ success = topgroup->performPathEffect(c, subShape);
c->transform(i2anc_affine(subitem, topgroup).inverse());
- subShape->setCurve(c, TRUE);
-
- if (write) {
- Inkscape::XML::Node *repr = subitem->getRepr();
- gchar *str = sp_svg_write_path(c->get_pathvector());
- repr->setAttribute("d", str);
+ Inkscape::XML::Node *repr = subitem->getRepr();
+ if (c && success) {
+ subShape->setCurve(c, TRUE);
+ if (write) {
+ gchar *str = sp_svg_write_path(c->get_pathvector());
+ repr->setAttribute("d", str);
#ifdef GROUP_VERBOSE
- g_message("sp_group_perform_patheffect writes 'd' attribute");
+ g_message("sp_group_perform_patheffect writes 'd' attribute");
#endif
- g_free(str);
+ g_free(str);
+ }
+ c->unref();
+ } else {
+ // LPE was unsuccesfull or doeffect stack return null. Read the old 'd'-attribute.
+ if (gchar const * value = repr->attribute("d")) {
+ Geom::PathVector pv = sp_svg_read_pathv(value);
+ SPCurve *oldcurve = new (std::nothrow) SPCurve(pv);
+ if (oldcurve) {
+ subShape->setCurve(oldcurve, TRUE);
+ oldcurve->unref();
+ }
+ }
}
-
- c->unref();
}
}
}
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index e2f61bfb5..00671b936 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -24,6 +24,8 @@
#include "live_effects/lpeobject.h"
#include "live_effects/lpeobject-reference.h"
#include "live_effects/lpe-measure-line.h"
+#include "live_effects/lpe-mirror_symmetry.h"
+#include "live_effects/lpe-copy_rotate.h"
#include "sp-path.h"
#include "sp-item-group.h"
@@ -126,7 +128,10 @@ void SPLPEItem::set(unsigned int key, gchar const* value) {
if (!value) {
LivePathEffectObject *lpeobj = (*it)->lpeobject;
Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe();
- if (dynamic_cast<Inkscape::LivePathEffect::LPEMeasureLine *>(lpe)){
+ if (dynamic_cast<Inkscape::LivePathEffect::LPEMirrorSymmetry *>(lpe) ||
+ dynamic_cast<Inkscape::LivePathEffect::LPEMeasureLine *>(lpe) ||
+ dynamic_cast<Inkscape::LivePathEffect::LPECopyRotate *>(lpe) )
+ {
lpe->doOnRemove(this);
}
}
@@ -209,7 +214,7 @@ Inkscape::XML::Node* SPLPEItem::write(Inkscape::XML::Document *xml_doc, Inkscape
/**
* returns true when LPE was successful.
*/
-bool SPLPEItem::performPathEffect(SPCurve *curve, bool is_clip_or_mask) {
+bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip_or_mask) {
if (!curve) {
return false;
@@ -241,12 +246,15 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool is_clip_or_mask) {
}
if (!is_clip_or_mask || (is_clip_or_mask && lpe->apply_to_clippath_and_mask)) {
// Groups have their doBeforeEffect called elsewhere
+ if (current) {
+ lpe->setCurrentShape(current);
+ }
if (!SP_IS_GROUP(this)) {
lpe->doBeforeEffect_impl(this);
}
try {
- lpe->doEffect(curve);
+ lpe->doEffect(curve);
}
catch (std::exception & e) {
g_warning("Exception during LPE %s execution. \n %s", lpe->getName().c_str(), e.what());
@@ -257,6 +265,8 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool is_clip_or_mask) {
return false;
}
if (!SP_IS_GROUP(this)) {
+ lpe->pathvector_before_effect = curve->get_pathvector();
+ lpe->sp_curve->set_pathvector(lpe->pathvector_before_effect);
lpe->doAfterEffect(this);
}
}
@@ -604,7 +614,7 @@ bool SPLPEItem::hasPathEffect() const
return true;
}
-bool SPLPEItem::hasPathEffectOfType(int const type) const
+bool SPLPEItem::hasPathEffectOfType(int const type, bool is_ready) const
{
if (path_effect_list->empty()) {
return false;
@@ -616,7 +626,9 @@ bool SPLPEItem::hasPathEffectOfType(int const type) const
if (lpeobj) {
Inkscape::LivePathEffect::Effect const* lpe = lpeobj->get_lpe();
if (lpe && (lpe->effectType() == type)) {
- return true;
+ if (is_ready || lpe->isReady()) {
+ return true;
+ }
}
}
}
@@ -695,10 +707,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, true);
+ success = this->performPathEffect(c, SP_SHAPE(clip_mask), true);
c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse());
} else {
- success = this->performPathEffect(c, true);
+ success = this->performPathEffect(c, SP_SHAPE(clip_mask), true);
}
} catch (std::exception & e) {
g_warning("Exception during LPE execution. \n %s", e.what());
@@ -709,12 +721,13 @@ SPLPEItem::apply_to_clip_or_mask(SPItem *clip_mask, SPItem *item)
success = false;
}
Inkscape::XML::Node *repr = clip_mask->getRepr();
- if (success) {
+ // This c check allow to not apply LPE if curve is NULL after performPathEffect used in clone.obgets LPE
+ if (success && c) {
gchar *str = sp_svg_write_path(c->get_pathvector());
repr->setAttribute("d", str);
g_free(str);
} else {
- // LPE was unsuccesfull. Read the old 'd'-attribute.
+ // LPE was unsuccesfull or doeffect stack return null.. Read the old 'd'-attribute.
if (gchar const * value = repr->attribute("d")) {
Geom::PathVector pv = sp_svg_read_pathv(value);
SPCurve *oldcurve = new (std::nothrow) SPCurve(pv);
@@ -724,7 +737,9 @@ SPLPEItem::apply_to_clip_or_mask(SPItem *clip_mask, SPItem *item)
}
}
}
- c->unref();
+ if (c) {
+ c->unref();
+ }
}
}
}
diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h
index 9e5cb3329..0f198c49c 100644
--- a/src/sp-lpe-item.h
+++ b/src/sp-lpe-item.h
@@ -23,6 +23,7 @@
class LivePathEffectObject;
class SPCurve;
+class SPShape;
class SPDesktop;
namespace Inkscape{
@@ -69,11 +70,11 @@ public:
virtual void update_patheffect(bool write);
- bool performPathEffect(SPCurve *curve, bool is_clip_or_mask = false);
+ bool performPathEffect(SPCurve *curve, SPShape *current = NULL, bool is_clip_or_mask = false);
bool pathEffectsEnabled() const;
bool hasPathEffect() const;
- bool hasPathEffectOfType(int const type) const;
+ bool hasPathEffectOfType(int const type, bool is_ready = true) const;
bool hasPathEffectRecursive() const;
Inkscape::LivePathEffect::Effect* getPathEffectOfType(int type);
Inkscape::LivePathEffect::Effect const* getPathEffectOfType(int type) const;
diff --git a/src/sp-object.cpp b/src/sp-object.cpp
index 75f4657ef..0dc301c49 100644
--- a/src/sp-object.cpp
+++ b/src/sp-object.cpp
@@ -775,6 +775,21 @@ void SPObject::appendChild(Inkscape::XML::Node *child) {
repr->appendChild(child);
}
+SPObject* SPObject::nthChild(unsigned index) {
+ g_assert(this->repr);
+ if (hasChildren()) {
+ std::vector<SPObject*> l;
+ unsigned counter = 0;
+ for (auto& child: children) {
+ if (counter == index) {
+ return &child;
+ }
+ counter++;
+ }
+ }
+ return NULL;
+}
+
void SPObject::addChild(Inkscape::XML::Node *child, Inkscape::XML::Node * prev)
{
g_assert(this->repr);
diff --git a/src/sp-object.h b/src/sp-object.h
index 9abbd324b..d145e966b 100644
--- a/src/sp-object.h
+++ b/src/sp-object.h
@@ -318,6 +318,9 @@ public:
SPObject *lastChild() { return children.empty() ? nullptr : &children.back(); }
SPObject const *lastChild() const { return children.empty() ? nullptr : &children.back(); }
+ SPObject *nthChild(unsigned index);
+ SPObject const *nthChild(unsigned index) const;
+
enum Action { ActionGeneral, ActionBBox, ActionUpdate, ActionShow };
/**
diff --git a/src/sp-path.cpp b/src/sp-path.cpp
index 6c69f3463..b593b7937 100644
--- a/src/sp-path.cpp
+++ b/src/sp-path.cpp
@@ -289,23 +289,10 @@ Geom::Affine SPPath::set_transform(Geom::Affine const &transform) {
if (!_curve) { // 0 nodes, nothing to transform
return Geom::identity();
}
- // Adjust stroke
- this->adjust_stroke(transform.descrim());
-
- // Adjust pattern fill
- this->adjust_pattern(transform);
-
- // Adjust gradient fill
- this->adjust_gradient(transform);
-
- // Adjust LPE
- this->adjust_livepatheffect(transform);
// Transform the original-d path if this is a valid LPE this, other else the (ordinary) path
if (_curve_before_lpe && hasPathEffectRecursive()) {
- if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL) ||
- this->hasPathEffectOfType(Inkscape::LivePathEffect::BEND_PATH))
- {
+ if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL) || this->hasPathEffectOfType(Inkscape::LivePathEffect::BEND_PATH)) {
// if path has the CLONE_ORIGINAL LPE applied, don't write the transform to the pathdata, but write it 'unoptimized'
// also if the effect is type BEND PATH to fix bug #179842
return transform;
@@ -316,6 +303,18 @@ Geom::Affine SPPath::set_transform(Geom::Affine const &transform) {
_curve->transform(transform);
}
+ // Adjust stroke
+ this->adjust_stroke(transform.descrim());
+
+ // Adjust pattern fill
+ this->adjust_pattern(transform);
+
+ // Adjust gradient fill
+ this->adjust_gradient(transform);
+
+ // Adjust LPE
+ this->adjust_livepatheffect(transform);
+
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
// nothing remains - we've written all of the transform, so return identity
@@ -355,9 +354,9 @@ g_message("sp_path_update_patheffect writes 'd' attribute");
if (gchar const * value = repr->attribute("d")) {
Geom::PathVector pv = sp_svg_read_pathv(value);
SPCurve *oldcurve = new SPCurve(pv);
+
if (oldcurve) {
- this->setCurveInsync(oldcurve, TRUE);
- repr->setAttribute("d", value);
+ this->setCurve(oldcurve, TRUE);
oldcurve->unref();
}
}
diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp
index c51881a96..9485b6ba3 100644
--- a/src/ui/dialog/polar-arrange-tab.cpp
+++ b/src/ui/dialog/polar-arrange-tab.cpp
@@ -43,14 +43,14 @@ PolarArrangeTab::PolarArrangeTab(ArrangeDialog *parent_)
anchorPointLabel.set_alignment(Gtk::ALIGN_START);
pack_start(anchorPointLabel, false, false);
- anchorBoundingBoxRadio.set_label(C_("Polar arrange tab", "Object's bounding box:"));
+ anchorBoundingBoxRadio.set_label(C_("Polar arrange tab", "Objects' bounding boxes:"));
anchorRadioGroup = anchorBoundingBoxRadio.get_group();
anchorBoundingBoxRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_anchor_radio_changed));
pack_start(anchorBoundingBoxRadio, false, false);
pack_start(anchorSelector, false, false);
- anchorObjectPivotRadio.set_label(C_("Polar arrange tab", "Object's rotational center"));
+ anchorObjectPivotRadio.set_label(C_("Polar arrange tab", "Objects' rotational centers"));
anchorObjectPivotRadio.set_group(anchorRadioGroup);
anchorObjectPivotRadio.signal_toggled().connect(sigc::mem_fun(*this, &PolarArrangeTab::on_anchor_radio_changed));
pack_start(anchorObjectPivotRadio, false, false);