summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-roughen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects/lpe-roughen.cpp')
-rw-r--r--src/live_effects/lpe-roughen.cpp392
1 files changed, 294 insertions, 98 deletions
diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp
index 33ffd96d6..105fe2fc4 100644
--- a/src/live_effects/lpe-roughen.cpp
+++ b/src/live_effects/lpe-roughen.cpp
@@ -18,7 +18,9 @@
#include "live_effects/lpe-roughen.h"
#include "display/curve.h"
#include "live_effects/parameter/parameter.h"
+#include <boost/functional/hash.hpp>
#include "helper/geom.h"
+#include "sp-item-group.h"
#include <glibmm/i18n.h>
#include <cmath>
@@ -32,13 +34,22 @@ static const Util::EnumData<DivisionMethod> DivisionMethodData[DM_END] = {
static const Util::EnumDataConverter<DivisionMethod>
DMConverter(DivisionMethodData, DM_END);
+static const Util::EnumData<HandlesMethod> HandlesMethodData[HM_END] = {
+ { HM_ALONG_NODES, N_("Along nodes"), "along" },
+ { HM_RAND, N_("Rand"), "rand" },
+ { HM_RETRACT, N_("Retract"), "retract" },
+ { HM_SMOOTH, N_("Smooth"), "smooth" }
+};
+static const Util::EnumDataConverter<HandlesMethod>
+HMConverter(HandlesMethodData, HM_END);
+
LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
: Effect(lpeobject),
// initialise your parameters here:
method(_("Method"), _("Division method"), "method", DMConverter, &wr,
this, DM_SEGMENTS),
max_segment_size(_("Max. segment size"), _("Max. segment size"),
- "max_segment_size", &wr, this, 10.),
+ "max_segment_size", &wr, this, 10),
segments(_("Number of segments"), _("Number of segments"), "segments",
&wr, this, 2),
displace_x(_("Max. displacement in X"), _("Max. displacement in X"),
@@ -47,10 +58,14 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
"displace_y", &wr, this, 10.),
global_randomize(_("Global randomize"), _("Global randomize"),
"global_randomize", &wr, this, 1.),
+ handles(_("Handles"), _("Handles options"), "handles", HMConverter, &wr,
+ this, HM_ALONG_NODES),
shift_nodes(_("Shift nodes"), _("Shift nodes"), "shift_nodes", &wr, this,
true),
- shift_node_handles(_("Shift node handles"), _("Shift node handles"),
- "shift_node_handles", &wr, this, true)
+ fixed_displacement(_("Fixed displacement"), _("Fixed displacement, 1/3 of segment length"),
+ "fixed_displacement", &wr, this, false),
+ spray_tool_friendly(_("Spray Tool friendly"), _("For use with spray tool in copy mode"),
+ "spray_tool_friendly", &wr, this, false)
{
registerParameter(&method);
registerParameter(&max_segment_size);
@@ -58,8 +73,10 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
registerParameter(&displace_x);
registerParameter(&displace_y);
registerParameter(&global_randomize);
+ registerParameter(&handles);
registerParameter(&shift_nodes);
- registerParameter(&shift_node_handles);
+ registerParameter(&fixed_displacement);
+ registerParameter(&spray_tool_friendly);
displace_x.param_set_range(0., Geom::infinity());
displace_y.param_set_range(0., Geom::infinity());
global_randomize.param_set_range(0., Geom::infinity());
@@ -69,19 +86,23 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
segments.param_set_range(1, Geom::infinity());
segments.param_set_increments(1, 1);
segments.param_set_digits(0);
+ seed = 0;
+ apply_to_clippath_and_mask = true;
}
LPERoughen::~LPERoughen() {}
void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem)
{
+ if(spray_tool_friendly && seed == 0 && SP_OBJECT(lpeitem)->getId()){
+ std::string id_item(SP_OBJECT(lpeitem)->getId());
+ long seed = static_cast<long>(boost::hash_value(id_item));
+ global_randomize.param_set_value(global_randomize.get_value(), seed);
+ }
displace_x.resetRandomizer();
displace_y.resetRandomizer();
global_randomize.resetRandomizer();
srand(1);
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
Gtk::Widget *LPERoughen::newWidget()
@@ -122,6 +143,15 @@ Gtk::Widget *LPERoughen::newWidget()
vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
Gtk::PACK_EXPAND_WIDGET);
}
+ if (param->param_key == "handles") {
+ Gtk::Label *options = Gtk::manage(new Gtk::Label(
+ Glib::ustring(_("<b>Options</b> Modify options to rough")),
+ Gtk::ALIGN_START));
+ options->set_use_markup(true);
+ vbox->pack_start(*options, false, false, 2);
+ vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
+ Gtk::PACK_EXPAND_WIDGET);
+ }
Glib::ustring *tip = param->param_getTooltip();
if (widg) {
vbox->pack_start(*widg, true, true, 2);
@@ -133,7 +163,6 @@ Gtk::Widget *LPERoughen::newWidget()
}
}
}
-
++it;
}
return dynamic_cast<Gtk::Widget *>(vbox);
@@ -147,19 +176,25 @@ double LPERoughen::sign(double random_number)
return random_number;
}
-Geom::Point LPERoughen::randomize()
+Geom::Point LPERoughen::randomize(double max_lenght, bool is_node)
{
- double displace_x_parsed = displace_x * global_randomize;
- double displace_y_parsed = displace_y * global_randomize;
-
+ double factor = 1.0/3.0;
+ if(is_node){
+ factor = 1.0;
+ }
+ double displace_x_parsed = displace_x * global_randomize * factor;
+ double displace_y_parsed = displace_y * global_randomize * factor;
Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed));
+ if( fixed_displacement ){
+ Geom::Ray ray(Geom::Point(0,0),output);
+ output = Geom::Point::polar(ray.angle(), max_lenght);
+ }
return output;
}
void LPERoughen::doEffect(SPCurve *curve)
{
- Geom::PathVector const original_pathv =
- pathv_to_linear_and_cubic_beziers(curve->get_pathvector());
+ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector());
curve->reset();
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
path_it != original_pathv.end(); ++path_it) {
@@ -170,41 +205,30 @@ void LPERoughen::doEffect(SPCurve *curve)
Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
Geom::Path::const_iterator curve_endit = path_it->end_default();
SPCurve *nCurve = new SPCurve();
+ Geom::Point prev(0, 0);
+ Geom::Point last_move(0, 0);
+ nCurve->moveto(curve_it1->initialPoint());
if (path_it->closed()) {
- const Geom::Curve &closingline =
- path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
- Geom::Point initialMove(0, 0);
- if (shift_nodes) {
- initialMove = randomize();
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
}
- Geom::Point initialPoint = curve_it1->initialPoint() + initialMove;
- nCurve->moveto(initialPoint);
- Geom::Point point0(0, 0);
- Geom::Point point1(0, 0);
- Geom::Point point2(0, 0);
- Geom::Point point3(0, 0);
- bool first = true;
while (curve_it1 != curve_endit) {
Geom::CubicBezier const *cubic = NULL;
- point0 = curve_it1->initialPoint();
- point1 = curve_it1->initialPoint();
- point2 = curve_it1->finalPoint();
- point3 = curve_it1->finalPoint();
cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
if (cubic) {
- point1 = (*cubic)[1];
- if (shift_nodes && first) {
- point1 = (*cubic)[1] + initialMove;
- }
- point2 = (*cubic)[2];
- nCurve->curveto(point1, point2, point3);
+ nCurve->curveto((*cubic)[1] + last_move, (*cubic)[2], curve_it1->finalPoint());
} else {
- nCurve->lineto(point3);
+ nCurve->lineto(curve_it1->finalPoint());
}
+ last_move = Geom::Point(0, 0);
double length = curve_it1->length(0.001);
std::size_t splits = 0;
if (method == DM_SEGMENTS) {
@@ -212,15 +236,21 @@ void LPERoughen::doEffect(SPCurve *curve)
} else {
splits = ceil(length / max_segment_size);
}
- for (unsigned int t = splits; t >= 1; t--) {
- if (t == 1 && splits != 1) {
+ Geom::Curve const * original = nCurve->last_segment()->duplicate() ;
+ for (unsigned int t = 1; t <= splits; t++) {
+ if(t == splits && splits != 1){
continue;
}
- const SPCurve *tmp;
+ SPCurve const * tmp;
if (splits == 1) {
- tmp = jitter(nCurve->last_segment());
+ tmp = jitter(nCurve->last_segment(), prev, last_move);
} else {
- tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t);
+ bool last = false;
+ if(t == splits-1){
+ last = true;
+ }
+ double time = Geom::nearest_time(original->pointAt((1. / (double)splits) * t), *nCurve->last_segment());
+ tmp = addNodesAndJitter(nCurve->last_segment(), prev, last_move, time, last);
}
if (nCurve->get_segment_count() > 1) {
nCurve->backspace();
@@ -231,12 +261,44 @@ void LPERoughen::doEffect(SPCurve *curve)
delete tmp;
}
++curve_it1;
- if(curve_it2 != curve_endit) {
- ++curve_it2;
- }
- first = false;
+ ++curve_it2;
}
if (path_it->closed()) {
+ if(handles == HM_SMOOTH && curve_it1 == curve_endit){
+ SPCurve *out = new SPCurve();
+ nCurve = nCurve->create_reverse();
+ Geom::CubicBezier const *cubic_start = dynamic_cast<Geom::CubicBezier const *>(nCurve->first_segment());
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
+ Geom::Point oposite = nCurve->first_segment()->pointAt(1.0/3.0);
+ if(cubic_start){
+ Geom::Ray ray((*cubic_start)[1], (*cubic_start)[0]);
+ double dist = Geom::distance((*cubic_start)[1], (*cubic_start)[0]);
+ oposite = Geom::Point::polar(ray.angle(),dist) + (*cubic_start)[0];
+ }
+ if(cubic){
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[1], oposite, (*cubic)[3]);
+ } else {
+ out->moveto(nCurve->last_segment()->initialPoint());
+ out->curveto(nCurve->last_segment()->initialPoint(), oposite, nCurve->last_segment()->finalPoint());
+ }
+ nCurve->backspace();
+ nCurve->append_continuous(out, 0.001);
+ nCurve = nCurve->create_reverse();
+ }
+ if(handles == HM_ALONG_NODES && curve_it1 == curve_endit){
+ SPCurve *out = new SPCurve();
+ nCurve = nCurve->create_reverse();
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
+ if(cubic){
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[1], (*cubic)[2] - ((*cubic)[3] - nCurve->first_segment()->initialPoint()) , (*cubic)[3]);
+ nCurve->backspace();
+ nCurve->append_continuous(out, 0.001);
+ }
+ nCurve = nCurve->create_reverse();
+ }
+ nCurve->move_endpoints(nCurve->last_segment()->finalPoint(), nCurve->last_segment()->finalPoint());
nCurve->closepath_current();
}
curve->append(nCurve, false);
@@ -245,77 +307,211 @@ void LPERoughen::doEffect(SPCurve *curve)
}
}
-SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t)
+SPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last)
{
SPCurve *out = new SPCurve();
Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A);
- Geom::Point point1(0, 0);
- Geom::Point point2(0, 0);
- Geom::Point point3(0, 0);
+ double max_lenght = Geom::distance(A->initialPoint(),A->pointAt(t)) / 3.0;
+ Geom::Point point_a1(0, 0);
+ Geom::Point point_a2(0, 0);
+ Geom::Point point_a3(0, 0);
Geom::Point point_b1(0, 0);
Geom::Point point_b2(0, 0);
Geom::Point point_b3(0, 0);
if (shift_nodes) {
- point3 = randomize();
- point_b3 = randomize();
+ point_a3 = randomize(max_lenght, true);
+ if(last){
+ point_b3 = randomize(max_lenght, true);
+ }
}
- if (shift_node_handles) {
- point1 = randomize();
- point2 = randomize();
- point_b1 = randomize();
- point_b2 = randomize();
+ if (handles == HM_RAND || handles == HM_SMOOTH) {
+ point_a1 = randomize(max_lenght);
+ point_a2 = randomize(max_lenght);
+ point_b1 = randomize(max_lenght);
+ if(last){
+ point_b2 = randomize(max_lenght);
+ }
} else {
- point2 = point3;
- point_b1 = point3;
- point_b2 = point_b3;
+ point_a2 = point_a3;
+ point_b1 = point_a3;
+ if(last){
+ point_b2 = point_b3;
+ }
}
- if (cubic) {
- std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
- std::vector<Geom::Point> seg1 = div.first.controlPoints(),
- seg2 = div.second.controlPoints();
- out->moveto(seg1[0]);
- out->curveto(seg1[1] + point1, seg1[2] + point2, seg1[3] + point3);
- out->curveto(seg2[1] + point_b1, seg2[2], seg2[3]);
- } else if (shift_node_handles) {
- out->moveto(A->initialPoint());
- out->curveto(A->pointAt(t / 3) + point1, A->pointAt((t / 3) * 2) + point2,
- A->pointAt(t) + point3);
- out->curveto(A->pointAt(t + (t / 3)) + point_b1, A->pointAt(t + ((t / 3) * 2)),
- A->finalPoint());
- } else {
+ if(handles == HM_SMOOTH){
+ if(cubic) {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg1 = div.first.controlPoints(),
+ seg2 = div.second.controlPoints();
+ Geom::Ray ray(seg1[3] + point_a3, seg2[1] + point_a3);
+ double lenght = max_lenght;
+ if(!fixed_displacement ){
+ lenght = Geom::distance(seg1[3] + point_a3, seg2[1] + point_a3);
+ }
+ point_b1 = seg1[3] + point_a3 + Geom::Point::polar(ray.angle() , lenght);
+ point_b2 = seg2[2];
+ point_b3 = seg2[3] + point_b3;
+ point_a3 = seg1[3] + point_a3;
+ ray.setPoints(prev,A->initialPoint());
+ point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev == Geom::Point(0,0)){
+ point_a1 = randomize(max_lenght);
+ }
+ if(last){
+ Geom::Path b2(point_b3);
+ b2.appendNew<Geom::LineSegment>(point_a3);
+ lenght = max_lenght;
+ ray.setPoints(point_b3, point_b2);
+ if(!fixed_displacement ){
+ lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3);
+ }
+ point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght);
+ }
+ ray.setPoints(point_b1, point_a3);
+ point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght);
+ if(last){
+ prev = point_b2;
+ } else {
+ prev = point_a2;
+ }
+ out->moveto(seg1[0]);
+ out->curveto(point_a1,point_a2,point_a3);
+ out->curveto(point_b1, point_b2, point_b3);
+ } else {
+ Geom::Ray ray(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3)));
+ double lenght = max_lenght;
+ if(!fixed_displacement ){
+ lenght = Geom::distance(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3)));
+ }
+ point_b1 = A->pointAt(t) + point_a3 + Geom::Point::polar(ray.angle() , lenght);
+ point_b2 = A->pointAt(t +((t / 3) * 2));
+ point_b3 = A->finalPoint() + point_b3;
+ point_a3 = A->pointAt(t) + point_a3;
+ ray.setPoints(prev,A->initialPoint());
+ point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev == Geom::Point(0,0)){
+ point_a1 = randomize(max_lenght);
+ }
+ if(last){
+ Geom::Path b2(point_b3);
+ b2.appendNew<Geom::LineSegment>(point_a3);
+ lenght = max_lenght;
+ ray.setPoints(point_b3, point_b2);
+ if(!fixed_displacement ){
+ lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3);
+ }
+ point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght);
+ }
+ ray.setPoints(point_b1, point_a3);
+ point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght);
+ if(last){
+ prev = point_b2;
+ } else {
+ prev = point_a2;
+ }
+ out->moveto(A->initialPoint());
+ out->curveto(point_a1,point_a2,point_a3);
+ out->curveto(point_b1, point_b2, point_b3);
+ }
+ } else if(handles == HM_RETRACT){
out->moveto(A->initialPoint());
- out->lineto(A->pointAt(t) + point3);
- out->lineto(A->finalPoint());
+ out->lineto(A->pointAt(t) + point_a3);
+ if(cubic && !last){
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg2 = div.second.controlPoints();
+ out->curveto(seg2[1], seg2[2], seg2[3]);
+ } else {
+ out->lineto(A->finalPoint() + point_b3);
+ }
+ } else if(handles == HM_ALONG_NODES){
+ if (cubic) {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg1 = div.first.controlPoints(),
+ seg2 = div.second.controlPoints();
+ out->moveto(seg1[0]);
+ out->curveto(seg1[1] + last_move, seg1[2] + point_a3, seg1[3] + point_a3);
+ last_move = point_a3;
+ if(last){
+ last_move = point_b3;
+ }
+ out->curveto(seg2[1] + point_a3, seg2[2] + point_b3, seg2[3] + point_b3);
+ } else {
+ out->moveto(A->initialPoint());
+ out->lineto(A->pointAt(t) + point_a3);
+ out->lineto(A->finalPoint() + point_b3);
+ }
+ } else if(handles == HM_RAND) {
+ if (cubic) {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg1 = div.first.controlPoints(),
+ seg2 = div.second.controlPoints();
+ out->moveto(seg1[0]);
+ out->curveto(seg1[1] + point_a1, seg1[2] + point_a2 + point_a3, seg1[3] + point_a3);
+ out->curveto(seg2[1] + point_a3 + point_b1, seg2[2] + point_b2 + point_b3, seg2[3] + point_b3);
+ } else {
+ out->moveto(A->initialPoint());
+ out->lineto(A->pointAt(t) + point_a3);
+ out->lineto(A->finalPoint() + point_b3);
+ }
}
return out;
}
-SPCurve *LPERoughen::jitter(const Geom::Curve *A)
+SPCurve *LPERoughen::jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move)
{
SPCurve *out = new SPCurve();
Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A);
- Geom::Point point1(0, 0);
- Geom::Point point2(0, 0);
- Geom::Point point3(0, 0);
+ double max_lenght = Geom::distance(A->initialPoint(),A->finalPoint()) / 3.0;
+ Geom::Point point_a1(0, 0);
+ Geom::Point point_a2(0, 0);
+ Geom::Point point_a3(0, 0);
if (shift_nodes) {
- point3 = randomize();
+ point_a3 = randomize(max_lenght, true);
}
- if (shift_node_handles) {
- point1 = randomize();
- point2 = randomize();
- } else {
- point2 = point3;
+ if (handles == HM_RAND || handles == HM_SMOOTH) {
+ point_a1 = randomize(max_lenght);
+ point_a2 = randomize(max_lenght);
}
- if (cubic) {
- out->moveto((*cubic)[0]);
- out->curveto((*cubic)[1] + point1, (*cubic)[2] + point2, (*cubic)[3] + point3);
- } else if (shift_node_handles) {
+ if(handles == HM_SMOOTH) {
+ if (cubic) {
+ Geom::Ray ray(prev,A->initialPoint());
+ point_a1 = Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev == Geom::Point(0,0)){
+ point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght);
+ }
+ ray.setPoints((*cubic)[3] + point_a3, (*cubic)[2] + point_a3);
+ point_a2 = randomize(max_lenght, ray.angle());
+ prev = (*cubic)[2] + point_a2;
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[0] + point_a1, (*cubic)[2] + point_a2 + point_a3, (*cubic)[3] + point_a3);
+ } else {
+ Geom::Ray ray(prev,A->initialPoint());
+ point_a1 = Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev==Geom::Point(0,0)){
+ point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght);
+ }
+ ray.setPoints(A->finalPoint() + point_a3, A->pointAt((1.0/3.0) * 2) + point_a3);
+ point_a2 = randomize(max_lenght, ray.angle());
+ prev = A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3;
+ out->moveto(A->initialPoint());
+ out->curveto(A->initialPoint() + point_a1, A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3, A->finalPoint() + point_a3);
+ }
+ } else if(handles == HM_RETRACT){
out->moveto(A->initialPoint());
- out->curveto(A->pointAt(0.3333) + point1, A->pointAt(0.6666) + point2,
- A->finalPoint() + point3);
- } else {
+ out->lineto(A->finalPoint() + point_a3);
+ } else if (handles == HM_ALONG_NODES) {
+ if(cubic){
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[1] + last_move, (*cubic)[2] + point_a3, (*cubic)[3] + point_a3);
+ last_move = point_a3;
+ } else {
+ out->moveto(A->initialPoint());
+ out->lineto(A->finalPoint() + point_a3);
+ }
+ } else if (handles == HM_RAND) {
out->moveto(A->initialPoint());
- out->lineto(A->finalPoint() + point3);
+ out->curveto(A->pointAt(0.3333) + point_a1, A->pointAt(0.6666) + point_a2 + point_a3,
+ A->finalPoint() + point_a3);
}
return out;
}