Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-mirror_symmetry.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/*
6 * Authors:
7 * Maximilian Albert
8 * Johan Engelen
9 * Abhishek Sharma
10 * Jabiertxof
11 *
12 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
13 * Copyright (C) Maximilin Albert 2008 <maximilian.albert@gmail.com>
14 *
15 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
16 */
17
19
20#include <glibmm/i18n.h>
21#include <gtkmm/box.h>
22#include <gtkmm/button.h>
23
24#include "path-chemistry.h"
25#include "style.h"
26
27#include <2geom/affine.h>
29#include <2geom/rect.h>
30
31#include "display/curve.h"
32#include "helper/geom.h"
34#include "object/sp-lpe-item.h"
35#include "object/sp-path.h"
36#include "object/sp-page.h"
37#include "object/sp-text.h"
38#include "path/path-boolop.h"
39#include "svg/svg.h"
40#include "ui/pack.h"
41#include "page-manager.h"
42
43namespace Inkscape {
44namespace LivePathEffect {
45
47 { MT_V, N_("Vertical page center"), "vertical" },
48 { MT_H, N_("Horizontal page center"), "horizontal" },
49 { MT_FREE, N_("Freely defined mirror line"), "free" },
50 { MT_X, N_("X coordinate of mirror line midpoint"), "X" },
51 { MT_Y, N_("Y coordinate of mirror line midpoint"), "Y" }
52};
55
56
58 Effect(lpeobject),
59 // do not change name of this parameter us used in oncommit
60 lpesatellites(_("lpesatellites"), _("Items satellites"), "lpesatellites", &wr, this, false),
61 mode(_("Mode"), _("Set mode of transformation. Either freely defined by mirror line or constrained to certain symmetry points."), "mode", MTConverter, &wr, this, MT_FREE),
62 discard_orig_path(_("Discard original path"), _("Only keep mirrored part of the path, remove the original."), "discard_orig_path", &wr, this, false),
63 fuse_paths(_("Fuse paths"), _("Fuse original path and mirror image into a single path"), "fuse_paths", &wr, this, false),
64 oposite_fuse(_("Fuse opposite sides"), _("Picks the part on the other side of the mirror line as the original."), "oposite_fuse", &wr, this, false),
65 split_items(_("Split elements"), _("Split original and mirror image into separate paths, so each can have its own style."), "split_items", &wr, this, false),
66 split_open(_("Keep open paths on split"), _("Do not automatically close paths along the split line."), "split_open", &wr, this, false),
67 start_point(_("Mirror line start"), _("Start point of mirror line"), "start_point", &wr, this, _("Adjust start point of mirror line")),
68 end_point(_("Mirror line end"), _("End point of mirror line"), "end_point", &wr, this, _("Adjust end point of mirror line")),
69 center_point(_("Mirror line mid"), _("Center point of mirror line"), "center_point", &wr, this, _("Adjust center point of mirror line")),
70 link_styles(_("Link styles"), _("Link styles on split mode"), "link_styles", &wr, this, false)
71{
83 show_orig_path = true;
88 center_horiz = false;
89 center_vert = false;
91}
92
94
96{
97 bool fixed = false;
98 if (!is_load || is_applied || !split_items) {
99 return fixed;
100 }
101
102 Glib::ustring version = lpeversion.param_getSVGValue();
103 if (version < "1.2") {
105 Glib::ustring id = Glib::ustring("mirror-");
106 id += getLPEObj()->getId();
107 SPObject *elemref = getSPDoc()->getObjectById(id.c_str());
108 if (elemref) {
109 lpesatellites.link(elemref, 0);
110 }
111 lpeversion.param_setValue("1.2", true);
112 fixed = true;
114 }
117 container = lpeitem->parent;
118 return fixed;
119}
120
121void
123{
124 SPDocument *document = getSPDoc();
125 if (!document) {
126 return;
127 }
129
131 bool active = !lpesatellites.data().size() || is_load;
132 for (auto lpereference : lpesatellites.data()) {
133 if (lpereference && lpereference->isAttached() && lpereference.get()->getObject() != nullptr) {
134 active = true;
135 }
136 }
137 // we need to call this when the LPE is "mirrored 1 or + times in split mode"
138 // to prevent satellite hidden as in prev status
139 if (!active && !is_load && prev_split && !prev_discard_orig_path) {
141 return;
142 }
146 toMirror(m);
147 }
150}
151
152Gtk::Widget *
154{
155 // use manage here, because after deletion of Effect object, others might
156 // still be pointing to this widget.
157 auto const vbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 2);
158 vbox->set_margin(5);
159
160 std::vector<Parameter *>::iterator it = param_vector.begin();
161 while (it != param_vector.end()) {
162 if ((*it)->widget_is_visible) {
163 Parameter *param = *it;
164 auto const widg = param->param_newWidget();
165
166 if (widg && param->param_key != "split_open") {
167 UI::pack_start(*vbox, *widg, true, true, 2);
168
169 if (auto const tip = param->param_getTooltip()) {
170 widg->set_tooltip_markup(*tip);
171 } else {
172 widg->set_tooltip_text("");
173 widg->set_has_tooltip(false);
174 }
175 }
176 }
177
178 ++it;
179 }
180 auto const hbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
181 auto const center_vert_button = Gtk::make_managed<Gtk::Button>(Glib::ustring(_("Vertical center")));
182 center_vert_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEMirrorSymmetry::centerVert));
183 center_vert_button->set_size_request(110,20);
184 auto const center_horiz_button = Gtk::make_managed<Gtk::Button>(Glib::ustring(_("Horizontal center")));
185 center_horiz_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEMirrorSymmetry::centerHoriz));
186 center_horiz_button->set_size_request(110,20);
187 UI::pack_start(*vbox, *hbox, true,true,2);
188 UI::pack_start(*hbox, *center_vert_button, false, false,2);
189 UI::pack_start(*hbox, *center_horiz_button, false, false,2);
190 return vbox;
191}
192
193void
195 center_vert = true;
196 sp_lpe_item_update_patheffect(sp_lpe_item, false, false, true);
197 makeUndoDone(_("Center Vertical"));
198}
199
200void
202 center_horiz = true;
203 sp_lpe_item_update_patheffect(sp_lpe_item, false, false, true);
204 makeUndoDone(_("Center Horizontal"));
205}
206
207void
209{
210 using namespace Geom;
211 if ((!split_items || discard_orig_path) && lpesatellites.data().size()) {
213 }
214 if (link_styles) {
215 reset = true;
216 }
217 if (!lpesatellites.data().size()) {
219 if (lpesatellites.data().size()) {
221 }
222 }
223 original_bbox(lpeitem, false, true);
227 if (center_vert) {
228 center_point.param_setValue(point_c, true);
230 //force update
232 center_vert = false;
233 } else if (center_horiz) {
234 center_point.param_setValue(point_c, true);
237 //force update
238 center_horiz = false;
239 } else {
240
241 if (mode == MT_Y) {
245 }
246 if (mode == MT_X) {
250 }
252 start_point.param_setValue(point_a, true);
253 end_point.param_setValue(point_b, true);
256 return;
257 }
258 if ( mode == MT_X || mode == MT_Y ) {
260 center_point.param_setValue(Geom::middle_point(point_a, point_b), true);
261 end_point.param_setValue(point_b, true);
262 start_point.param_setValue(point_a, true);
263 } else {
264 if ( mode == MT_X ) {
265 if (!are_near(start_point[X], point_a[X], 0.01)) {
266 start_point.param_setValue(point_a, true);
267 }
268 if (!are_near(end_point[X], point_b[X], 0.01)) {
269 end_point.param_setValue(point_b, true);
270 }
271 } else { //MT_Y
272 if (!are_near(start_point[Y], point_a[Y], 0.01)) {
273 start_point.param_setValue(point_a, true);
274 }
275 if (!are_near(end_point[Y], point_b[Y], 0.01)) {
276 end_point.param_setValue(point_b, true);
277 }
278 }
279 }
280 } else if ( mode == MT_FREE) {
282 start_point.param_setValue(point_a, true);
283 end_point.param_setValue(point_b, true);
286 return;
287 }
291 end_point.param_setValue(end_point + trans, true);
292 }
295 } else { // MT_V or MT_H (horizontal or vertical page center)
296 SPDocument *document = getSPDoc();
297 if (document) {
298 auto &pageManager = document->getPageManager();
299 SPPage *page = pageManager.getPageFor(sp_lpe_item, false);
300 Geom::OptRect pageRect;
301
302 if (page == nullptr) {
303 pageRect = document->preferredBounds();
304 } else {
305 pageRect = page->getDocumentRect();
306 }
307
308 Geom::Point sp, ep;
309 if (mode == MT_V) { // The mirror line is the vertical page center.
310 sp = Geom::Point(pageRect->midpoint().x(), pageRect->top());
311 ep = Geom::Point(sp.x(), pageRect->bottom());
312 } else { // The mirror line is the horizontal page center.
313 sp = Geom::Point(pageRect->left(), pageRect->midpoint().y());
314 ep = Geom::Point(pageRect->right(), sp.y());
315 }
316 Geom::Affine transform = i2anc_affine(lpeitem, nullptr).inverse();
317 start_point.param_setValue(sp * transform, true);
318 end_point.param_setValue(ep * transform, true);
320 }
321 }
322 }
324}
325
327{
328 dest->setAttribute("transform", orig->getAttribute("transform"));
329 dest->setAttribute("mask", orig->getAttribute("mask"));
330 dest->setAttribute("clip-path", orig->getAttribute("clip-path"));
331 dest->setAttribute("class", orig->getAttribute("class"));
332 dest->setAttribute("style", orig->getAttribute("style"));
333 for (auto iter : orig->style->properties()) {
334 if (iter->style_src != SPStyleSrc::UNSET) {
335 auto key = iter->id();
336 if (key != SPAttr::FONT && key != SPAttr::D && key != SPAttr::MARKER) {
337 const gchar *attr = orig->getAttribute(iter->name().c_str());
338 if (attr) {
339 dest->setAttribute(iter->name(), attr);
340 }
341 }
342 }
343 }
344}
345
347{
348 SPDocument *document = getSPDoc();
349 if (!document) {
350 return;
351 }
352 if ( is<SPGroup>(orig) && is<SPGroup>(dest) && cast<SPGroup>(orig)->getItemCount() == cast<SPGroup>(dest)->getItemCount() ) {
353 if (reset) {
354 cloneStyle(orig, dest);
355 }
356 std::vector< SPObject * > childs = orig->childList(true);
357 size_t index = 0;
358 for (auto & child : childs) {
359 SPObject *dest_child = dest->nthChild(index);
360 cloneD(child, dest_child);
361 index++;
362 }
363 return;
364 } else if( is<SPGroup>(orig) && is<SPGroup>(dest) && cast<SPGroup>(orig)->getItemCount() != cast<SPGroup>(dest)->getItemCount()) {
366 return;
367 }
368
369 if (is<SPText>(orig) && is<SPText>(dest) && cast<SPText>(orig)->children.size() == cast<SPText>(dest)->children.size()) {
370 if (reset) {
371 cloneStyle(orig, dest);
372 }
373 size_t index = 0;
374 for (auto &child : cast<SPText>(orig)->children) {
375 SPObject *dest_child = dest->nthChild(index);
376 cloneD(&child, dest_child);
377 index++;
378 }
379 }
380
381 auto shape = cast<SPShape>(orig);
382 auto path = cast<SPPath>(dest);
383 if (shape) {
384 SPCurve const *c = shape->curve();
385 if (c) {
386 auto str = sp_svg_write_path(c->get_pathvector());
387 if (shape && !path) {
388 const char *id = dest->getAttribute("id");
389 const char *style = dest->getAttribute("style");
390 Inkscape::XML::Document *xml_doc = dest->document->getReprDoc();
391 Inkscape::XML::Node *dest_node = xml_doc->createElement("svg:path");
392 dest_node->setAttribute("id", id);
393 dest_node->setAttribute("style", style);
394 dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL);
395 path = cast<SPPath>(dest);
396 }
397 path->setAttribute("d", str);
398 } else {
399 path->removeAttribute("d");
400 }
401 }
402 if (reset) {
403 cloneStyle(orig, dest);
404 }
405}
406
409 SPDocument *document = getSPDoc();
410 if (!document) {
411 return nullptr;
412 }
413 Inkscape::XML::Document *xml_doc = document->getReprDoc();
414 Inkscape::XML::Node *prev = elemref->getRepr();
415 auto group = cast<SPGroup>(elemref);
416 if (group) {
417 Inkscape::XML::Node *container = xml_doc->createElement("svg:g");
418 container->setAttribute("transform", prev->attribute("transform"));
419 container->setAttribute("mask", prev->attribute("mask"));
420 container->setAttribute("clip-path", prev->attribute("clip-path"));
421 container->setAttribute("class", prev->attribute("class"));
422 std::vector<SPItem*> const item_list = group->item_list();
423 Inkscape::XML::Node *previous = nullptr;
424 for (auto sub_item : item_list) {
425 Inkscape::XML::Node *resultnode = createPathBase(sub_item);
426 container->addChild(resultnode, previous);
427 previous = resultnode;
428 }
429 return container;
430 }
431 Inkscape::XML::Node *resultnode = xml_doc->createElement("svg:path");
432 resultnode->setAttribute("transform", prev->attribute("transform"));
433 resultnode->setAttribute("mask", prev->attribute("mask"));
434 resultnode->setAttribute("clip-path", prev->attribute("clip-path"));
435 resultnode->setAttribute("class", prev->attribute("class"));
436 return resultnode;
437}
438
439void
441{
442 SPDocument *document = getSPDoc();
443 if (!document) {
444 return;
445 }
446 //Inkscape::XML::Document *xml_doc = document->getReprDoc();
447 SPObject *elemref = nullptr;
448 if (!is_load && container != sp_lpe_item->parent) {
450 return;
451 }
452 if (lpesatellites.data().size() && lpesatellites.data()[0]) {
453 elemref = lpesatellites.data()[0]->getObject();
454 }
455 Inkscape::XML::Node *phantom = nullptr;
456 bool creation = false;
457 if (elemref) {
458 phantom = elemref->getRepr();
459 } else {
460 creation = true;
461 phantom = createPathBase(sp_lpe_item);
462 reset = true;
463 elemref = container->appendChildRepr(phantom);
464 Inkscape::GC::release(phantom);
465 }
466 cloneD(sp_lpe_item, elemref);
468 elemref->getRepr()->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(transform));
469 // Alow work in clones
470 /* if (elemref->parent != container) {
471 if (!creation) {
472 lpesatellites.unlink(elemref);
473 }
474 Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
475 copy->setAttribute("id", elemref->getId());
476 lpesatellites.link(container->appendChildRepr(copy), 0);
477 Inkscape::GC::release(copy);
478 elemref->deleteObject();
479 lpesatellites.write_to_SVG();
480 lpesatellites.update_satellites();
481 } else */
482 if (creation) {
484 lpesatellites.link(elemref, 0);
488 }
489 }
491 if (!creation) {
493 }
495 sp_lpe_item_update_patheffect(sp_lpe_item, false, false, true);
496 }
497}
498
499
500//TODO: Migrate the tree next function to effect.cpp/h to avoid duplication
501void
506
507void
509{
510 if (keep_paths) {
512 return;
513 }
515}
516
517void
519{
520 using namespace Geom;
521
522 original_bbox(lpeitem, false, true);
523
527 start_point.param_setValue(point_a, true);
529 end_point.param_setValue(point_b, true);
531 center_point.param_setValue(point_c, true);
533 //we bump to 1.1 because previous 1.0.2 take no effect because a bug on 1.0.2
534 lpeversion.param_setValue("1.2", true);
536}
537
540{
541 if (split_items && !fuse_paths) {
542 return path_in;
543 }
544 Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
545 Geom::PathVector path_out;
546
547 if (!discard_orig_path && !fuse_paths) {
548 path_out = pathv_to_linear_and_cubic_beziers(path_in);
549 }
550
554 for (const auto & path_it : original_pathv)
555 {
556 if (path_it.empty()) {
557 continue;
558 }
559 Geom::PathVector tmp_pathvector;
560 double time_start = 0.0;
561 int position = 0;
562 bool end_open = false;
563 if (path_it.closed()) {
564 const Geom::Curve &closingline = path_it.back_closed();
565 if (!are_near(closingline.initialPoint(), closingline.finalPoint())) {
566 end_open = true;
567 }
568 }
569 Geom::Path original = path_it;
570 if (end_open && path_it.closed()) {
571 original.close(false);
572 original.appendNew<Geom::LineSegment>( original.initialPoint() );
573 original.close(true);
574 }
577 double dir = line_separation.angle();
580 double size_divider = Geom::distance(center_point, bbox) + diagonal;
581 s = Geom::Point::polar(dir,size_divider) + center_point;
582 e = Geom::Point::polar(dir + Geom::rad_from_deg(180),size_divider) + center_point;
583 Geom::Path divider = Geom::Path(s);
584 divider.appendNew<Geom::LineSegment>(e);
585 Geom::Crossings cs = crossings(original, divider);
586 std::vector<double> crossed;
587 for(auto & c : cs) {
588 crossed.push_back(c.ta);
589 }
590 std::sort(crossed.begin(), crossed.end());
591 for (unsigned int i = 0; i < crossed.size(); i++) {
592 double time_end = crossed[i];
593 if (time_start != time_end && time_end - time_start > Geom::EPSILON) {
594 Geom::Path portion = original.portion(time_start, time_end);
595 if (!portion.empty()) {
596 Geom::Point middle = portion.pointAt((double)portion.size()/2.0);
597 position = Geom::sgn(Geom::cross(e - s, middle - s));
598 if (!oposite_fuse) {
599 position *= -1;
600 }
601 if (position == 1) {
602 if (!split_items) {
603 Geom::Path mirror = portion.reversed() * m;
604 mirror.setInitial(portion.finalPoint());
605 portion.append(mirror);
606 if(i != 0) {
607 portion.setFinal(portion.initialPoint());
608 portion.close();
609 }
610 }
611 tmp_pathvector.push_back(portion);
612 }
613 portion.clear();
614 }
615 }
616 time_start = time_end;
617 }
618 position = Geom::sgn(Geom::cross(e - s, original.finalPoint() - s));
619 if (!oposite_fuse) {
620 position *= -1;
621 }
622 if (cs.size()!=0 && (position == 1)) {
623 if (time_start != original.size() && original.size() - time_start > Geom::EPSILON) {
624 Geom::Path portion = original.portion(time_start, original.size());
625 if (!portion.empty()) {
626 portion = portion.reversed();
627 if (!split_items) {
628 Geom::Path mirror = portion.reversed() * m;
629 mirror.setInitial(portion.finalPoint());
630 portion.append(mirror);
631 }
632 portion = portion.reversed();
633 if (!original.closed()) {
634 tmp_pathvector.push_back(portion);
635 } else {
636 if (cs.size() > 1 && tmp_pathvector.size() > 0 && tmp_pathvector[0].size() > 0 ) {
637 if (!split_items) {
638 portion.setFinal(tmp_pathvector[0].initialPoint());
639 portion.setInitial(tmp_pathvector[0].finalPoint());
640 } else {
641 tmp_pathvector[0] = tmp_pathvector[0].reversed();
642 portion = portion.reversed();
643 portion.setInitial(tmp_pathvector[0].finalPoint());
644 }
645 tmp_pathvector[0].append(portion);
646 } else {
647 tmp_pathvector.push_back(portion);
648 }
649 if (lpeversion.param_getSVGValue() < "1.1") {
650 tmp_pathvector[0].close();
651 }
652 }
653 portion.clear();
654 }
655 }
656 }
657 if (!split_open && lpeversion.param_getSVGValue() >= "1.1" && original.closed()) {
658 for (auto &path : tmp_pathvector) {
659 if (!path.closed()) {
660 path.close();
661 }
662 }
663 flatten(tmp_pathvector, fill_oddEven);
664 }
665 if (cs.size() == 0 && position == 1) {
666 tmp_pathvector.push_back(original);
667 if (!split_items) {
668 tmp_pathvector.push_back(original * m);
669 }
670 }
671 path_out.insert(path_out.end(), tmp_pathvector.begin(), tmp_pathvector.end());
672 tmp_pathvector.clear();
673 }
674 } else if (!fuse_paths || discard_orig_path) {
675 for (const auto & i : original_pathv) {
676 path_out.push_back(i * m);
677 }
678 }
679 return path_out;
680}
681
682void
683LPEMirrorSymmetry::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
684{
685 using namespace Geom;
686 hp_vec.clear();
687 Geom::Path path;
690 path.start( s );
691 path.appendNew<Geom::LineSegment>( e );
692 Geom::PathVector helper;
693 helper.push_back(path);
694 hp_vec.push_back(helper);
695}
696
697} //namespace LivePathEffect
698} /* namespace Inkscape */
699
700/*
701 Local Variables:
702 mode:c++
703 c-file-style:"stroustrup"
704 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
705 indent-tabs-mode:nil
706 fill-column:99
707 End:
708*/
709// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
@ fill_oddEven
Definition LivarotDefs.h:68
3x3 affine transformation matrix.
uint64_t page
Definition canvas.cpp:171
3x3 matrix representing an affine transformation.
Definition affine.h:70
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
void clear()
Definition bezier.h:248
unsigned size() const
Definition bezier.h:147
friend Bezier portion(const Bezier &a, Coord from, Coord to)
Definition bezier.cpp:250
Abstract continuous curve on a plane defined on [0,1].
Definition curve.h:78
virtual Point initialPoint() const =0
Retrieve the start of the curve.
virtual Point finalPoint() const =0
Retrieve the end of the curve.
constexpr C min() const
constexpr C max() const
constexpr C middle() const
Infinite line on a plane.
Definition line.h:53
Point vector() const
Get the line's raw direction vector.
Definition line.h:132
Coord angle() const
Angle the line makes with the X axis, in mathematical convention.
Definition line.h:137
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Sequence of subpaths.
Definition pathvector.h:122
size_type size() const
Get the number of paths in the vector.
Definition pathvector.h:147
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
void clear()
Remove all paths from the vector.
Definition pathvector.h:195
iterator insert(iterator pos, Path const &p)
Definition pathvector.h:179
PathVector reversed(bool reverse_paths=true) const
Get a new vector with reversed direction of paths.
iterator begin()
Definition pathvector.h:151
iterator end()
Definition pathvector.h:152
Sequence of contiguous curves, aka spline.
Definition path.h:353
void close(bool closed=true)
Set whether the path is closed.
Definition path.cpp:322
void setInitial(Point const &p)
Definition path.h:734
void appendNew(Args &&... args)
Append a new curve to the path.
Definition path.h:804
void start(Point const &p)
Definition path.cpp:426
Two-dimensional point that doubles as a vector.
Definition point.h:66
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
Axis aligned, non-empty rectangle.
Definition rect.h:92
std::vector< StorageType > const & data() const
Definition array.h:48
void param_setValue(bool newvalue)
Definition bool.cpp:89
std::vector< Parameter * > param_vector
Definition effect.h:179
void registerParameter(Parameter *param)
Definition effect.cpp:1710
virtual void processObjects(LPEAction lpe_action)
Definition effect.cpp:1416
void makeUndoDone(Glib::ustring message)
Definition effect.cpp:1521
LivePathEffectObject * getLPEObj()
Definition effect.h:151
void original_bbox(SPLPEItem const *lpeitem, bool absolute=false, bool clip_mask=false, Geom::Affine base_transform=Geom::identity())
void param_setValue(Glib::ustring newvalue, bool write=false)
Definition hidden.cpp:71
Glib::ustring param_getSVGValue() const override
Definition hidden.cpp:53
Inkscape::XML::Node * createPathBase(SPObject *elemref)
void doBeforeEffect(SPLPEItem const *lpeitem) override
Is performed each time before the effect is updated.
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
void cloneD(SPObject *orig, SPObject *dest)
void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector< Geom::PathVector > &hp_vec) override
Add possible canvas indicators (i.e., helperpaths other than the original path) to hp_vec This functi...
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
void doAfterEffect(SPLPEItem const *lpeitem, SPCurve *curve) override
Is performed at the end of the LPE only one time per "lpeitem" in paths/shapes is called in middle of...
void cloneStyle(SPObject *orig, SPObject *dest)
bool doOnOpen(SPLPEItem const *) override
Is performed on load document or revert If the item is fixed legacy return true.
void doOnVisibilityToggled(SPLPEItem const *) override
LPEMirrorSymmetry(LivePathEffectObject *lpeobject)
Gtk::Widget * newWidget() override
This creates a managed widget.
Glib::ustring const * param_getTooltip() const
Definition parameter.h:81
virtual void param_widget_is_visible(bool is_visible)
Definition parameter.h:69
virtual Gtk::Widget * param_newWidget()=0
void param_update_default(Geom::Point default_point)
Definition point.cpp:64
void param_setValue(Geom::Point newpoint, bool write=false)
Definition point.cpp:100
void link(SPObject *to, size_t pos=Glib::ustring::npos)
Simplified management of enumerations of svg items with UI labels.
Definition enums.h:42
Interface for refcounted XML nodes.
Definition node.h:80
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:167
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
Wrapper around a Geom::PathVector object.
Definition curve.h:26
Typed SVG document implementation.
Definition document.h:103
SPObject * getObjectById(std::string const &id) const
Geom::OptRect preferredBounds() const
Definition document.cpp:978
Inkscape::PageManager & getPageManager()
Definition document.h:164
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:213
Geom::Affine transform
Definition sp-item.h:138
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
SPDocument * document
Definition sp-object.h:188
char const * getId() const
Returns the objects current ID string.
SPObject * parent
Definition sp-object.h:189
Inkscape::XML::Node * updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT)
Updates the object's repr based on the object's state.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
char const * getAttribute(char const *name) const
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
SPObject * nthChild(unsigned index)
void addChild(Inkscape::XML::Node *child, Inkscape::XML::Node *prev=nullptr)
double c[8][4]
Geom::Point orig
constexpr Coord EPSILON
Default "acceptably small" value.
Definition coord.h:84
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Affine reflection(Point const &vector, Point const &origin)
Reflects objects about line.
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
Definition geom.cpp:588
Specific geometry functions for Inkscape, not provided my lib2geom.
std::string original
LPE <mirror_symmetry> implementation: mirrors a path with respect to a given line.
Various utility functions.
Definition affine.h:22
int sgn(const T &x)
Sign function - indicates the sign of a numeric type.
Definition math-utils.h:51
Angle distance(Angle const &a, Angle const &b)
Definition angle.h:163
std::vector< Crossing > Crossings
Definition crossing.h:126
Crossings crossings(Curve const &a, Curve const &b)
Bezier portion(const Bezier &a, double from, double to)
Definition bezier.cpp:250
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Point middle_point(LineSegment const &_segment)
static R & release(R &r)
Decrements the reference count of a anchored object.
static const Util::EnumDataConverter< ModeType > MTConverter(ModeTypeData, MT_END)
static const Util::EnumData< ModeType > ModeTypeData[]
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition pack.cpp:141
Helper class to stream background task notifications as a series of messages.
static cairo_user_data_key_t key
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
int mode
void flatten(Geom::PathVector &pathv, FillRule fill_rule)
Boolean operations.
Path intersection.
Ocnode * child[8]
Definition quantize.cpp:33
Axis-aligned rectangle.
Geom::Affine i2anc_affine(SPObject const *object, SPObject const *ancestor)
Definition sp-item.cpp:1794
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
Base class for live path effect items.
SPPage – a page object.
Simplified management of enumerations of svg items with UI labels.
Definition enums.h:27
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
Definition curve.h:24
SPStyle - a style object for SPItem objects.
std::string sp_svg_transform_write(Geom::Affine const &transform)
static void sp_svg_write_path(Inkscape::SVG::PathString &str, Geom::Path const &p, bool normalize=false)
Definition svg-path.cpp:109
int index