1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** \file
3 * LPE <parallel> implementation
4 */
5 /*
6 * Authors:
7 * Maximilian Albert
8 *
9 * Copyright (C) Johan Engelen 2007-2012 <j.b.c.engelen@alumnus.utwente.nl>
10 * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15 #include "lpe-parallel.h"
16
17 #include "display/curve.h"
18
19 #include "object/sp-shape.h"
20
21 #include "ui/knot/knot-holder.h"
22 #include "ui/knot/knot-holder-entity.h"
23
24 // TODO due to internal breakage in glibmm headers, this must be last:
25 #include <glibmm/i18n.h>
26
27 namespace Inkscape {
28 namespace LivePathEffect {
29
30 namespace Pl {
31
32 class KnotHolderEntityLeftEnd : public LPEKnotHolderEntity {
33 public:
KnotHolderEntityLeftEnd(LPEParallel * effect)34 KnotHolderEntityLeftEnd(LPEParallel *effect) : LPEKnotHolderEntity(effect) {};
35 void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) override;
36 Geom::Point knot_get() const override;
37 };
38
39 class KnotHolderEntityRightEnd : public LPEKnotHolderEntity {
40 public:
KnotHolderEntityRightEnd(LPEParallel * effect)41 KnotHolderEntityRightEnd(LPEParallel *effect) : LPEKnotHolderEntity(effect) {};
42 void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) override;
43 Geom::Point knot_get() const override;
44 };
45
46 } // namespace Pl
47
LPEParallel(LivePathEffectObject * lpeobject)48 LPEParallel::LPEParallel(LivePathEffectObject *lpeobject) :
49 Effect(lpeobject),
50 // initialise your parameters here:
51 offset_pt(_("Offset"), _("Adjust the offset"), "offset_pt", &wr, this),
52 length_left(_("Length left:"), _("Specifies the left end of the parallel"), "length-left", &wr, this, 150),
53 length_right(_("Length right:"), _("Specifies the right end of the parallel"), "length-right", &wr, this, 150)
54 {
55 show_orig_path = true;
56 _provides_knotholder_entities = true;
57
58 registerParameter(&offset_pt);
59 registerParameter(&length_left);
60 registerParameter(&length_right);
61 }
62
63 LPEParallel::~LPEParallel()
64 = default;
65
66 void
doOnApply(SPLPEItem const * lpeitem)67 LPEParallel::doOnApply (SPLPEItem const* lpeitem)
68 {
69 auto shape = dynamic_cast<SPShape const *>(lpeitem);
70 if (!shape) {
71 g_warning("LPE parallel can only be applied to shapes (not groups).");
72 SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
73 item->removeCurrentPathEffect(false);
74 return;
75 }
76 SPCurve const *curve = shape->curve();
77
78 A = *(curve->first_point());
79 B = *(curve->last_point());
80 dir = unit_vector(B - A);
81 Geom::Point offset = (A + B)/2 + dir.ccw() * 100;
82 offset_pt.param_update_default(offset);
83 offset_pt.param_setValue(offset, true);
84 }
85
86 Geom::Piecewise<Geom::D2<Geom::SBasis> >
doEffect_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis>> const & pwd2_in)87 LPEParallel::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
88 {
89 using namespace Geom;
90
91 Piecewise<D2<SBasis> > output;
92
93 A = pwd2_in.firstValue();
94 B = pwd2_in.lastValue();
95 dir = unit_vector(B - A);
96
97 C = offset_pt - dir * length_left;
98 D = offset_pt + dir * length_right;
99
100 output = Piecewise<D2<SBasis> >(D2<SBasis>(SBasis(C[X], D[X]), SBasis(C[Y], D[Y])));
101
102 return output + dir;
103 }
104
addKnotHolderEntities(KnotHolder * knotholder,SPDesktop * desktop,SPItem * item)105 void LPEParallel::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
106 {
107 KnotHolderEntity *e = new Pl::KnotHolderEntityLeftEnd(this);
108 e->create(desktop, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:ParallelLeftEnd",
109 _("Adjust the \"left\" end of the parallel"));
110 knotholder->add(e);
111 }
112 {
113 KnotHolderEntity *e = new Pl::KnotHolderEntityRightEnd(this);
114 e->create(desktop, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:ParallelRightEnd",
115 _("Adjust the \"right\" end of the parallel"));
116 knotholder->add(e);
117 }
118 };
119
120 namespace Pl {
121
122 void
knot_set(Geom::Point const & p,Geom::Point const &,guint state)123 KnotHolderEntityLeftEnd::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
124 {
125 using namespace Geom;
126
127 LPEParallel *lpe = dynamic_cast<LPEParallel *>(_effect);
128
129 Geom::Point const s = snap_knot_position(p, state);
130
131 double lambda = L2(s - lpe->offset_pt) * sgn(dot(s - lpe->offset_pt, lpe->dir));
132 lpe->length_left.param_set_value(-lambda);
133
134 sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
135 }
136
137 void
knot_set(Geom::Point const & p,Geom::Point const &,guint state)138 KnotHolderEntityRightEnd::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
139 {
140 using namespace Geom;
141
142 LPEParallel *lpe = dynamic_cast<LPEParallel *>(_effect);
143
144 Geom::Point const s = snap_knot_position(p, state);
145
146 double lambda = L2(s - lpe->offset_pt) * sgn(dot(s - lpe->offset_pt, lpe->dir));
147 lpe->length_right.param_set_value(lambda);
148
149 sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
150 }
151
152 Geom::Point
knot_get() const153 KnotHolderEntityLeftEnd::knot_get() const
154 {
155 LPEParallel const *lpe = dynamic_cast<LPEParallel const*>(_effect);
156 return lpe->C;
157 }
158
159 Geom::Point
knot_get() const160 KnotHolderEntityRightEnd::knot_get() const
161 {
162 LPEParallel const *lpe = dynamic_cast<LPEParallel const*>(_effect);
163 return lpe->D;
164 }
165
166 } // namespace Pl
167
168 /* ######################## */
169
170 } //namespace LivePathEffect
171 } /* namespace Inkscape */
172
173 /*
174 Local Variables:
175 mode:c++
176 c-file-style:"stroustrup"
177 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
178 indent-tabs-mode:nil
179 fill-column:99
180 End:
181 */
182 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
183