Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-roughen.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
6/* Authors:
7 * Jabier Arraiza Cenoz <jabier.arraiza@marker.es>
8 *
9 * Thanks to all people involved specially to Josh Andler for the idea and to the
10 * original extensions authors.
11 *
12 * Copyright (C) 2014 Authors
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include "lpe-roughen.h"
18
19#include <boost/functional/hash.hpp>
20
21#include <glibmm/i18n.h>
22#include <gtkmm/box.h>
23#include <gtkmm/label.h>
24#include <gtkmm/separator.h>
25
26#include "preferences.h"
27
28#include "display/curve.h"
29#include "helper/geom.h"
30#include "object/sp-lpe-item.h"
31#include "ui/pack.h"
33
34namespace Inkscape {
35namespace LivePathEffect {
36
38 { DM_SEGMENTS, N_("Number of segments"), "segments" },
39 { DM_SIZE, N_("Segment size"), "size" }
40};
42
44 { HM_ALONG_NODES, N_("Along nodes"), "along" },
45 { HM_RAND, N_("Random"), "rand" },
46 { HM_RETRACT, N_("Retract"), "retract" },
47 { HM_SMOOTH, N_("Smooth"), "smooth" }
48};
50
52 : Effect(lpeobject)
53 , method(_("Method"), _("<b>Segment size:</b> add nodes to path evenly; <b>Number of segments:</b> add nodes between existing nodes"), "method", DMConverter, &wr, this, DM_SIZE)
54 , max_segment_size(_("Segment size"), _("Add nodes to path evenly. Choose <b>Segment size</b> method from the dropdown to use this subdivision method."), "max_segment_size", &wr, this, 10)
55 , segments(_("Number of segments"), _("Add nodes between existing nodes. Choose <b>Number of segments</b> method from the dropdown to use this subdivision method."), "segments", &wr, this, 2)
56 , displace_x(_("Displace ←→"), _("Maximal displacement in x direction"), "displace_x", &wr, this, 10.)
57 , displace_y(_("Displace ↑↓"), _("Maximal displacement in y direction"), "displace_y", &wr, this, 10.)
58 , global_randomize(_("Global randomize"), _("Global displacement in all directions"), "global_randomize", &wr, this, 1.)
59 , handles(_("Direction"), _("Options for handle direction"), "handles", HMConverter, &wr, this, HM_ALONG_NODES)
60 , shift_nodes(_("Apply displacement"), _("Uncheck to use this LPE for just adding nodes, without roughening; useful for further interactive processing."), "shift_nodes", &wr, this, true)
61 , fixed_displacement(_("Fixed displacement"), _("Fixed displacement, 1/3 of segment length"), "fixed_displacement",
62 &wr, this, false)
63 , spray_tool_friendly(_("Spray Tool friendly"), _("For use with Spray Tool in copy mode"), "spray_tool_friendly",
64 &wr, this, false)
65{
76
77 displace_x.param_set_range(0., std::numeric_limits<double>::max());
78 displace_y.param_set_range(0., std::numeric_limits<double>::max());
79 global_randomize.param_set_range(0., std::numeric_limits<double>::max());
80
81 max_segment_size.param_set_range(0., std::numeric_limits<double>::max());
84
88 seed = 0;
90}
91
92LPERoughen::~LPERoughen() = default;
93
94void LPERoughen::doOnApply(SPLPEItem const *lpeitem)
95{
97 if (bbox) {
99
100 for (auto const param: param_vector) {
101 auto const pref_path = Glib::ustring::compose("/live_effects/%1/%2",
102 LPETypeConverter.get_key(effectType()),
103 param->param_key);
104 if (prefs->getEntry(pref_path).isSet())
105 continue;
106
107 if (param->param_key == "max_segment_size") {
108 auto const minor = std::min(bbox->width(), bbox->height());
109 auto const max_segment_size_str = Inkscape::ustring::format_classic(minor / 50.0);
110 param->param_readSVGValue(max_segment_size_str.c_str());
111 } else if (param->param_key == "displace_x") {
112 auto const displace_x_str = Inkscape::ustring::format_classic(bbox->width() / 150.0);
113 param->param_readSVGValue(displace_x_str.c_str());
114 } else if (param->param_key == "displace_y") {
115 auto const displace_y_str = Inkscape::ustring::format_classic(bbox->height() / 150.0);
116 param->param_readSVGValue(displace_y_str.c_str());
117 }
118 }
120 }
121 lpeversion.param_setValue("1.2", true);
122}
123
125{
126 if (spray_tool_friendly && seed == 0 && lpeitem->getId()) {
127 std::string id_item(lpeitem->getId());
128 long seed = static_cast<long>(boost::hash_value(id_item));
130 }
134 if (lpeversion.param_getSVGValue() < "1.1") {
135 srand(1);
136 } else {
139 }
140}
141
143{
144 auto const vbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 2);
145 vbox->set_margin(5);
146
147 std::vector<Parameter *>::iterator it = param_vector.begin();
148 while (it != param_vector.end()) {
149 if ((*it)->widget_is_visible) {
150 Parameter *param = *it;
151 auto widg = param->param_newWidget();
152 if (param->param_key == "method") {
153 auto const method_label = Gtk::make_managed<Gtk::Label>(
154 Glib::ustring(_("<b>Resolution</b>")), Gtk::Align::START);
155 method_label->set_use_markup(true);
156 UI::pack_start(*vbox, *method_label, false, false, 2);
157 UI::pack_start(*vbox, *Gtk::make_managed<Gtk::Separator>(Gtk::Orientation::HORIZONTAL),
159 }
160 if (param->param_key == "handles") {
161 auto const options = Gtk::make_managed<Gtk::Label>(
162 Glib::ustring(_("<b>Options</b>")), Gtk::Align::START);
163 options->set_use_markup(true);
164 UI::pack_start(*vbox, *options, false, false, 2);
165 UI::pack_start(*vbox, *Gtk::make_managed<Gtk::Separator>(Gtk::Orientation::HORIZONTAL),
167 }
168
169 if (widg) {
170 UI::pack_start(*vbox, *widg, true, true, 2);
171
172 if (auto const tip = param->param_getTooltip()) {
173 widg->set_tooltip_markup(*tip);
174 } else {
175 widg->set_tooltip_text("");
176 widg->set_has_tooltip(false);
177 }
178 }
179 }
180 ++it;
181 }
182
183 return vbox;
184}
185
186double LPERoughen::sign(double random_number)
187{
188 if (lpeversion.param_getSVGValue() < "1.1") {
189 if (rand() % 100 < 49) {
190 random_number *= -1.;
191 }
192 }
193 return random_number;
194}
195
196Geom::Point LPERoughen::randomize(double max_length, bool is_node)
197{
198 double factor = 1.0 / 3.0;
199 if (is_node) {
200 factor = 1.0;
201 }
202 double displace_x_parsed = displace_x * global_randomize * factor;
203 double displace_y_parsed = displace_y * global_randomize * factor;
204 Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed));
205 if (fixed_displacement) {
206 Geom::Ray ray(Geom::Point(0, 0), output);
207 output = Geom::Point::polar(ray.angle(), max_length);
208 }
209 return output;
210}
211
213{
215 curve.clear();
216 for (const auto &path_it : original_pathv) {
217 if (path_it.empty())
218 continue;
219
220 Geom::Path::const_iterator curve_it1 = path_it.begin();
221 Geom::Path::const_iterator curve_it2 = ++(path_it.begin());
222 Geom::Path::const_iterator curve_endit = path_it.end_default();
223 Geom::PathVector nCurve;
224 Geom::Point prev(0, 0);
225 Geom::Point last_move(0, 0);
226 nCurve.push_back(Geom::Path{curve_it1->initialPoint()});
227 if (path_it.closed()) {
228 const Geom::Curve &closingline = path_it.back_closed();
229 // the closing line segment is always of type
230 // Geom::LineSegment.
231 if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
232 // closingline.isDegenerate() did not work, because it only checks for
233 // *exact* zero length, which goes wrong for relative coordinates and
234 // rounding errors...
235 // the closing line segment has zero-length. So stop before that one!
236 curve_endit = path_it.end_open();
237 }
238 }
239 while (curve_it1 != curve_endit) {
240 auto const cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
241 if (cubic) {
242 nCurve.back().appendNew<Geom::CubicBezier>((*cubic)[1] + last_move, (*cubic)[2], curve_it1->finalPoint());
243 } else {
244 nCurve.back().appendNew<Geom::LineSegment>(curve_it1->finalPoint());
245 }
246 last_move = Geom::Point(0, 0);
247 double length = curve_it1->length(0.01);
248 std::size_t splits = 0;
249 if (method == DM_SEGMENTS) {
250 splits = segments;
251 } else {
252 splits = ceil(length / max_segment_size);
253 }
254 auto const original = std::unique_ptr<Geom::Curve>(get_last_segment(nCurve)->duplicate());
255 for (unsigned int t = 1; t <= splits; t++) {
256 if (t == splits && splits != 1) {
257 continue;
258 }
260 if (splits == 1) {
261 tmp = jitter(*get_last_segment(nCurve), prev, last_move);
262 } else {
263 bool last = false;
264 if (t == splits - 1) {
265 last = true;
266 }
267 double time =
268 Geom::nearest_time(original->pointAt((1. / (double)splits) * t), *get_last_segment(nCurve));
269 tmp = addNodesAndJitter(*get_last_segment(nCurve), prev, last_move, time, last);
270 }
271 if (nCurve.curveCount() > 1) {
272 backspace(nCurve);
273 pathvector_append_continuous(nCurve, std::move(tmp), 0.001);
274 } else {
275 nCurve = std::move(tmp);
276 }
277 }
278 ++curve_it1;
279 ++curve_it2;
280 }
281 if (path_it.closed()) {
282 if (handles == HM_SMOOTH && curve_it1 == curve_endit) {
283 nCurve.reverse();
284 Geom::CubicBezier const *cubic_start = dynamic_cast<Geom::CubicBezier const *>(get_first_segment(nCurve));
285 Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(get_last_segment(nCurve));
286 Geom::Point oposite = get_first_segment(nCurve)->pointAt(1.0 / 3.0);
287 if (cubic_start) {
288 Geom::Ray ray((*cubic_start)[1], (*cubic_start)[0]);
289 double dist = Geom::distance((*cubic_start)[1], (*cubic_start)[0]);
290 oposite = Geom::Point::polar(ray.angle(), dist) + (*cubic_start)[0];
291 }
292 Geom::Path out;
293 if (cubic) {
294 out.start((*cubic)[0]);
295 out.appendNew<Geom::CubicBezier>((*cubic)[1], oposite, (*cubic)[3]);
296 } else {
297 out.start(get_last_segment(nCurve)->initialPoint());
298 out.appendNew<Geom::CubicBezier>(get_last_segment(nCurve)->initialPoint(), oposite, nCurve.finalPoint());
299 }
300 backspace(nCurve);
301 pathvector_append_continuous(nCurve, std::move(out), 0.001);
302 nCurve.reverse();
303 }
304 if (handles == HM_ALONG_NODES && curve_it1 == curve_endit) {
305 nCurve.reverse();
306 if (auto cubic = dynamic_cast<Geom::CubicBezier const *>(get_last_segment(nCurve))) {
307 Geom::Path out;
308 out.start((*cubic)[0]);
309 out.appendNew<Geom::CubicBezier>((*cubic)[1], (*cubic)[2] - ((*cubic)[3] - get_first_segment(nCurve)->initialPoint()), (*cubic)[3]);
310 backspace(nCurve);
311 pathvector_append_continuous(nCurve, std::move(out), 0.001);
312 }
313 nCurve.reverse();
314 }
315 move_endpoints(nCurve, get_last_segment(nCurve)->finalPoint(), get_last_segment(nCurve)->finalPoint());
316 closepath_current(nCurve.back());
317 }
318 pathvector_append(curve, std::move(nCurve));
319 }
320}
321
322Geom::Path LPERoughen::addNodesAndJitter(Geom::Curve const &A, Geom::Point &prev, Geom::Point &last_move, double t, bool last)
323{
324 Geom::Path out;
325 auto const cubic = dynamic_cast<Geom::CubicBezier const *>(&A);
326 double max_length = Geom::distance(A.initialPoint(), A.pointAt(t)) / 3.0;
327 Geom::Point point_a1;
328 Geom::Point point_a2;
329 Geom::Point point_a3;
330 Geom::Point point_b1;
331 Geom::Point point_b2;
332 Geom::Point point_b3;
333 if (shift_nodes) {
334 point_a3 = randomize(max_length, true);
335 if (last) {
336 point_b3 = randomize(max_length, true);
337 }
338 }
339 if (handles == HM_RAND || handles == HM_SMOOTH) {
340 point_a1 = randomize(max_length);
341 point_a2 = randomize(max_length);
342 point_b1 = randomize(max_length);
343 if (last) {
344 point_b2 = randomize(max_length);
345 }
346 } else {
347 point_a2 = point_a3;
348 point_b1 = point_a3;
349 if (last) {
350 point_b2 = point_b3;
351 }
352 }
353 if (handles == HM_SMOOTH) {
354 if (cubic) {
355 std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
356 std::vector<Geom::Point> seg1 = div.first.controlPoints(), seg2 = div.second.controlPoints();
357 Geom::Ray ray(seg1[3] + point_a3, seg2[1] + point_a3);
358 double length = max_length;
359 if (!fixed_displacement) {
360 length = Geom::distance(seg1[3] + point_a3, seg2[1] + point_a3);
361 }
362 point_b1 = seg1[3] + point_a3 + Geom::Point::polar(ray.angle(), length);
363 point_b2 = seg2[2];
364 point_b3 = seg2[3] + point_b3;
365 point_a3 = seg1[3] + point_a3;
366 ray.setPoints(prev, A.initialPoint());
367 point_a1 = A.initialPoint() + Geom::Point::polar(ray.angle(), max_length);
368 if (last) {
369 Geom::Path b2(point_b3);
370 b2.appendNew<Geom::LineSegment>(point_a3);
371 length = max_length;
372 ray.setPoints(point_b3, point_b2);
373 if (!fixed_displacement) {
374 length = Geom::distance(b2.pointAt(1.0 / 3.0), point_b3);
375 }
376 point_b2 = point_b3 + Geom::Point::polar(ray.angle(), length);
377 }
378 ray.setPoints(point_b1, point_a3);
379 point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_length);
380 if (last) {
381 prev = point_b2;
382 } else {
383 prev = point_a2;
384 }
385 out.start(seg1[0]);
386 out.appendNew<Geom::CubicBezier>(point_a1, point_a2, point_a3);
387 out.appendNew<Geom::CubicBezier>(point_b1, point_b2, point_b3);
388 } else {
389 Geom::Ray ray(A.pointAt(t) + point_a3, A.pointAt(t + (t / 3)));
390 double length = max_length;
391 if (!fixed_displacement) {
392 length = Geom::distance(A.pointAt(t) + point_a3, A.pointAt(t + (t / 3)));
393 }
394 point_b1 = A.pointAt(t) + point_a3 + Geom::Point::polar(ray.angle(), length);
395 point_b2 = A.pointAt(t + ((t / 3) * 2));
396 point_b3 = A.finalPoint() + point_b3;
397 point_a3 = A.pointAt(t) + point_a3;
398 ray.setPoints(prev, A.initialPoint());
399 point_a1 = A.initialPoint() + Geom::Point::polar(ray.angle(), max_length);
400 if (prev == Geom::Point(0, 0)) {
401 point_a1 = randomize(max_length);
402 }
403 if (last) {
404 Geom::Path b2(point_b3);
405 b2.appendNew<Geom::LineSegment>(point_a3);
406 length = max_length;
407 ray.setPoints(point_b3, point_b2);
408 if (!fixed_displacement) {
409 length = Geom::distance(b2.pointAt(1.0 / 3.0), point_b3);
410 }
411 point_b2 = point_b3 + Geom::Point::polar(ray.angle(), length);
412 }
413 ray.setPoints(point_b1, point_a3);
414 point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_length);
415 if (last) {
416 prev = point_b2;
417 } else {
418 prev = point_a2;
419 }
420 out.start(A.initialPoint());
421 out.appendNew<Geom::CubicBezier>(point_a1, point_a2, point_a3);
422 out.appendNew<Geom::CubicBezier>(point_b1, point_b2, point_b3);
423 }
424 } else if (handles == HM_RETRACT) {
425 out.start(A.initialPoint());
426 out.appendNew<Geom::LineSegment>(A.pointAt(t) + point_a3);
427 if (cubic && !last) {
428 std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
429 std::vector<Geom::Point> seg2 = div.second.controlPoints();
430 out.appendNew<Geom::CubicBezier>(seg2[1], seg2[2], seg2[3]);
431 } else {
432 out.appendNew<Geom::LineSegment>(A.finalPoint() + point_b3);
433 }
434 } else if (handles == HM_ALONG_NODES) {
435 if (cubic) {
436 std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
437 std::vector<Geom::Point> seg1 = div.first.controlPoints(), seg2 = div.second.controlPoints();
438 out.start(seg1[0]);
439 out.appendNew<Geom::CubicBezier>(seg1[1] + last_move, seg1[2] + point_a3, seg1[3] + point_a3);
440 last_move = point_a3;
441 if (last) {
442 last_move = point_b3;
443 }
444 out.appendNew<Geom::CubicBezier>(seg2[1] + point_a3, seg2[2] + point_b3, seg2[3] + point_b3);
445 } else {
446 out.start(A.initialPoint());
447 out.appendNew<Geom::LineSegment>(A.pointAt(t) + point_a3);
448 out.appendNew<Geom::LineSegment>(A.finalPoint() + point_b3);
449 }
450 } else if (handles == HM_RAND) {
451 if (cubic) {
452 std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
453 std::vector<Geom::Point> seg1 = div.first.controlPoints(), seg2 = div.second.controlPoints();
454 out.start(seg1[0]);
455 out.appendNew<Geom::CubicBezier>(seg1[1] + point_a1, seg1[2] + point_a2 + point_a3, seg1[3] + point_a3);
456 out.appendNew<Geom::CubicBezier>(seg2[1] + point_a3 + point_b1, seg2[2] + point_b2 + point_b3, seg2[3] + point_b3);
457 } else {
458 out.start(A.initialPoint());
459 out.appendNew<Geom::LineSegment>(A.pointAt(t) + point_a3);
460 out.appendNew<Geom::LineSegment>(A.finalPoint() + point_b3);
461 }
462 }
463 return out;
464}
465
467{
468 Geom::Path out;
469 auto const cubic = dynamic_cast<Geom::CubicBezier const *>(&A);
470 double max_length = Geom::distance(A.initialPoint(), A.finalPoint()) / 3.0;
471 Geom::Point point_a1;
472 Geom::Point point_a2;
473 Geom::Point point_a3;
474 if (shift_nodes) {
475 point_a3 = randomize(max_length, true);
476 }
477 if (handles == HM_RAND || handles == HM_SMOOTH) {
478 point_a1 = randomize(max_length);
479 point_a2 = randomize(max_length);
480 }
481 if (handles == HM_SMOOTH) {
482 if (cubic) {
483 Geom::Ray ray(prev, A.initialPoint());
484 point_a1 = Geom::Point::polar(ray.angle(), max_length);
485 if (prev == Geom::Point(0, 0)) {
486 point_a1 = A.pointAt(1.0 / 3.0) + randomize(max_length);
487 }
488 ray.setPoints((*cubic)[3] + point_a3, (*cubic)[2] + point_a3);
489 if (lpeversion.param_getSVGValue() < "1.1") {
490 point_a2 = randomize(max_length, ray.angle());
491 } else {
492 point_a2 = randomize(max_length, false);
493 }
494 prev = (*cubic)[2] + point_a2;
495 out.start((*cubic)[0]);
496 out.appendNew<Geom::CubicBezier>((*cubic)[0] + point_a1, (*cubic)[2] + point_a2 + point_a3, (*cubic)[3] + point_a3);
497 } else {
498 Geom::Ray ray(prev, A.initialPoint());
499 point_a1 = Geom::Point::polar(ray.angle(), max_length);
500 if (prev == Geom::Point(0, 0)) {
501 point_a1 = A.pointAt(1.0 / 3.0) + randomize(max_length);
502 }
503 ray.setPoints(A.finalPoint() + point_a3, A.pointAt((1.0 / 3.0) * 2) + point_a3);
504 if (lpeversion.param_getSVGValue() < "1.1") {
505 point_a2 = randomize(max_length, ray.angle());
506 } else {
507 point_a2 = randomize(max_length, false);
508 }
509 prev = A.pointAt((1.0 / 3.0) * 2) + point_a2 + point_a3;
510 out.start(A.initialPoint());
511 out.appendNew<Geom::CubicBezier>(A.initialPoint() + point_a1, A.pointAt((1.0 / 3.0) * 2) + point_a2 + point_a3,
512 A.finalPoint() + point_a3);
513 }
514 } else if (handles == HM_RETRACT) {
515 out.start(A.initialPoint());
516 out.appendNew<Geom::LineSegment>(A.finalPoint() + point_a3);
517 } else if (handles == HM_ALONG_NODES) {
518 if (cubic) {
519 out.start((*cubic)[0]);
520 out.appendNew<Geom::CubicBezier>((*cubic)[1] + last_move, (*cubic)[2] + point_a3, (*cubic)[3] + point_a3);
521 last_move = point_a3;
522 } else {
523 out.start(A.initialPoint());
524 out.appendNew<Geom::LineSegment>(A.finalPoint() + point_a3);
525 }
526 } else if (handles == HM_RAND) {
527 out.start(A.initialPoint());
528 out.appendNew<Geom::CubicBezier>(A.pointAt(0.3333) + point_a1, A.pointAt(0.6666) + point_a2 + point_a3,
529 A.finalPoint() + point_a3);
530 }
531 return out;
532}
533
535{
536 using Geom::X;
537 using Geom::Y;
538 return Geom::Point(A[X] + t * (B[X] - A[X]), A[Y] + t * (B[Y] - A[Y]));
539}
540
541}; // namespace LivePathEffect
542}; /* namespace Inkscape */
543
544/*
545 Local Variables:
546 mode:c++
547 c-file-style:"stroustrup"
548 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
549 indent-tabs-mode:nil
550 fill-column:99
551 End:
552*/
553// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Bezier curve with compile-time specified order.
std::pair< BezierCurveN, BezierCurveN > subdivide(Coord t) const
Divide a Bezier curve into two curves.
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 Point pointAt(Coord t) const
Evaluate the curve at a specified time value.
Definition curve.h:110
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Sequence of subpaths.
Definition pathvector.h:122
void push_back(Path const &path)
Append a path at the end.
Definition pathvector.h:172
Point finalPoint() const
Get the last point in the last path of the vector.
Definition pathvector.h:222
void reverse(bool reverse_paths=true)
Reverse the direction of paths in the vector.
size_type curveCount() const
Get the total number of curves in the vector.
Sequence of contiguous curves, aka spline.
Definition path.h:353
Point pointAt(Coord t) const
Get the point at the specified time value.
Definition path.cpp:449
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< Parameter * > param_vector
Definition effect.h:178
void registerParameter(Parameter *param)
Definition effect.cpp:1704
EffectType effectType() const
Definition effect.cpp:1182
void param_setValue(Glib::ustring newvalue, bool write=false)
Definition hidden.cpp:71
Glib::ustring param_getSVGValue() const override
Definition hidden.cpp:53
virtual Geom::Point tPoint(Geom::Point A, Geom::Point B, double t=0.5)
Gtk::Widget * newWidget() override
This creates a managed widget.
Geom::Path addNodesAndJitter(Geom::Curve const &A, Geom::Point &prev, Geom::Point &last_move, double t, bool last)
virtual double sign(double randNumber)
LPERoughen(LivePathEffectObject *lpeobject)
void doEffect(Geom::PathVector &curve) override
EnumParam< DivisionMethod > method
Definition lpe-roughen.h:61
Geom::Path jitter(Geom::Curve const &A, Geom::Point &prev, Geom::Point &last_move)
void doBeforeEffect(SPLPEItem const *lpeitem) override
Is performed each time before the effect is updated.
virtual Geom::Point randomize(double max_length, bool is_node=false)
EnumParam< HandlesMethod > handles
Definition lpe-roughen.h:67
void doOnApply(SPLPEItem const *lpeitem) override
Is performed a single time when the effect is freshly applied to a path.
Glib::ustring const * param_getTooltip() const
Definition parameter.h:81
virtual Gtk::Widget * param_newWidget()=0
void param_set_value(gdouble val, long newseed)
Definition random.cpp:105
void param_set_randomsign(bool randomsign)
Definition random.h:36
void param_set_range(gdouble min, gdouble max)
Definition random.cpp:129
void param_set_digits(unsigned digits)
void param_set_range(double min, double max)
void param_set_increments(double step, double page)
bool isSet() const
Check whether the received entry is set.
Preference storage class.
Definition preferences.h:61
static Preferences * get()
Access the singleton Preferences object.
Entry const getEntry(Glib::ustring const &pref_path)
Retrieve a preference entry without specifying its type.
Simplified management of enumerations of svg items with UI labels.
Definition enums.h:42
Geom::OptRect bounds(BBoxType type, Geom::Affine const &transform=Geom::identity()) const
Definition sp-item.cpp:1003
@ GEOMETRIC_BBOX
Definition sp-item.h:116
char const * getId() const
Returns the objects current ID string.
void backspace(Geom::PathVector &pathv)
Remove last segment of curve.
Definition curve.cpp:139
void move_endpoints(Geom::PathVector &pathv, Geom::Point const &new_p0, Geom::Point const &new_p1)
Sets start of first path to new_p0, and end of first path to new_p1.
Definition curve.cpp:188
void pathvector_append(Geom::PathVector &to, Geom::PathVector const &pathv, bool use_lineto)
Append pathv to to.
Definition curve.cpp:78
Geom::Curve const * get_last_segment(Geom::PathVector const &pathv)
Return last pathsegment (possibly the closing path segment) of the last path in PathVector or null.
Definition curve.cpp:62
Geom::Curve const * get_first_segment(Geom::PathVector const &pathv)
Return first pathsegment in PathVector or NULL.
Definition curve.cpp:70
void closepath_current(Geom::Path &path)
Close path by setting the end point to the start point instead of adding a new lineto.
Definition curve.cpp:37
bool pathvector_append_continuous(Geom::PathVector &to, Geom::PathVector const &pathv, double tolerance)
Append pathv to to with possible fusing of close endpoints.
Definition curve.cpp:104
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
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.
std::string original
Roughen LPE effect, see lpe-roughen.cpp.
Coord length(LineSegment const &seg)
Coord nearest_time(Point const &p, Curve const &c)
Definition curve.h:354
Angle distance(Angle const &a, Angle const &b)
Definition angle.h:163
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
static const Util::EnumDataConverter< HandlesMethod > HMConverter(HandlesMethodData, HM_END)
static const Util::EnumData< HandlesMethod > HandlesMethodData[]
const EnumEffectDataConverter< EffectType > LPETypeConverter
defined in effect.cpp
static const Util::EnumData< DivisionMethod > DivisionMethodData[]
static const Util::EnumDataConverter< DivisionMethod > DMConverter(DivisionMethodData, DM_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
Glib::ustring format_classic(T const &... args)
Helper class to stream background task notifications as a series of messages.
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Singleton class to access the preferences file in a convenient way.
Base class for live path effect items.
Simplified management of enumerations of svg items with UI labels.
Definition enums.h:27
Definition curve.h:24