Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-fillet-chamfer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Author(s):
4 * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es>
5 *
6 * Copyright (C) 2014 Author(s)
7 *
8 *
9 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
10 */
11
12#include "lpe-fillet-chamfer.h"
13
15
16#include "display/curve.h"
17#include "helper/geom-curves.h"
18#include "helper/geom.h"
20#include "object/sp-rect.h"
21#include "object/sp-shape.h"
22#include "ui/knot/knot-holder.h"
23#include "ui/pack.h"
24#include "ui/tools/tool-base.h"
25#include "ui/util.h"
27
28// TODO due to internal breakage in glibmm headers, this must be last:
29#include <glibmm/i18n.h>
30
32
34 { FM_AUTO, N_("Auto"), "auto" },
35 { FM_ARC, N_("Force arc"), "arc" },
36 { FM_BEZIER, N_("Force bezier"), "bezier" }
37};
39
41 : Effect(lpeobject),
42 unit(_("Unit:"), _("Unit"), "unit", &wr, this, "px"),
43 nodesatellites_param("NodeSatellite_param", "NodeSatellite_param",
44 "nodesatellites_param", &wr, this),
45 method(_("Method:"), _("Method to calculate the fillet or chamfer"),
46 "method", FMConverter, &wr, this, FM_AUTO),
47 mode(_("Mode:"), _("Mode, e.g. fillet or chamfer"),
48 "mode", &wr, this, "F", true),
49 radius(_("Radius:"), _("Radius, in unit or %"), "radius", &wr,
50 this, 0.0),
51 chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps",
52 &wr, this, 1),
53 flexible(_("Radius in %"), _("Flexible radius size (%)"),
54 "flexible", &wr, this, false),
55 only_selected(_("Change only selected nodes"),
56 _("Change only selected nodes"), "only_selected", &wr, this,
57 false),
58 use_knot_distance(_("Use knots distance instead radius"),
59 _("Use knots distance instead radius"),
60 "use_knot_distance", &wr, this, true),
61 hide_knots(_("Hide knots"), _("Hide knots"), "hide_knots", &wr, this,
62 false),
63 apply_no_radius(_("Apply changes if radius = 0"), _("Apply changes if radius = 0"), "apply_no_radius", &wr, this, true),
64 apply_with_radius(_("Apply changes if radius > 0"), _("Apply changes if radius > 0"), "apply_with_radius", &wr, this, true),
65 _pathvector_nodesatellites(nullptr)
66{
67 // fix legacy < 1.2:
68 const gchar * satellites_param = getLPEObj()->getAttribute("satellites_param");
69 if (satellites_param){
70 getLPEObj()->setAttribute("nodesatellites_param", satellites_param);
71 };
84
85 radius.param_set_range(0.0, std::numeric_limits<double>::max());
88 chamfer_steps.param_set_range(1, std::numeric_limits<gint>::max());
93 helperpath = false;
94 previous_unit = Glib::ustring("");
95}
96
98{
99 SPLPEItem *splpeitem = const_cast<SPLPEItem *>(lpeItem);
100 auto shape = cast<SPShape>(splpeitem);
101 if (!shape) {
102 g_warning("LPE Fillet/Chamfer can only be applied to shapes (not groups).");
103 SPLPEItem *item = const_cast<SPLPEItem *>(lpeItem);
104 item->removeCurrentPathEffect(false);
105 }
106 auto rect = cast<SPRect>(splpeitem);
107 Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(shape->curve()->get_pathvector());
108 double power = radius;
109 double a = 0;
110 if (rect) {
111 double a = rect->getVisibleRx();
112 a = std::max(a, rect->getVisibleRy());
113 if (a) {
114 rect->setRx(true, 0);
115 rect->setRy(true, 0);
116 pathv = Geom::PathVector(Geom::Path(rect->getRect()));
117 if (!Geom::are_near(a, 0)) {
119 unit.param_set_value(getSPDoc()->getWidth().unit->abbr.c_str());
122 power = a;
123 }
124 }
125 }
126
127
128 NodeSatellites nodesatellites;
129 if (!flexible && Geom::are_near(a, 0)) {
130 auto trans = lpeItem->transform.inverse();
132 power *= ((trans.expansionX() + trans.expansionY()) / 2.0);
133 }
134
135 NodeSatelliteType nodesatellite_type = FILLET;
136
137 std::map<std::string, NodeSatelliteType> gchar_map_to_nodesatellite_type = boost::assign::map_list_of(
138 "F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE);
139
140 auto mode_str = mode.param_getSVGValue();
141 auto it = gchar_map_to_nodesatellite_type.find(mode_str.raw());
142
143 if (it != gchar_map_to_nodesatellite_type.end()) {
144 nodesatellite_type = it->second;
145 }
148 }
149 NodeSatellite nodesatellite(nodesatellite_type);
150 nodesatellite.setSteps(chamfer_steps);
151 nodesatellite.setAmount(power);
152 nodesatellite.setIsTime(flexible);
153 nodesatellite.setHasMirror(true);
154 nodesatellite.setHidden(hide_knots);
157}
158
160{
161 // use manage here, because after deletion of Effect object, others might
162 // still be pointing to this widget.
163 auto const vbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
164 vbox->set_margin(5);
165
166 for (auto const param: param_vector) {
167 if (!param->widget_is_visible) continue;
168
169 auto const widg = param->param_newWidget();
170 if (!widg) continue;
171
172 if (param->param_key == "radius") {
173 auto &scalar = dynamic_cast<UI::Widget::Scalar &>(*widg);
174 scalar.signal_value_changed().connect(
175 sigc::mem_fun(*this, &LPEFilletChamfer::updateAmount));
176 scalar.getSpinButton().set_width_chars(6);
177 } else if (param->param_key == "chamfer_steps") {
178 auto &scalar = dynamic_cast<UI::Widget::Scalar &>(*widg);
179 scalar.signal_value_changed().connect(
180 sigc::mem_fun(*this, &LPEFilletChamfer::updateChamferSteps));
181 scalar.getSpinButton().set_width_chars(3);
182 }
183
184 UI::pack_start(*vbox, *widg, true, true, 2);
185
186 if (auto const tip = param->param_getTooltip()) {
187 widg->set_tooltip_markup(*tip);
188 } else {
189 widg->set_tooltip_text({});
190 widg->set_has_tooltip(false);
191 }
192 }
193
194 // Fillet and chamfer containers
195
196 auto const fillet_container = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
197 Gtk::Button *fillet = Gtk::make_managed<Gtk::Button>(Glib::ustring(_("Fillet")));
198 fillet->signal_clicked().connect(
199 sigc::bind(sigc::mem_fun(*this, &LPEFilletChamfer::updateNodeSatelliteType), FILLET));
200
201 UI::pack_start(*fillet_container, *fillet, true, true, 2);
202 auto const inverse_fillet = Gtk::make_managed<Gtk::Button>(Glib::ustring(_("Inverse fillet")));
203 inverse_fillet->signal_clicked().connect(sigc::bind(
205 UI::pack_start(*fillet_container, *inverse_fillet, true, true, 2);
206
207 auto const chamfer_container = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
208 auto const chamfer = Gtk::make_managed<Gtk::Button>(Glib::ustring(_("Chamfer")));
209 chamfer->signal_clicked().connect(
210 sigc::bind(sigc::mem_fun(*this, &LPEFilletChamfer::updateNodeSatelliteType), CHAMFER));
211
212 UI::pack_start(*chamfer_container, *chamfer, true, true, 2);
213 auto const inverse_chamfer = Gtk::make_managed<Gtk::Button>(Glib::ustring(_("Inverse chamfer")));
214 inverse_chamfer->signal_clicked().connect(sigc::bind(
216 UI::pack_start(*chamfer_container, *inverse_chamfer, true, true, 2);
217
218 UI::pack_start(*vbox, *fillet_container, true, true, 2);
219 UI::pack_start(*vbox, *chamfer_container, true, true, 2);
220 return vbox;
221}
222
224{
225 if (!_pathvector_nodesatellites) { // empty item
226 return;
227 }
229 double power = radius;
230 if (!flexible) {
232 std::vector<SPLPEItem *> lpeitems = getCurrrentLPEItems();
233 if (lpeitems.size() == 1) {
234 sp_lpe_item = lpeitems[0];
235 auto trans = sp_lpe_item->transform.inverse();
236 power *= ((trans.expansionX() + trans.expansionY()) / 2.0);
237 }
238 }
242}
243
253
255{
256 if (!_pathvector_nodesatellites) { // empty item
257 return;
258 }
259 std::map<NodeSatelliteType, gchar const *> nodesatellite_type_to_gchar_map = boost::assign::map_list_of(
260 FILLET, "F")(INVERSE_FILLET, "IF")(CHAMFER, "C")(INVERSE_CHAMFER, "IC")(INVALID_SATELLITE, "KO");
261 mode.param_setValue((Glib::ustring)nodesatellite_type_to_gchar_map.at(nodesatellitetype));
266}
267
269{
270 if (!_pathvector_nodesatellites) { // empty item
271 return;
272 }
273 std::vector<SPLPEItem *> lpeitems = getCurrrentLPEItems();
274 if (lpeitems.size() == 1) {
275 sp_lpe_item = lpeitems[0];
278 } else {
281 for (size_t i = 0; i < nodesatellites.size(); ++i) {
282 for (size_t j = 0; j < nodesatellites[i].size(); ++j) {
283 Geom::Curve const &curve_in = pathv[i][j];
285 nodesatellites[i][j].setSelected(true);
286 } else {
287 nodesatellites[i][j].setSelected(false);
288 }
289 }
290 }
292 }
293 }
294}
295
297{
299 //fillet chamfer specific calls
302 //mandatory call
305 NodeSatellites nodesatellites = nodesatellites_param.data();
306 if (nodesatellites.empty()) {
307 doOnApply(lpeItem); // dont want _impl to not update versioning
308 nodesatellites = nodesatellites_param.data();
309 }
310 for (size_t i = 0; i < nodesatellites.size(); ++i) {
311 for (size_t j = 0; j < nodesatellites[i].size(); ++j) {
312 if (pathv.size() <= i || j >= count_path_curves(pathv[i])) {
313 // we are on the end of a open path
314 // for the moment we dont want to use
315 // this nodesatellite so simplest do nothing with it
316 continue;
317 }
318 Geom::Curve const &curve_in = pathv[i][j];
319 if (nodesatellites[i][j].is_time != flexible) {
320 nodesatellites[i][j].is_time = flexible;
321 double amount = nodesatellites[i][j].amount;
322 if (nodesatellites[i][j].is_time) {
323 double time = timeAtArcLength(amount, curve_in);
324 nodesatellites[i][j].amount = time;
325 } else {
326 double size = arcLengthAt(amount, curve_in);
327 nodesatellites[i][j].amount = size;
328 }
329 }
330 nodesatellites[i][j].hidden = hide_knots;
332 nodesatellites[i][j].setSelected(true);
333 }
334 }
335
336 if (pathv.size() > i && !pathv[i].closed()) {
337 nodesatellites[i].front().amount = 0;
338 nodesatellites[i].back().amount = 0;
339 }
340 }
343 }
344 if (is_load || _adjust_path) {
345 double power = radius;
346 if (!flexible) {
348 }
349 _adjust_path = false; // not wait till effect finish
350 NodeSatelliteType nodesatellite_type = FILLET;
351 std::map<std::string, NodeSatelliteType> gchar_map_to_nodesatellite_type = boost::assign::map_list_of(
352 "F", FILLET)("IF", INVERSE_FILLET)("C", CHAMFER)("IC", INVERSE_CHAMFER)("KO", INVALID_SATELLITE);
353 auto mode_str = mode.param_getSVGValue();
354 auto it = gchar_map_to_nodesatellite_type.find(mode_str.raw());
355 if (it != gchar_map_to_nodesatellite_type.end()) {
356 nodesatellite_type = it->second;
357 }
358 NodeSatellite nodesatellite(nodesatellite_type);
359 nodesatellite.setSteps(chamfer_steps);
360 nodesatellite.setAmount(power);
361 nodesatellite.setIsTime(flexible);
362 nodesatellite.setHasMirror(true);
363 nodesatellite.setHidden(hide_knots);
368 } else {
372 }
373 } else {
374 g_warning("LPE Fillet can only be applied to shapes (not groups).");
375 }
376}
377
378void
382
383void
384LPEFilletChamfer::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
385{
386 hp_vec.push_back(_hp);
387}
388
389void
390LPEFilletChamfer::addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps)
391{
393 double path_subdivision = 1.0 / steps;
394 for (size_t i = 1; i < steps; i++) {
395 Geom::Point chamfer_step = path_chamfer.pointAt(path_subdivision * i);
396 tmp_path.appendNew<Geom::LineSegment>(chamfer_step);
397 }
398 tmp_path.appendNew<Geom::LineSegment>(end_arc_point);
399}
400
403{
404 if (!_pathvector_nodesatellites) { //empty item pathv with lpe
405 return path_in;
406 }
407 const double GAP_HELPER = 0.00001;
408 Geom::PathVector path_out;
409 std::size_t path = -1;
410 const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0);
413 for (const auto &path_it : pathv) {
414 ++ path;
415 Geom::Path tmp_path;
416 double time0 = 0;
417 std::size_t curve = -1;
418 Geom::Path::const_iterator curve_it1 = path_it.begin();
419 Geom::Path::const_iterator curve_endit = path_it.end_default();
420 if (path_it.closed()) {
421 auto const &closingline = path_it.back_closed();
422 // the closing line segment is always of type
423 // Geom::LineSegment.
424 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
425 // closingline.isDegenerate() did not work, because it only checks for
426 // *exact* zero length, which goes wrong for relative coordinates and
427 // rounding errors...
428 // the closing line segment has zero-length. So stop before that one!
429 curve_endit = path_it.end_open();
430 }
431 }
432 size_t tcurves = count_path_curves(pathv[path]);
433 while (curve_it1 != curve_endit) {
434 ++curve;
435 size_t next_index = curve + 1;
436 if (curve == tcurves - 1 && pathv[path].closed()) {
437 next_index = 0;
438 }
439 //append last extreme of paths on open paths
440 if (curve == tcurves - 1 && !pathv[path].closed()) { // the path is open and we are at
441 // end of path
442 if (time0 != 1) { // Previous nodesatellite not at 100% amount
443 Geom::Curve *last_curve = curve_it1->portion(time0, 1);
444 last_curve->setInitial(tmp_path.finalPoint());
445 tmp_path.append(*last_curve);
446 }
447 ++curve_it1;
448 continue;
449 }
450 Geom::Curve const &curve_it2 = pathv.at(path).at(next_index);
451 NodeSatellite nodesatellite = nodesatellites.at(path).at(next_index);
452
453 if (!curve) { //curve == 0
454 if (!path_it.closed()) {
455 time0 = 0;
456 } else {
457 time0 = nodesatellites[path][0].time(*curve_it1);
458 }
459 }
460 double s = nodesatellite.arcDistance(curve_it2);
461 double time1 = nodesatellite.time(s, true, (*curve_it1));
462 double time2 = nodesatellite.time(curve_it2);
463 if (time1 <= time0) {
464 time1 = time0;
465 }
466 if (time2 > 1) {
467 time2 = 1;
468 }
469 Geom::Curve *knot_curve_1 = curve_it1->portion(time0, time1);
470 Geom::Curve *knot_curve_2 = curve_it2.portion(time2, 1);
471 if (curve > 0) {
472 knot_curve_1->setInitial(tmp_path.finalPoint());
473 } else {
474 tmp_path.start((*curve_it1).pointAt(time0));
475 }
476
477 Geom::Point start_arc_point = knot_curve_1->finalPoint();
478 Geom::Point end_arc_point = curve_it2.pointAt(time2);
479 //add a gap helper
480 if (time2 == 1) {
481 end_arc_point = curve_it2.pointAt(time2 - GAP_HELPER);
482 }
483 if (time1 == time0) {
484 start_arc_point = curve_it1->pointAt(time1 + GAP_HELPER);
485 }
486 Geom::Point curveit1 = curve_it1->finalPoint();
487 Geom::Point curveit2 = curve_it2.initialPoint();
488 double k1 = distance(start_arc_point, curveit1) * K;
489 double k2 = distance(curve_it2.initialPoint(), end_arc_point) * K;
490 Geom::CubicBezier const *cubic_1 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_1);
491 Geom::CubicBezier const *cubic_2 = dynamic_cast<Geom::CubicBezier const *>(&*knot_curve_2);
492 Geom::Ray ray_1(start_arc_point, curveit1);
493 Geom::Ray ray_2(curveit2, end_arc_point);
494 if (cubic_1) {
495 ray_1.setPoints((*cubic_1)[2], start_arc_point);
496 }
497 if (cubic_2) {
498 ray_2.setPoints(end_arc_point, (*cubic_2)[1]);
499 }
500 bool ccw_toggle = cross(curveit1 - start_arc_point, end_arc_point - start_arc_point) < 0;
501 double angle = angle_between(ray_1, ray_2, ccw_toggle);
502 double handle_angle_1 = ray_1.angle() - angle;
503 double handle_angle_2 = ray_2.angle() + angle;
504 if (ccw_toggle) {
505 handle_angle_1 = ray_1.angle() + angle;
506 handle_angle_2 = ray_2.angle() - angle;
507 }
508 Geom::Point handle_1 = Geom::Point::polar(ray_1.angle(), k1) + start_arc_point;
509 Geom::Point handle_2 = end_arc_point - Geom::Point::polar(ray_2.angle(), k2);
510 Geom::Point inverse_handle_1 = Geom::Point::polar(handle_angle_1, k1) + start_arc_point;
511 Geom::Point inverse_handle_2 = end_arc_point - Geom::Point::polar(handle_angle_2, k2);
512 if (time0 == 1) {
513 handle_1 = start_arc_point;
514 inverse_handle_1 = start_arc_point;
515 }
516 //remove gap helper
517 if (time2 == 1) {
518 end_arc_point = curve_it2.pointAt(time2);
519 }
520 if (time1 == time0) {
521 start_arc_point = curve_it1->pointAt(time0);
522 }
523 if (time1 != 1 && !Geom::are_near(angle, Geom::rad_from_deg(360)) &&
524 !curve_it1->isDegenerate() && !curve_it2.isDegenerate())
525 {
526 if (time1 != time0 || (time1 == 1 && time0 == 1)) {
527 if (!knot_curve_1->isDegenerate()) {
528 tmp_path.append(*knot_curve_1);
529 }
530 }
531 NodeSatelliteType type = nodesatellite.nodesatellite_type;
532 size_t steps = nodesatellite.steps;
533 if (!steps) steps = 1;
534 Geom::Line const x_line(Geom::Point(0, 0), Geom::Point(1, 0));
535 Geom::Line const angled_line(start_arc_point, end_arc_point);
536 double arc_angle = Geom::angle_between(x_line, angled_line);
537 double radius = Geom::distance(start_arc_point, middle_point(start_arc_point, end_arc_point)) /
538 sin(angle / 2.0);
539 Geom::Coord rx = radius;
540 Geom::Coord ry = rx;
541 bool eliptical = (is_straight_curve(*curve_it1) &&
542 is_straight_curve(curve_it2) && method != FM_BEZIER) ||
543 method == FM_ARC;
544 switch (type) {
545 case CHAMFER:
546 {
547 Geom::Path path_chamfer;
548 path_chamfer.start(tmp_path.finalPoint());
549 if (eliptical) {
550 ccw_toggle = !ccw_toggle;
551 path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, false, ccw_toggle, end_arc_point);
552 } else {
553 path_chamfer.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
554 }
555 addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
556 }
557 break;
558 case INVERSE_CHAMFER:
559 {
560 Geom::Path path_chamfer;
561 path_chamfer.start(tmp_path.finalPoint());
562 if (eliptical) {
563 path_chamfer.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, false, ccw_toggle, end_arc_point);
564 } else {
565 path_chamfer.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
566 }
567 addChamferSteps(tmp_path, path_chamfer, end_arc_point, steps);
568 }
569 break;
570 case INVERSE_FILLET:
571 {
572 if (eliptical) {
573 tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, false, ccw_toggle, end_arc_point);
574 } else {
575 tmp_path.appendNew<Geom::CubicBezier>(inverse_handle_1, inverse_handle_2, end_arc_point);
576 }
577 }
578 break;
579 default: //fillet
580 {
581 if (eliptical) {
582 ccw_toggle = !ccw_toggle;
583 tmp_path.appendNew<Geom::EllipticalArc>(rx, ry, arc_angle, false, ccw_toggle, end_arc_point);
584 } else {
585 tmp_path.appendNew<Geom::CubicBezier>(handle_1, handle_2, end_arc_point);
586 }
587 }
588 break;
589 }
590 } else {
591 if (!knot_curve_1->isDegenerate()) {
592 tmp_path.append(*knot_curve_1);
593 }
594 }
595 ++curve_it1;
596 time0 = time2;
597 }
598 if (path_it.closed()) {
599 tmp_path.close();
600 }
601 path_out.push_back(tmp_path);
602 }
603 if (helperpath) {
604 _hp = path_out;
606 }
607 _hp.clear();
608 return path_out;
609}
610
611} // namespace Inkscape::LivePathEffect
612
613/*
614 Local Variables:
615 mode:c++
616 c-file-style:"stroustrup"
617 c-file-offset:((innamespace . 0)(inline-open . 0)(case-label . +))
618 indent-tabs-mode:nil
619 fill-column:99
620 End:
621*/
622// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
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.
virtual bool isDegenerate() const =0
Check whether the curve has exactly zero length.
virtual void setInitial(Point const &v)=0
Change the starting point of the curve.
virtual Curve * portion(Coord a, Coord b) const =0
Create a curve that corresponds to a part of this curve.
virtual Point pointAt(Coord t) const
Evaluate the curve at a specified time value.
Definition curve.h:110
Elliptical arc curve.
Infinite line on a plane.
Definition line.h:53
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
Path & at(size_type index)
Definition pathvector.h:161
void clear()
Remove all paths from the vector.
Definition pathvector.h:195
bool empty() const
Check whether the vector contains any paths.
Definition pathvector.h:145
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
Point pointAt(Coord t) const
Get the point at the specified time value.
Definition path.cpp:449
void append(Curve *curve)
Add a new curve to the end of the path.
Definition path.h:750
Curve const & at(size_type i) const
Access a curve by index.
Definition path.h:438
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
Straight ray from a specific point to infinity.
Definition ray.h:53
void setPoints(Point const &a, Point const &b)
Definition ray.h:75
Coord angle() const
Definition ray.h:73
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
bool isNodePointSelected(Geom::Point const &nodePoint) const
Definition effect.cpp:1258
std::vector< SPLPEItem * > getCurrrentLPEItems() const
Definition effect.cpp:1187
Geom::PathVector pathvector_before_effect
Definition effect.h:174
EffectType effectType() const
Definition effect.cpp:1182
Geom::PathVector pathvector_after_effect
Definition effect.h:175
LivePathEffectObject * getLPEObj()
Definition effect.h:151
void param_setValue(Glib::ustring newvalue, bool write=false)
Definition hidden.cpp:71
Glib::ustring param_getSVGValue() const override
Definition hidden.cpp:53
void doBeforeEffect(SPLPEItem const *lpeItem) override
Is performed each time before the effect is updated.
LPEFilletChamfer(LivePathEffectObject *lpeobject)
void addChamferSteps(Geom::Path &tmp_path, Geom::Path path_chamfer, Geom::Point end_arc_point, size_t steps)
void updateNodeSatelliteType(NodeSatelliteType nodesatellitetype)
PathVectorNodeSatellites * _pathvector_nodesatellites
void doOnApply(SPLPEItem const *lpeItem) override
Is performed a single time when the effect is freshly applied to a path.
Geom::PathVector doEffect_path(Geom::PathVector const &path_in) override
Gtk::Widget * newWidget() override
This creates a managed widget.
void addCanvasIndicators(SPLPEItem const *, 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 setSelected(PathVectorNodeSatellites *_pathvector_nodesatellites)
void setPathVectorNodeSatellites(PathVectorNodeSatellites *pathVectorNodeSatellites, bool write=true)
void param_set_digits(unsigned digits)
void param_set_range(double min, double max)
void param_set_increments(double step, double page)
const gchar * get_abbreviation() const
Definition unit.cpp:77
void param_set_value(const gchar *unit)
Definition unit.cpp:68
A labelled text box, with spin buttons and optional icon, for entering arbitrary number values.
Definition scalar.h:34
Glib::SignalProxy< void()> signal_value_changed()
Signal raised when the spin button's value changes.
Definition scalar.cpp:159
Simplified management of enumerations of svg items with UI labels.
Definition enums.h:42
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Definition units.cpp:525
NodeSatellite a per node holder of data.
NodeSatelliteType nodesatellite_type
void setHasMirror(bool set_has_mirror)
void setSteps(size_t set_steps)
void setHidden(bool set_hidden)
void setAmount(double set_amount)
void setIsTime(bool set_is_time)
double arcDistance(Geom::Curve const &curve_in) const
Get the length of the nodesatellite in curve_in.
double time(Geom::Curve const &curve_in, bool inverse=false) const
Get the time position of the nodesatellite in curve_in.
PathVectorNodeSatellites a class to manage nodesatellites in a pathvector.
void setPathVector(Geom::PathVector pathv)
void updateNodeSatelliteType(NodeSatelliteType nodesatellitetype, bool apply_no_radius, bool apply_with_radius, bool only_selected)
void recalculateForNewPathVector(Geom::PathVector const pathv, NodeSatellite const S)
void updateSteps(size_t steps, bool apply_no_radius, bool apply_with_radius, bool only_selected)
void setNodeSatellites(NodeSatellites nodesatellites)
void updateAmount(double radius, bool apply_no_radius, bool apply_with_radius, bool only_selected, bool use_knot_distance, bool flexible)
Geom::Scale getDocumentScale(bool computed=true) const
Returns document scale as defined by width/height (in pixels) and viewBox (real world to user-units).
Definition document.cpp:773
Geom::Affine transform
Definition sp-item.h:138
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
char const * getAttribute(char const *name) const
Elliptical arc curve.
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Definition geom-curves.h:22
double timeAtArcLength(double const A, Geom::Curve const &curve_in)
Calculate the time in curve_in with a size of A.
double arcLengthAt(double const A, Geom::Curve const &curve_in)
Calculate the size in curve_in with a point at A.
NodeSatellite – a per node holder of data.
NodeSatelliteType
@ INVERSE_FILLET
@ INVERSE_CHAMFER
@ CHAMFER
@ INVALID_SATELLITE
std::vector< std::vector< NodeSatellite > > NodeSatellites
double Coord
Floating point type used to store coordinates.
Definition coord.h:76
@ X
Definition coord.h:48
size_t count_path_curves(Geom::Path const &path)
Definition geom.cpp:823
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.
SPItem * item
Angle distance(Angle const &a, Angle const &b)
Definition angle.h:163
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
double angle_between(Line const &l1, Line const &l2)
Definition line.h:456
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
SBasisN< n > sin(LinearN< n > bo, int k)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Point middle_point(LineSegment const &_segment)
Live Path Effects code.
static const Util::EnumData< Filletmethod > FilletmethodData[]
static const Util::EnumDataConverter< Filletmethod > FMConverter(FilletmethodData, FM_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
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
int mode
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
Definition curve.h:24