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