Code

Krzysztof's patch for 388257
[inkscape.git] / src / live_effects / lpe-copy_rotate.cpp
index 40a4b1a54833f70b4b7ec1d03790f570edfbd138..dac34c5d485bad8057bae5966942e8e5f8b02463 100644 (file)
 #include <2geom/path.h>
 #include <2geom/transforms.h>
 #include <2geom/d2-sbasis.h>
+#include <2geom/angle.h>
 
 namespace Inkscape {
 namespace LivePathEffect {
 
 namespace CR {
 
-class KnotHolderEntityAngle : public KnotHolderEntity
+class KnotHolderEntityStartingAngle : public LPEKnotHolderEntity
 {
 public:
-    virtual bool isLPEParam() { return true; }
+    virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
+    virtual Geom::Point knot_get();
+};
 
-    virtual void knot_set(NR::Point const &p, NR::Point const &origin, guint state);
-    virtual NR::Point knot_get();
+class KnotHolderEntityRotationAngle : public LPEKnotHolderEntity
+{
+public:
+    virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
+    virtual Geom::Point knot_get();
 };
 
 } // namespace CR
 
 LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
     Effect(lpeobject),
-    include_original(_("Include original?"), _(""), "include_original", &wr, this, false),
-    angle(_("Angle"), _("Angle"), "angle", &wr, this, 30.0),
-    num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 1),
-    origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this),
+    starting_angle(_("Starting"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
+    rotation_angle(_("Rotation angle"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0),
+    num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 5),
+    origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"),
     dist_angle_handle(100)
 {
     show_orig_path = true;
 
     // register all your parameters here, so Inkscape knows which parameters this effect has:
-    registerParameter( dynamic_cast<Parameter *>(&include_original) );
-    registerParameter( dynamic_cast<Parameter *>(&angle) );
+    registerParameter( dynamic_cast<Parameter *>(&starting_angle) );
+    registerParameter( dynamic_cast<Parameter *>(&rotation_angle) );
     registerParameter( dynamic_cast<Parameter *>(&num_copies) );
     registerParameter( dynamic_cast<Parameter *>(&origin) );
 
-    registerKnotHolderHandle(new CR::KnotHolderEntityAngle(), _("Adjust the angle"));
+    registerKnotHolderHandle(new CR::KnotHolderEntityStartingAngle(), _("Adjust the starting angle"));
+    registerKnotHolderHandle(new CR::KnotHolderEntityRotationAngle(), _("Adjust the rotation angle"));
 
     num_copies.param_make_integer(true);
     num_copies.param_set_range(0, 1000);
@@ -69,8 +76,8 @@ LPECopyRotate::doOnApply(SPLPEItem *lpeitem)
 {
     SPCurve *curve = SP_SHAPE(lpeitem)->curve;
 
-    A = curve->first_point().to_2geom();
-    B = curve->last_point().to_2geom();
+    A = *(curve->first_point());
+    B = *(curve->last_point());
 
     origin.param_setValue(A);
 
@@ -83,25 +90,43 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
 {
     using namespace Geom;
 
+    // I first suspected the minus sign to be a bug in 2geom but it is
+    // likely due to SVG's choice of coordinate system orientation (max)
+    start_pos = origin + dir * Rotate(-deg_to_rad(starting_angle)) * dist_angle_handle;
+    rot_pos = origin + dir * Rotate(-deg_to_rad(starting_angle + rotation_angle)) * dist_angle_handle;
+
     A = pwd2_in.firstValue();
     B = pwd2_in.lastValue();
     dir = unit_vector(B - A);
 
     Piecewise<D2<SBasis> > output;
 
-    if (include_original) {
-        output = pwd2_in;
-    }
-
-    for (int i = 1; i <= num_copies; ++i) {
-        Rotate rot(deg_to_rad(angle * i));
-        Matrix t = Translate(-origin) * rot * Translate(origin);
+    Matrix pre = Translate(-origin) * Rotate(-deg_to_rad(starting_angle));
+    for (int i = 0; i < num_copies; ++i) {
+        // I first suspected the minus sign to be a bug in 2geom but it is
+        // likely due to SVG's choice of coordinate system orientation (max)
+        Rotate rot(-deg_to_rad(rotation_angle * i));
+        Matrix t = pre * rot * Translate(origin);
         output.concat(pwd2_in * t);
     }
 
     return output;
 }
 
+void
+LPECopyRotate::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+    using namespace Geom;
+
+    Path path(start_pos);
+    path.appendNew<LineSegment>((Geom::Point) origin);
+    path.appendNew<LineSegment>(rot_pos);
+
+    PathVector pathv;
+    pathv.push_back(path);
+    hp_vec.push_back(pathv);
+}
+
 namespace CR {
 
 using namespace Geom;
@@ -119,12 +144,15 @@ get_effect(SPItem *item)
 }
 
 void
-KnotHolderEntityAngle::knot_set(NR::Point const &p, NR::Point const &/*origin*/, guint state)
+KnotHolderEntityStartingAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
 {
     LPECopyRotate* lpe = get_effect(item);
 
-    // FIXME: is the minus sign due to a bug in 2geom?
-    lpe->angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, p.to_2geom() - lpe->origin)));
+    Geom::Point const s = snap_knot_position(p);
+
+    // I first suspected the minus sign to be a bug in 2geom but it is
+    // likely due to SVG's choice of coordinate system orientation (max)
+    lpe->starting_angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, s - lpe->origin)));
     if (state & GDK_SHIFT_MASK) {
         lpe->dist_angle_handle = L2(lpe->B - lpe->A);
     } else {
@@ -135,15 +163,38 @@ KnotHolderEntityAngle::knot_set(NR::Point const &p, NR::Point const &/*origin*/,
     sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
 }
 
-NR::Point
-KnotHolderEntityAngle::knot_get()
+void
+KnotHolderEntityRotationAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
 {
     LPECopyRotate* lpe = get_effect(item);
 
-    // FIXME: is the minus sign due to a bug in 2geom?
-    Point d = lpe->dir * Rotate(-deg_to_rad(lpe->angle)) * lpe->dist_angle_handle;
+    Geom::Point const s = snap_knot_position(p);
 
-    return lpe->origin + d;
+    // I first suspected the minus sign to be a bug in 2geom but it is
+    // likely due to SVG's choice of coordinate system orientation (max)
+    lpe->rotation_angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle);
+    if (state & GDK_SHIFT_MASK) {
+        lpe->dist_angle_handle = L2(lpe->B - lpe->A);
+    } else {
+        lpe->dist_angle_handle = L2(p - lpe->origin);
+    }
+
+    // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
+    sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
+}
+
+Geom::Point
+KnotHolderEntityStartingAngle::knot_get()
+{
+    LPECopyRotate* lpe = get_effect(item);
+    return snap_knot_position(lpe->start_pos);
+}
+
+Geom::Point
+KnotHolderEntityRotationAngle::knot_get()
+{
+    LPECopyRotate* lpe = get_effect(item);
+    return snap_knot_position(lpe->rot_pos);
 }
 
 } // namespace CR