Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-copy_rotate.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/*
6 * Authors:
7 * Maximilian Albert <maximilian.albert@gmail.com>
8 * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
9 * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
10 * Copyright (C) Authors 2007-2012
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "lpe-copy_rotate.h"
16
17#include <gdk/gdk.h>
18#include <gtkmm/widget.h>
19#include <gtkmm/box.h>
20
24
25#include "inkscape.h"
26#include "style.h"
27#include "display/curve.h"
28#include "helper/geom.h"
32#include "object/sp-object.h"
33#include "object/sp-path.h"
34#include "object/sp-shape.h"
35#include "object/sp-text.h"
36#include "path/path-boolop.h"
37#include "svg/path-string.h"
38#include "svg/svg.h"
39#include "ui/pack.h"
40#include "xml/sp-css-attr.h"
41
42// TODO due to internal breakage in glibmm headers, this must be last:
43#include <glibmm/i18n.h>
44
45namespace Inkscape {
46namespace LivePathEffect {
47
49 { RM_NORMAL, N_("Normal"), "normal" },
50 { RM_KALEIDOSCOPE, N_("Kaleidoscope"), "kaleidoskope" },
51 { RM_FUSE, N_("Fuse paths"), "fuse_paths" }
52};
55
57 Effect(lpeobject),
58 // do not change name of this parameter us used in oncommit
59 lpesatellites(_("lpesatellites"), _("Items satellites"), "lpesatellites", &wr, this, false),
60 method(_("Method:"), _("Rotate methods"), "method", RMConverter, &wr, this, RM_NORMAL),
61 origin(_("Origin"), _("Adjust origin of the rotation"), "origin", &wr, this, _("Adjust origin of the rotation")),
62 starting_point(_("Start point"), _("Starting point to define start angle"), "starting_point", &wr, this, _("Adjust starting point to define start angle")),
63 starting_angle(_("Starting angle"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
64 rotation_angle(_("Rotation angle"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0),
65 num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 6),
66 gap(_("Gap"), _("Gap space between copies, use small negative gaps to fix some joins"), "gap", &wr, this, -0.01),
67 copies_to_360(_("Distribute evenly"), _("Angle between copies is 360°/number of copies (ignores rotation angle setting)"), "copies_to_360", &wr, this, true),
68 mirror_copies(_("Mirror copies"), _("Mirror between copies"), "mirror_copies", &wr, this, false),
69 split_items(_("Split elements"), _("Split elements, so each can have its own style"), "split_items", &wr, this, false),
70 link_styles(_("Link styles"), _("Link styles on split mode"), "link_styles", &wr, this, false),
71 dist_angle_handle(100.0)
72{
73 show_orig_path = true;
75 //0.92 compatibility
76 if (this->getRepr()->attribute("fuse_paths") && strcmp(this->getRepr()->attribute("fuse_paths"), "true") == 0){
77 this->getRepr()->removeAttribute("fuse_paths");
78 this->getRepr()->setAttribute("method", "kaleidoskope");
79 this->getRepr()->setAttribute("mirror_copies", "true");
80 };
81 // register all your parameters here, so Inkscape knows which parameters this effect has:
94 gap.param_set_range(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max());
95 gap.param_set_increments(0.01, 0.01);
98 num_copies.param_set_range(1, std::numeric_limits<gint>::max());
106}
107
109
111{
112 bool fixed = false;
113 if (!is_load || is_applied) {
114 return fixed;
115 }
116 Glib::ustring version = lpeversion.param_getSVGValue();
117 if (version < "1.2") {
118 if (!split_items) {
119 return fixed;
120 }
122 for (size_t i = 0; i < num_copies - 1; i++) {
123 Glib::ustring id = Glib::ustring("rotated-");
124 id += std::to_string(i);
125 id += "-";
126 id += getLPEObj()->getId();
127 SPObject *elemref = getSPDoc()->getObjectById(id.c_str());
128 if (elemref) {
129 lpesatellites.link(elemref, i);
130 }
131 }
132 lpeversion.param_setValue("1.2", true);
133 fixed = true;
135 }
136 if (!split_items) {
137 return fixed;
138 }
141 container = lpeitem->parent;
142 return fixed;
143}
144
145void
147{
148 if (split_items) {
149 SPDocument *document = getSPDoc();
150 if (!document) {
151 return;
152 }
153 bool write = false;
154 bool active = !lpesatellites.data().size();
155 for (auto lpereference : lpesatellites.data()) {
156 if (lpereference && lpereference->isAttached() && lpereference.get()->getObject() != nullptr) {
157 active = true;
158 }
159 }
160 if (!active && !is_load && previous_split) {
163 return;
164 }
165
168 write = true;
169 size_t pos = 0;
170 for (auto lpereference : lpesatellites.data()) {
171 if (lpereference && lpereference->isAttached()) {
172 auto copies = cast<SPItem>(lpereference->getObject());
173 if (copies) {
174 if (pos > num_copies - 2) {
175 copies->setHidden(true);
176 } else if (copies->isHidden()) {
177 copies->setHidden(false);
178 }
179 }
180 }
181 pos++;
182 }
184 }
185 bool forcewrite = write;
186 Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle)));
187 for (size_t i = 1; i < num_copies; ++i) {
189 if(mirror_copies && i%2 != 0) {
191 r *= Geom::Scale(1, -1);
193 }
194
195 Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i)));
196 Geom::Affine t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
197 if (method != RM_NORMAL) {
198 if(mirror_copies && i%2 != 0) {
199 t = m * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
200 }
201 } else {
202 if(mirror_copies && i%2 != 0) {
203 t = m * Geom::Rotate(Geom::rad_from_deg(-rotation_angle)) * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
204 }
205 }
207 toItem(t, i-1, reset, write);
208 forcewrite = forcewrite || write;
209 }
210 //we keep satellites connected and active if write needed
211 bool connected = lpesatellites.is_connected();
212 if (forcewrite || !connected) {
215 if (!connected) {
216 sp_lpe_item_update_patheffect(sp_lpe_item, false, false, true);
217 } else {
219 }
220 }
222 }
224}
225
227{
228 dest->setAttribute("transform", orig->getAttribute("transform"));
229 dest->setAttribute("style", orig->getAttribute("style"));
230 dest->setAttribute("mask", orig->getAttribute("mask"));
231 dest->setAttribute("clip-path", orig->getAttribute("clip-path"));
232 dest->setAttribute("class", orig->getAttribute("class"));
233 for (auto iter : orig->style->properties()) {
234 if (iter->style_src != SPStyleSrc::UNSET) {
235 auto key = iter->id();
236 if (key != SPAttr::FONT && key != SPAttr::D && key != SPAttr::MARKER) {
237 const gchar *attr = orig->getAttribute(iter->name().c_str());
238 if (attr) {
239 dest->setAttribute(iter->name(), attr);
240 }
241 }
242 }
243 }
244}
245
247{
248 SPDocument *document = getSPDoc();
249 if (!document) {
250 return;
251 }
252 dest->setAttribute("transform", orig->getAttribute("transform"));
253 if (is<SPGroup>(orig) && is<SPGroup>(dest) && cast_unsafe<SPGroup>(orig)->getItemCount() == cast_unsafe<SPGroup>(dest)->getItemCount()) {
254 if (reset) {
255 cloneStyle(orig, dest);
256 }
257 std::vector< SPObject * > childs = orig->childList(true);
258 size_t index = 0;
259 for (auto & child : childs) {
260 SPObject *dest_child = dest->nthChild(index);
261 cloneD(child, dest_child);
262 index++;
263 }
264 return;
265 } else if( is<SPGroup>(orig) && is<SPGroup>(dest) && cast<SPGroup>(orig)->getItemCount() != cast<SPGroup>(dest)->getItemCount()) {
267 return;
268 }
269
270 if ( is<SPText>(orig) && is<SPText>(dest) && cast<SPText>(orig)->children.size() == cast<SPText>(dest)->children.size()) {
271 if (reset) {
272 cloneStyle(orig, dest);
273 }
274 size_t index = 0;
275 for (auto & child : cast<SPText>(orig)->children) {
276 SPObject *dest_child = dest->nthChild(index);
277 cloneD(&child, dest_child);
278 index++;
279 }
280 }
281
282 auto shape = cast<SPShape>(orig);
283 auto path = cast<SPPath>(dest);
284 if (shape) {
285 SPCurve const *c = shape->curve();
286 if (c) {
287 auto str = sp_svg_write_path(c->get_pathvector());
288 if (shape && !path) {
289 const char *id = dest->getAttribute("id");
290 const char *style = dest->getAttribute("style");
291 Inkscape::XML::Document *xml_doc = dest->document->getReprDoc();
292 Inkscape::XML::Node *dest_node = xml_doc->createElement("svg:path");
293 dest_node->setAttribute("id", id);
294 dest_node->setAttribute("style", style);
295 dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL);
296 path = cast<SPPath>(dest);
297 }
298 path->setAttribute("d", str);
299 } else {
300 path->removeAttribute("d");
301 }
302
303 }
304 if (reset) {
305 cloneStyle(orig, dest);
306 }
307}
308
311 SPDocument *document = getSPDoc();
312 if (!document) {
313 return nullptr;
314 }
315 Inkscape::XML::Document *xml_doc = document->getReprDoc();
316 Inkscape::XML::Node *prev = elemref->getRepr();
317 auto group = cast<SPGroup>(elemref);
318 if (group) {
319 Inkscape::XML::Node *container = xml_doc->createElement("svg:g");
320 container->setAttribute("transform", prev->attribute("transform"));
321 container->setAttribute("mask", prev->attribute("mask"));
322 container->setAttribute("clip-path", prev->attribute("clip-path"));
323 container->setAttribute("class", prev->attribute("class"));
324 container->setAttribute("style", prev->attribute("style"));
325 std::vector<SPItem*> const item_list = group->item_list();
326 Inkscape::XML::Node *previous = nullptr;
327 for (auto sub_item : item_list) {
328 Inkscape::XML::Node *resultnode = createPathBase(sub_item);
329
330 container->addChild(resultnode, previous);
331 previous = resultnode;
332 }
333 return container;
334 }
335 Inkscape::XML::Node *resultnode = xml_doc->createElement("svg:path");
336 resultnode->setAttribute("transform", prev->attribute("transform"));
337 resultnode->setAttribute("style", prev->attribute("style"));
338 resultnode->setAttribute("mask", prev->attribute("mask"));
339 resultnode->setAttribute("clip-path", prev->attribute("clip-path"));
340 resultnode->setAttribute("class", prev->attribute("class"));
341 return resultnode;
342}
343
344void
345LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset, bool &write)
346{
347 SPDocument *document = getSPDoc();
348 if (!document) {
349 return;
350 }
351 //Inkscape::XML::Document *xml_doc = document->getReprDoc();
352
353 SPObject *elemref = nullptr;
354 if (container != sp_lpe_item->parent) {
356 return;
357 }
358 if (lpesatellites.data().size() > i && lpesatellites.data()[i]) {
359 elemref = lpesatellites.data()[i]->getObject();
360 }
361 Inkscape::XML::Node *phantom = nullptr;
362 bool creation = false;
363 if (elemref) {
364 phantom = elemref->getRepr();
365 } else {
366 creation = true;
367 phantom = createPathBase(sp_lpe_item);
368 reset = true;
369 elemref = container->appendChildRepr(phantom);
370
371 Inkscape::GC::release(phantom);
372 }
373 cloneD(sp_lpe_item, elemref);
374 elemref->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(transform));
376 // allow use on clones even in different parent
377 /* if (elemref->parent != container) {
378 if (!creation) {
379 lpesatellites.unlink(elemref);
380 }
381 Inkscape::XML::Node *copy = phantom->duplicate(xml_doc);
382 copy->setAttribute("id", elemref->getId());
383 lpesatellites.link(container->appendChildRepr(copy), i);
384 Inkscape::GC::release(copy);
385 elemref->deleteObject();
386 } else */
387 if (creation) {
388 write = true;
389 lpesatellites.link(elemref, i);
390 }
391}
392
394{
395 // use manage here, because after deletion of Effect object, others might
396 // still be pointing to this widget.
397 auto const vbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 2);
398 vbox->set_margin(5);
399
400 std::vector<Parameter *>::iterator it = param_vector.begin();
401 while (it != param_vector.end()) {
402 if ((*it)->widget_is_visible) {
403 Parameter *param = *it;
404 auto const widg = param->param_newWidget();
405
406 if (widg) {
407 UI::pack_start(*vbox, *widg, true, true, 2);
408
409 if (auto const tip = param->param_getTooltip()) {
410 widg->set_tooltip_markup(*tip);
411 } else {
412 widg->set_tooltip_text("");
413 widg->set_has_tooltip(false);
414 }
415 }
416 }
417
418 ++it;
419 }
420
421 return vbox;
422}
423
424
425void
427{
428 using namespace Geom;
429 original_bbox(lpeitem, false, true);
430
433 origin.param_setValue(A, true);
435 dist_angle_handle = L2(B - A);
436 dir = unit_vector(B - A);
437 lpeversion.param_setValue("1.2", true);
438}
439
440void
442{
443 using namespace Geom;
444 if (!split_items && lpesatellites.data().size()) {
446 }
447 if (link_styles) {
448 reset = true;
449 }
450 if (split_items && !lpesatellites.data().size()) {
452 if (lpesatellites.data().size()) {
454 }
455 }
456 original_bbox(lpeitem, false, true);
457 if (copies_to_360 && num_copies > 2) {
459 }
462 }
465 if ((int)num_copies%2 !=0) {
468 }
469 } else {
471 }
472
475 if (Geom::are_near(A, B, 0.01)) {
476 B += Geom::Point(1.0, 0.0);
477 }
478 dir = unit_vector(B - A);
479 // I first suspected the minus sign to be a bug in 2geom but it is
480 // likely due to SVG's choice of coordinate system orientation (max)
481 bool near_start_point = Geom::are_near(previous_start_point, (Geom::Point)starting_point, 0.01);
482 bool near_origin = Geom::are_near(previous_origin, (Geom::Point)origin, 0.01);
483 if (!near_start_point && !is_load) {
484 if (lpeitem->document->isSensitive()) {
486 }
487 // FIXME: This will always be true! Did we mean to check if some state contains Shift flag?
488 if (GDK_SHIFT_MASK) {
489 dist_angle_handle = L2(B - A);
490 } else {
492 }
493 }
494 if (dist_angle_handle < 1.0) {
495 dist_angle_handle = 1.0;
496 }
500 }
501 start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * distance;
502 if (!near_start_point || !near_origin || split_items) {
504 }
505
508}
509
510void
512{
513 Geom::PathVector tmp_path;
514 double time_start = 0.0;
515 Geom::Path original = path_on[0];
516 int position = 0;
518 std::vector<double> crossed;
519 for(auto & c : cs) {
520 crossed.push_back(c.ta);
521 }
522 std::sort(crossed.begin(), crossed.end());
523 for (double time_end : crossed) {
524 if (time_start == time_end || time_end - time_start < Geom::EPSILON) {
525 continue;
526 }
527 Geom::Path portion_original = original.portion(time_start,time_end);
528 if (!portion_original.empty()) {
529 Geom::Point side_checker = portion_original.pointAt(0.0001);
530 position = Geom::sgn(Geom::cross(divider[1].finalPoint() - divider[0].finalPoint(), side_checker - divider[0].finalPoint()));
531 if (rotation_angle != 180) {
532 position = pointInTriangle(side_checker, divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint());
533 }
534 if (position == 1) {
535 tmp_path.push_back(portion_original);
536 }
537 portion_original.clear();
538 time_start = time_end;
539 }
540 }
541 position = Geom::sgn(Geom::cross(divider[1].finalPoint() - divider[0].finalPoint(), original.finalPoint() - divider[0].finalPoint()));
542 if (rotation_angle != 180) {
543 position = pointInTriangle(original.finalPoint(), divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint());
544 }
545 if (cs.size() > 0 && position == 1) {
546 Geom::Path portion_original = original.portion(time_start, original.size());
547 if(!portion_original.empty()){
548 if (!original.closed()) {
549 tmp_path.push_back(portion_original);
550 } else {
551 if (tmp_path.size() > 0 && tmp_path[0].size() > 0 ) {
552 portion_original.setFinal(tmp_path[0].initialPoint());
553 portion_original.append(tmp_path[0]);
554 tmp_path[0] = portion_original;
555 } else {
556 tmp_path.push_back(portion_original);
557 }
558 }
559 portion_original.clear();
560 }
561 }
562 if (cs.size()==0 && position == 1) {
563 tmp_path.push_back(original);
564 }
565 path_on = tmp_path;
566}
567
570{
571 Geom::PathVector path_out;
574 size_divider = Geom::distance(origin,bbox) + (diagonal * 6);
575 Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider;
576 Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider;
577 divider = Geom::Path(line_start);
580 divider.close();
581 half_dir = unit_vector(Geom::middle_point(line_start,line_end) - (Geom::Point)origin);
582 FillRuleBool fillrule = fill_nonZero;
583 if (current_shape->style &&
586 {
587 fillrule = (FillRuleBool)fill_oddEven;
588 }
589 if (method != RM_NORMAL) {
590 if (method != RM_KALEIDOSCOPE) {
591 path_out = doEffect_path_post(path_in, fillrule);
592 } else {
593 path_out = pathv_to_linear_and_cubic_beziers(path_in);
594 }
595 if (num_copies == 0) {
596 return path_out;
597 }
598 Geom::PathVector triangle;
599 triangle.push_back(divider);
600 path_out = sp_pathvector_boolop(path_out, triangle, bool_op_inters, fillrule, fillrule);
601 if ( !split_items ) {
602 path_out = doEffect_path_post(path_out, fillrule);
603 } else {
604 path_out *= Geom::Translate(half_dir * gap);
605 }
606 } else {
607 path_out = doEffect_path_post(path_in, fillrule);
608 }
609 if (!split_items && method != RM_NORMAL) {
610 Geom::PathVector path_out_tmp;
611 for (const auto & path_it : path_out) {
612 if (path_it.empty()) {
613 continue;
614 }
615 Geom::Path::const_iterator curve_it1 = path_it.begin();
616 Geom::Path::const_iterator curve_endit = path_it.end_default();
617 Geom::Path res;
618 if (path_it.closed()) {
619 const Geom::Curve &closingline = path_it.back_closed();
620 // the closing line segment is always of type
621 // Geom::LineSegment.
622 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
623 // closingline.isDegenerate() did not work, because it only checks for
624 // *exact* zero length, which goes wrong for relative coordinates and
625 // rounding errors...
626 // the closing line segment has zero-length. So stop before that one!
627 curve_endit = path_it.end_open();
628 }
629 }
630 while (curve_it1 != curve_endit) {
631 if (!Geom::are_near(curve_it1->initialPoint(), curve_it1->pointAt(0.5), 0.05)) {
632 if (!res.empty()) {
633 res.setFinal(curve_it1->initialPoint());
634 }
635 Geom::Curve *c = curve_it1->duplicate();
636 res.append(c);
637 }
638 ++curve_it1;
639 }
640 if (path_it.closed()) {
641 res.close();
642 }
643 path_out_tmp.push_back(res);
644 }
645 path_out = path_out_tmp;
646 }
647 return pathv_to_linear_and_cubic_beziers(path_out);
648}
649
652{
653 if ((split_items || num_copies == 1) && method == RM_NORMAL) {
654 if (split_items) {
656 Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle)));
657 Geom::Affine t = m * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) *
658 Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
659 return path_out * t;
660 }
661 return path_in;
662 }
663
664 Geom::Affine pre = Geom::Translate(-origin) * Geom::Rotate(-Geom::rad_from_deg(starting_angle));
665 Geom::PathVector original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
666 Geom::PathVector output_pv;
667 Geom::PathVector output;
668 for (int i = 0; i < num_copies; ++i) {
669 Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * i));
671 if( i%2 != 0 && mirror_copies) {
673 r *= Geom::Scale(1, -1);
675 }
676 Geom::Affine t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
677 if(mirror_copies && i%2 != 0) {
678 t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin);
679 }
680 if (method != RM_NORMAL) {
681 //we use safest way to union
682 Geom::PathVector join_pv = original_pathv * t;
683 join_pv *= Geom::Translate(half_dir * rot * gap);
684 if (!output_pv.empty()) {
685 output_pv = sp_pathvector_boolop(output_pv, join_pv, bool_op_union, fillrule, fillrule);
686 } else {
687 output_pv = join_pv;
688 }
689 } else {
690 t = pre * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
691 if(mirror_copies && i%2 != 0) {
692 t = pre * Geom::Rotate(Geom::rad_from_deg(-starting_angle-rotation_angle)) * r * rot * Geom::Rotate(-Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin);
693 }
694 output_pv = path_in * t;
695 output.insert(output.end(), output_pv.begin(), output_pv.end());
696 }
697 }
698 if (method != RM_NORMAL) {
699 output = output_pv;
700 }
701 return output;
702}
703
704void
705LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
706{
707 using namespace Geom;
708 hp_vec.clear();
709 Geom::Path hp;
710 hp.start(start_pos);
713 Geom::PathVector pathv;
714 pathv.push_back(hp);
715 hp_vec.push_back(pathv);
716}
717
718void
720{
722 original_bbox(cast<SPLPEItem>(item), false, true);
723}
724
725void
730
731void
733{
734 if (keep_paths) {
736 return;
737 }
739}
740
741} //namespace LivePathEffect
742} /* namespace Inkscape */
743
744/*
745 Local Variables:
746 mode:c++
747 c-file-style:"stroustrup"
748 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
749 indent-tabs-mode:nil
750 fill-column:99
751 End:
752*/
753// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
FillRule
Definition LivarotDefs.h:68
@ fill_oddEven
Definition LivarotDefs.h:69
@ fill_nonZero
Definition LivarotDefs.h:70
@ bool_op_inters
Definition LivarotDefs.h:79
@ bool_op_union
Definition LivarotDefs.h:78
Point origin
Definition aa.cpp:227
3x3 matrix representing an affine transformation.
Definition affine.h:70
Wrapper for angular values.
Definition angle.h:73
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
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
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
iterator insert(iterator pos, Path const &p)
Definition pathvector.h:179
iterator begin()
Definition pathvector.h:151
iterator end()
Definition pathvector.h:152
Sequence of contiguous curves, aka spline.
Definition path.h:353
Point finalPoint() const
Get the last point in the path.
Definition path.h:709
void close(bool closed=true)
Set whether the path is closed.
Definition path.cpp:322
bool empty() const
Check whether path is empty.
Definition path.h:500
Point pointAt(Coord t) const
Get the point at the specified time value.
Definition path.cpp:449
void clear()
Remove all curves from the path.
Definition path.cpp:337
Path portion(Coord f, Coord t) const
Definition path.h:645
void append(Curve *curve)
Add a new curve to the end of the path.
Definition path.h:750
Point initialPoint() const
Get the first point in the path.
Definition path.h:705
void setFinal(Point const &p)
Definition path.h:740
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
Rotation around the origin.
Definition transforms.h:187
Rotate inverse() const
Definition transforms.h:209
Scaling from the origin.
Definition transforms.h:150
Translation by a vector.
Definition transforms.h:115
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 resetDefaults(SPItem const *item)
Sets all parameters to their default values and writes them to SVG.
Definition effect.cpp:2014
virtual void processObjects(LPEAction lpe_action)
Definition effect.cpp:1416
Inkscape::XML::Node * getRepr()
Definition effect.cpp:1934
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
Geom::PathVector doEffect_path_post(Geom::PathVector const &path_in, FillRuleBool fillrule)
void cloneD(SPObject *orig, SPObject *dest)
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
void toItem(Geom::Affine transform, size_t i, bool reset, bool &write)
Gtk::Widget * newWidget() override
This creates a managed widget.
void cloneStyle(SPObject *orig, SPObject *dest)
void doOnVisibilityToggled(SPLPEItem const *) override
LPECopyRotate(LivePathEffectObject *lpeobject)
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 resetDefaults(SPItem const *item) override
Sets all parameters to their default values and writes them to SVG.
void doBeforeEffect(SPLPEItem const *lpeitem) override
Is performed each time before the effect is updated.
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...
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
Inkscape::XML::Node * createPathBase(SPObject *elemref)
bool doOnOpen(SPLPEItem const *) override
Is performed on load document or revert If the item is fixed legacy return true.
void doOnRemove(SPLPEItem const *) override
void split(Geom::PathVector &path_in, Geom::Path const &divider)
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)
void param_set_digits(unsigned digits)
void param_set_range(double min, double max)
void param_set_increments(double step, double page)
Simplified management of enumerations of svg items with UI labels.
Definition enums.h:42
Interface for refcounted XML nodes.
Definition node.h:80
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.
void removeAttribute(Inkscape::Util::const_char_ptr key)
Remove an attribute of this node.
Definition node.h:280
Wrapper around a Geom::PathVector object.
Definition curve.h:28
Typed SVG document implementation.
Definition document.h:101
SPObject * getObjectById(std::string const &id) const
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:211
bool isSensitive() const
Definition document.h:363
Base class for visual SVG elements.
Definition sp-item.h:109
Geom::Affine transform
Definition sp-item.h:138
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
Definition sp-item.cpp:927
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Definition sp-object.h:785
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.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Definition sp-object.h:248
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)
T< SPAttr::FILL_RULE, SPIEnum< SPWindRule > > fill_rule
fill-rule: 0 nonzero, 1 evenodd
Definition style.h:244
double c[8][4]
Geom::Point orig
constexpr Coord EPSILON
Default "acceptably small" value.
Definition coord.h:84
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
Definition geom.cpp:586
Specific geometry functions for Inkscape, not provided my lib2geom.
auto floor(Geom::Rect const &rect)
Definition geom.h:131
SPItem * item
std::string original
Path intersection graph.
LPE <copy_rotate> implementation, see lpe-copy_rotate.cpp.
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
double angle_between(Line const &l1, Line const &l2)
Definition line.h:456
std::vector< Crossing > Crossings
Definition crossing.h:126
Affine identity()
Create an identity matrix.
Definition affine.h:210
Crossings crossings(Curve const &a, Curve const &b)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
SBasis L2(D2< SBasis > const &a, unsigned k)
Definition d2-sbasis.cpp:42
Point unit_vector(Point const &a)
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< RotateMethod > RMConverter(RotateMethodData, RM_END)
bool pointInTriangle(Geom::Point const &p, std::vector< Geom::Point > points)
static const Util::EnumData< RotateMethod > RotateMethodData[RM_END]
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.
Geom::PathVector sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, BooleanOp bop, FillRule fra, FillRule frb)
Perform a boolean operation on two pathvectors.
Boolean operations.
Path intersection.
Inkscape::SVG::PathString - builder for SVG path strings.
Ocnode * child[8]
Definition quantize.cpp:33
TODO: insert short description here.
Conversion between SBasis and Bezier basis polynomials.
SPCSSAttr - interface for CSS Attributes.
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
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
@ SP_WIND_RULE_EVENODD
Definition style-enums.h:26
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