Code

Make PointParam handles snap, too
[inkscape.git] / src / live_effects / lpe-copy_rotate.cpp
1 #define INKSCAPE_LPE_COPY_ROTATE_CPP
2 /** \file
3  * LPE <copy_rotate> implementation
4  */
5 /*
6  * Authors:
7  *   Maximilian Albert
8  *
9  * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
10  * Copyright (C) Maximilian Albert 2008 <maximilian.albert@gmail.com>
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #include "live_effects/lpe-copy_rotate.h"
16 #include "sp-shape.h"
17 #include "display/curve.h"
19 #include <2geom/path.h>
20 #include <2geom/transforms.h>
21 #include <2geom/d2-sbasis.h>
22 #include <2geom/angle.h>
24 namespace Inkscape {
25 namespace LivePathEffect {
27 namespace CR {
29 class KnotHolderEntityAngle : public LPEKnotHolderEntity
30 {
31 public:
32     virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state);
33     virtual NR::Point knot_get();
34 };
36 } // namespace CR
38 LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
39     Effect(lpeobject),
40     angle(_("Angle"), _("Angle"), "angle", &wr, this, 30.0),
41     num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 1),
42     origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"),
43     include_original(_("Include original?"), _(""), "include_original", &wr, this, true),
44     dist_angle_handle(100)
45 {
46     show_orig_path = true;
48     // register all your parameters here, so Inkscape knows which parameters this effect has:
49     registerParameter( dynamic_cast<Parameter *>(&include_original) );
50     registerParameter( dynamic_cast<Parameter *>(&angle) );
51     registerParameter( dynamic_cast<Parameter *>(&num_copies) );
52     registerParameter( dynamic_cast<Parameter *>(&origin) );
54     registerKnotHolderHandle(new CR::KnotHolderEntityAngle(), _("Adjust the angle"));
56     num_copies.param_make_integer(true);
57     num_copies.param_set_range(0, 1000);
59 }
61 LPECopyRotate::~LPECopyRotate()
62 {
64 }
66 void
67 LPECopyRotate::doOnApply(SPLPEItem *lpeitem)
68 {
69     SPCurve *curve = SP_SHAPE(lpeitem)->curve;
71     A = curve->first_point();
72     B = curve->last_point();
74     origin.param_setValue(A);
76     dir = unit_vector(B - A);
77     dist_angle_handle = L2(B - A);
78 }
80 Geom::Piecewise<Geom::D2<Geom::SBasis> >
81 LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
82 {
83     using namespace Geom;
85     A = pwd2_in.firstValue();
86     B = pwd2_in.lastValue();
87     dir = unit_vector(B - A);
89     Piecewise<D2<SBasis> > output;
91     if (include_original) {
92         output = pwd2_in;
93     }
95     for (int i = 1; i <= num_copies; ++i) {
96         // I first suspected the minus sign to be a bug in 2geom but it is
97         // likely due to SVG's choice of coordinate system orientation (max)
98         Rotate rot(-deg_to_rad(angle * i));
99         Matrix t = Translate(-origin) * rot * Translate(origin);
100         output.concat(pwd2_in * t);
101     }
103     return output;
106 namespace CR {
108 using namespace Geom;
110 // TODO: make this more generic
111 static LPECopyRotate *
112 get_effect(SPItem *item)
114     Effect *effect = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(item));
115     if (effect->effectType() != COPY_ROTATE) {
116         g_print ("Warning: Effect is not of type LPECopyRotate!\n");
117         return NULL;
118     }
119     return static_cast<LPECopyRotate *>(effect);
122 void
123 KnotHolderEntityAngle::knot_set(NR::Point const &p, NR::Point const &/*origin*/, guint state)
125     LPECopyRotate* lpe = get_effect(item);
127     NR::Point const s = snap_knot_position(p);
129     // I first suspected the minus sign to be a bug in 2geom but it is
130     // likely due to SVG's choice of coordinate system orientation (max)
131     lpe->angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, s.to_2geom() - lpe->origin)));
132     if (state & GDK_SHIFT_MASK) {
133         lpe->dist_angle_handle = L2(lpe->B - lpe->A);
134     } else {
135         lpe->dist_angle_handle = L2(p - lpe->origin);
136     }
138     // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
139     sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
142 NR::Point
143 KnotHolderEntityAngle::knot_get()
145     LPECopyRotate* lpe = get_effect(item);
146     // I first suspected the minus sign to be a bug in 2geom but it is
147     // likely due to SVG's choice of coordinate system orientation (max)
148     Point d = lpe->dir * Rotate(-deg_to_rad(lpe->angle)) * lpe->dist_angle_handle;
150     return snap_knot_position(lpe->origin + d);
153 } // namespace CR
155 /* ######################## */
157 } //namespace LivePathEffect
158 } /* namespace Inkscape */
160 /*
161   Local Variables:
162   mode:c++
163   c-file-style:"stroustrup"
164   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
165   indent-tabs-mode:nil
166   fill-column:99
167   End:
168 */
169 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :