Code

Fix change in revision 9947 to be consistent with rest of the codebase.
[inkscape.git] / src / sp-spiral.cpp
index 9a3708d4b3a55e888fab51479636075ad19b40aa..cfe02947a26af5276f16532be2bea8f2aafb06df 100644 (file)
@@ -1,5 +1,3 @@
-#define __SP_SPIRAL_C__
-
 /** \file
  * <sodipodi:spiral> implementation
  */
@@ -7,6 +5,7 @@
  * Authors:
  *   Mitsuru Oka <oka326@parkcity.ne.jp>
  *   Lauris Kaplinski <lauris@kaplinski.com>
+ *   Abhishek Sharma
  *
  * Copyright (C) 1999-2002 Lauris Kaplinski
  * Copyright (C) 2000-2001 Ximian, Inc.
@@ -19,7 +18,8 @@
 
 #include "svg/svg.h"
 #include "attributes.h"
-#include "display/bezier-utils.h"
+#include <2geom/bezier-utils.h>
+#include <2geom/pathvector.h>
 #include "display/curve.h"
 #include <glibmm/i18n.h>
 #include "xml/repr.h"
@@ -36,7 +36,7 @@ static void sp_spiral_set (SPObject *object, unsigned int key, const gchar *valu
 static void sp_spiral_update (SPObject *object, SPCtx *ctx, guint flags);
 
 static gchar * sp_spiral_description (SPItem * item);
-static void sp_spiral_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::SnapPreferences const *snapprefs);
+static void sp_spiral_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
 
 static void sp_spiral_set_shape (SPShape *shape);
 static void sp_spiral_update_patheffect (SPLPEItem *lpeitem, bool write);
@@ -51,24 +51,24 @@ static SPShapeClass *parent_class;
 GType
 sp_spiral_get_type (void)
 {
-       static GType spiral_type = 0;
-
-       if (!spiral_type) {
-               GTypeInfo spiral_info = {
-                       sizeof (SPSpiralClass),
-                       NULL,   /* base_init */
-                       NULL,   /* base_finalize */
-                       (GClassInitFunc) sp_spiral_class_init,
-                       NULL,   /* class_finalize */
-                       NULL,   /* class_data */
-                       sizeof (SPSpiral),
-                       16,     /* n_preallocs */
-                       (GInstanceInitFunc) sp_spiral_init,
-                       NULL,   /* value_table */
-               };
-               spiral_type = g_type_register_static (SP_TYPE_SHAPE, "SPSpiral", &spiral_info, (GTypeFlags)0);
-       }
-       return spiral_type;
+    static GType spiral_type = 0;
+
+    if (!spiral_type) {
+        GTypeInfo spiral_info = {
+            sizeof (SPSpiralClass),
+            NULL,    /* base_init */
+            NULL,    /* base_finalize */
+            (GClassInitFunc) sp_spiral_class_init,
+            NULL,    /* class_finalize */
+            NULL,    /* class_data */
+            sizeof (SPSpiral),
+            16,    /* n_preallocs */
+            (GInstanceInitFunc) sp_spiral_init,
+            NULL,    /* value_table */
+        };
+        spiral_type = g_type_register_static (SP_TYPE_SHAPE, "SPSpiral", &spiral_info, (GTypeFlags)0);
+    }
+    return spiral_type;
 }
 
 /**
@@ -77,27 +77,27 @@ sp_spiral_get_type (void)
 static void
 sp_spiral_class_init (SPSpiralClass *klass)
 {
-       GObjectClass * gobject_class;
-       SPObjectClass * sp_object_class;
-       SPItemClass * item_class;
-       SPLPEItemClass * lpe_item_class;
-       SPShapeClass *shape_class;
+    GObjectClass * gobject_class;
+    SPObjectClass * sp_object_class;
+    SPItemClass * item_class;
+    SPLPEItemClass * lpe_item_class;
+    SPShapeClass *shape_class;
 
-       gobject_class = (GObjectClass *) klass;
-       sp_object_class = (SPObjectClass *) klass;
-       item_class = (SPItemClass *) klass;
-       lpe_item_class = (SPLPEItemClass *) klass;
-       shape_class = (SPShapeClass *) klass;
+    gobject_class = (GObjectClass *) klass;
+    sp_object_class = (SPObjectClass *) klass;
+    item_class = (SPItemClass *) klass;
+    lpe_item_class = (SPLPEItemClass *) klass;
+    shape_class = (SPShapeClass *) klass;
 
-       parent_class = (SPShapeClass *)g_type_class_ref (SP_TYPE_SHAPE);
+    parent_class = (SPShapeClass *)g_type_class_ref (SP_TYPE_SHAPE);
 
-       sp_object_class->build = sp_spiral_build;
-       sp_object_class->write = sp_spiral_write;
-       sp_object_class->set = sp_spiral_set;
-       sp_object_class->update = sp_spiral_update;
+    sp_object_class->build = sp_spiral_build;
+    sp_object_class->write = sp_spiral_write;
+    sp_object_class->set = sp_spiral_set;
+    sp_object_class->update = sp_spiral_update;
 
-       item_class->description = sp_spiral_description;
-       item_class->snappoints = sp_spiral_snappoints;
+    item_class->description = sp_spiral_description;
+    item_class->snappoints = sp_spiral_snappoints;
 
     lpe_item_class->update_patheffect = sp_spiral_update_patheffect;
 
@@ -110,13 +110,13 @@ sp_spiral_class_init (SPSpiralClass *klass)
 static void
 sp_spiral_init (SPSpiral * spiral)
 {
-       spiral->cx         = 0.0;
-       spiral->cy         = 0.0;
-       spiral->exp        = 1.0;
-       spiral->revo       = 3.0;
-       spiral->rad        = 1.0;
-       spiral->arg        = 0.0;
-       spiral->t0         = 0.0;
+    spiral->cx         = 0.0;
+    spiral->cy         = 0.0;
+    spiral->exp        = 1.0;
+    spiral->revo       = 3.0;
+    spiral->rad        = 1.0;
+    spiral->arg        = 0.0;
+    spiral->t0         = 0.0;
 }
 
 /**
@@ -125,16 +125,16 @@ sp_spiral_init (SPSpiral * spiral)
 static void
 sp_spiral_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr)
 {
-       if (((SPObjectClass *) parent_class)->build)
-               ((SPObjectClass *) parent_class)->build (object, document, repr);
-
-       sp_object_read_attr (object, "sodipodi:cx");
-       sp_object_read_attr (object, "sodipodi:cy");
-       sp_object_read_attr (object, "sodipodi:expansion");
-       sp_object_read_attr (object, "sodipodi:revolution");
-       sp_object_read_attr (object, "sodipodi:radius");
-       sp_object_read_attr (object, "sodipodi:argument");
-       sp_object_read_attr (object, "sodipodi:t0");
+    if (((SPObjectClass *) parent_class)->build)
+        ((SPObjectClass *) parent_class)->build (object, document, repr);
+
+    object->readAttr( "sodipodi:cx" );
+    object->readAttr( "sodipodi:cy" );
+    object->readAttr( "sodipodi:expansion" );
+    object->readAttr( "sodipodi:revolution" );
+    object->readAttr( "sodipodi:radius" );
+    object->readAttr( "sodipodi:argument" );
+    object->readAttr( "sodipodi:t0" );
 }
 
 /**
@@ -143,25 +143,25 @@ sp_spiral_build (SPObject * object, SPDocument * document, Inkscape::XML::Node *
 static Inkscape::XML::Node *
 sp_spiral_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 {
-       SPSpiral *spiral = SP_SPIRAL (object);
-
-       if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-               repr = xml_doc->createElement("svg:path");
-       }
-
-       if (flags & SP_OBJECT_WRITE_EXT) {
-               /* Fixme: we may replace these attributes by
-                * sodipodi:spiral="cx cy exp revo rad arg t0"
-                */
-               repr->setAttribute("sodipodi:type", "spiral");
-               sp_repr_set_svg_double(repr, "sodipodi:cx", spiral->cx);
-               sp_repr_set_svg_double(repr, "sodipodi:cy", spiral->cy);
-               sp_repr_set_svg_double(repr, "sodipodi:expansion", spiral->exp);
-               sp_repr_set_svg_double(repr, "sodipodi:revolution", spiral->revo);
-               sp_repr_set_svg_double(repr, "sodipodi:radius", spiral->rad);
-               sp_repr_set_svg_double(repr, "sodipodi:argument", spiral->arg);
-               sp_repr_set_svg_double(repr, "sodipodi:t0", spiral->t0);
-       }
+    SPSpiral *spiral = SP_SPIRAL (object);
+
+    if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
+        repr = xml_doc->createElement("svg:path");
+    }
+
+    if (flags & SP_OBJECT_WRITE_EXT) {
+        /* Fixme: we may replace these attributes by
+         * sodipodi:spiral="cx cy exp revo rad arg t0"
+         */
+        repr->setAttribute("sodipodi:type", "spiral");
+        sp_repr_set_svg_double(repr, "sodipodi:cx", spiral->cx);
+        sp_repr_set_svg_double(repr, "sodipodi:cy", spiral->cy);
+        sp_repr_set_svg_double(repr, "sodipodi:expansion", spiral->exp);
+        sp_repr_set_svg_double(repr, "sodipodi:revolution", spiral->revo);
+        sp_repr_set_svg_double(repr, "sodipodi:radius", spiral->rad);
+        sp_repr_set_svg_double(repr, "sodipodi:argument", spiral->arg);
+        sp_repr_set_svg_double(repr, "sodipodi:t0", spiral->t0);
+    }
 
      // make sure the curve is rebuilt with all up-to-date parameters
      sp_spiral_set_shape ((SPShape *) spiral);
@@ -189,61 +189,61 @@ sp_spiral_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::X
 static void
 sp_spiral_set (SPObject *object, unsigned int key, const gchar *value)
 {
-       SPSpiral *spiral;
-       SPShape  *shape;
-
-       spiral = SP_SPIRAL (object);
-       shape  = SP_SHAPE (object);
-
-       /// \todo fixme: we should really collect updates
-       switch (key) {
-       case SP_ATTR_SODIPODI_CX:
-               if (!sp_svg_length_read_computed_absolute (value, &spiral->cx)) {
-                       spiral->cx = 0.0;
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       case SP_ATTR_SODIPODI_CY:
-               if (!sp_svg_length_read_computed_absolute (value, &spiral->cy)) {
-                       spiral->cy = 0.0;
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       case SP_ATTR_SODIPODI_EXPANSION:
-               if (value) {
-                       /** \todo
+    SPSpiral *spiral;
+    SPShape  *shape;
+
+    spiral = SP_SPIRAL (object);
+    shape  = SP_SHAPE (object);
+
+    /// \todo fixme: we should really collect updates
+    switch (key) {
+    case SP_ATTR_SODIPODI_CX:
+        if (!sp_svg_length_read_computed_absolute (value, &spiral->cx)) {
+            spiral->cx = 0.0;
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    case SP_ATTR_SODIPODI_CY:
+        if (!sp_svg_length_read_computed_absolute (value, &spiral->cy)) {
+            spiral->cy = 0.0;
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    case SP_ATTR_SODIPODI_EXPANSION:
+        if (value) {
+            /** \todo
                          * FIXME: check that value looks like a (finite)
                          * number. Create a routine that uses strtod, and
                          * accepts a default value (if strtod finds an error).
                          * N.B. atof/sscanf/strtod consider "nan" and "inf"
                          * to be valid numbers.
                          */
-                       spiral->exp = g_ascii_strtod (value, NULL);
-                       spiral->exp = CLAMP (spiral->exp, 0.0, 1000.0);
-               } else {
-                       spiral->exp = 1.0;
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       case SP_ATTR_SODIPODI_REVOLUTION:
-               if (value) {
-                       spiral->revo = g_ascii_strtod (value, NULL);
-                       spiral->revo = CLAMP (spiral->revo, 0.05, 1024.0);
-               } else {
-                       spiral->revo = 3.0;
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       case SP_ATTR_SODIPODI_RADIUS:
-               if (!sp_svg_length_read_computed_absolute (value, &spiral->rad)) {
-                       spiral->rad = MAX (spiral->rad, 0.001);
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       case SP_ATTR_SODIPODI_ARGUMENT:
-               if (value) {
-                       spiral->arg = g_ascii_strtod (value, NULL);
-                       /** \todo
+            spiral->exp = g_ascii_strtod (value, NULL);
+            spiral->exp = CLAMP (spiral->exp, 0.0, 1000.0);
+        } else {
+            spiral->exp = 1.0;
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    case SP_ATTR_SODIPODI_REVOLUTION:
+        if (value) {
+            spiral->revo = g_ascii_strtod (value, NULL);
+            spiral->revo = CLAMP (spiral->revo, 0.05, 1024.0);
+        } else {
+            spiral->revo = 3.0;
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    case SP_ATTR_SODIPODI_RADIUS:
+        if (!sp_svg_length_read_computed_absolute (value, &spiral->rad)) {
+            spiral->rad = MAX (spiral->rad, 0.001);
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    case SP_ATTR_SODIPODI_ARGUMENT:
+        if (value) {
+            spiral->arg = g_ascii_strtod (value, NULL);
+            /** \todo
                          * FIXME: We still need some bounds on arg, for
                          * numerical reasons. E.g., we don't want inf or NaN,
                          * nor near-infinite numbers. I'm inclined to take
@@ -251,32 +251,32 @@ sp_spiral_set (SPObject *object, unsigned int key, const gchar *value)
                          * which use atan2 - revo*2*pi, which typically
                          * results in very negative arg.
                          */
-               } else {
-                       spiral->arg = 0.0;
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       case SP_ATTR_SODIPODI_T0:
-               if (value) {
-                       spiral->t0 = g_ascii_strtod (value, NULL);
-                       spiral->t0 = CLAMP (spiral->t0, 0.0, 0.999);
-                       /** \todo
+        } else {
+            spiral->arg = 0.0;
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    case SP_ATTR_SODIPODI_T0:
+        if (value) {
+            spiral->t0 = g_ascii_strtod (value, NULL);
+            spiral->t0 = CLAMP (spiral->t0, 0.0, 0.999);
+            /** \todo
                          * Have shared constants for the allowable bounds for
                          * attributes. There was a bug here where we used -1.0
                          * as the minimum (which leads to NaN via, e.g.,
                          * pow(-1.0, 0.5); see sp_spiral_get_xy for
                          * requirements.
                          */
-               } else {
-                       spiral->t0 = 0.0;
-               }
-               object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
-               break;
-       default:
-               if (((SPObjectClass *) parent_class)->set)
-                       ((SPObjectClass *) parent_class)->set (object, key, value);
-               break;
-       }
+        } else {
+            spiral->t0 = 0.0;
+        }
+        object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+        break;
+    default:
+        if (((SPObjectClass *) parent_class)->set)
+            ((SPObjectClass *) parent_class)->set (object, key, value);
+        break;
+    }
 }
 
 /**
@@ -285,12 +285,12 @@ sp_spiral_set (SPObject *object, unsigned int key, const gchar *value)
 static void
 sp_spiral_update (SPObject *object, SPCtx *ctx, guint flags)
 {
-       if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
-               sp_shape_set_shape ((SPShape *) object);
-       }
+    if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+        ((SPShape *) object)->setShape ();
+    }
 
-       if (((SPObjectClass *) parent_class)->update)
-               ((SPObjectClass *) parent_class)->update (object, ctx, flags);
+    if (((SPObjectClass *) parent_class)->update)
+        ((SPObjectClass *) parent_class)->update (object, ctx, flags);
 }
 
 static void
@@ -319,9 +319,9 @@ sp_spiral_update_patheffect(SPLPEItem *lpeitem, bool write)
 static gchar *
 sp_spiral_description (SPItem * item)
 {
-       // TRANSLATORS: since turn count isn't an integer, please adjust the
-       // string as needed to deal with an localized plural forms.
-       return g_strdup_printf (_("<b>Spiral</b> with %3f turns"), SP_SPIRAL(item)->revo);
+    // TRANSLATORS: since turn count isn't an integer, please adjust the
+    // string as needed to deal with an localized plural forms.
+    return g_strdup_printf (_("<b>Spiral</b> with %3f turns"), SP_SPIRAL(item)->revo);
 }
 
 
@@ -334,34 +334,34 @@ sp_spiral_description (SPItem * item)
  **/
 static void
 sp_spiral_fit_and_draw (SPSpiral const *spiral,
-                       SPCurve  *c,
-                       double dstep,
-                       Geom::Point darray[],
-                       Geom::Point const &hat1,
-                       Geom::Point &hat2,
-                       double *t)
+            SPCurve     *c,
+            double dstep,
+            Geom::Point darray[],
+            Geom::Point const &hat1,
+            Geom::Point &hat2,
+            double *t)
 {
 #define BEZIER_SIZE   4
 #define FITTING_MAX_BEZIERS 4
 #define BEZIER_LENGTH (BEZIER_SIZE * FITTING_MAX_BEZIERS)
-       g_assert (dstep > 0);
-       g_assert (is_unit_vector (hat1));
-
-       Geom::Point bezier[BEZIER_LENGTH];
-       double d;
-       int depth, i;
-
-       for (d = *t, i = 0; i <= SAMPLE_SIZE; d += dstep, i++) {
-               darray[i] = sp_spiral_get_xy(spiral, d);
-
-               /* Avoid useless adjacent dups.  (Otherwise we can have all of darray filled with
-                  the same value, which upsets chord_length_parameterize.) */
-               if ((i != 0)
-                   && (darray[i] == darray[i - 1])
-                   && (d < 1.0)) {
-                       i--;
-                       d += dstep;
-                       /** We mustn't increase dstep for subsequent values of
+    g_assert (dstep > 0);
+    g_assert (is_unit_vector (hat1));
+
+    Geom::Point bezier[BEZIER_LENGTH];
+    double d;
+    int depth, i;
+
+    for (d = *t, i = 0; i <= SAMPLE_SIZE; d += dstep, i++) {
+        darray[i] = sp_spiral_get_xy(spiral, d);
+
+        /* Avoid useless adjacent dups.  (Otherwise we can have all of darray filled with
+           the same value, which upsets chord_length_parameterize.) */
+        if ((i != 0)
+            && (darray[i] == darray[i - 1])
+            && (d < 1.0)) {
+            i--;
+            d += dstep;
+            /** We mustn't increase dstep for subsequent values of
                          * i: for large spiral.exp values, rate of growth
                          * increases very rapidly.
                          */
@@ -377,86 +377,107 @@ sp_spiral_fit_and_draw (SPSpiral const *spiral,
                          * value for next iteration to avoid the problem
                          * mentioned above.
                          */
-               }
-       }
+        }
+    }
 
-       double const next_t = d - 2 * dstep;
-       /* == t + (SAMPLE_SIZE - 1) * dstep, in absence of dups. */
+    double const next_t = d - 2 * dstep;
+    /* == t + (SAMPLE_SIZE - 1) * dstep, in absence of dups. */
 
-       hat2 = -sp_spiral_get_tangent (spiral, next_t);
+    hat2 = -sp_spiral_get_tangent (spiral, next_t);
 
-       /** \todo
+    /** \todo
          * We should use better algorithm to specify maximum error.
          */
-       depth = sp_bezier_fit_cubic_full (bezier, NULL, darray, SAMPLE_SIZE,
-                                         hat1, hat2,
-                                         SPIRAL_TOLERANCE*SPIRAL_TOLERANCE,
-                                         FITTING_MAX_BEZIERS);
-       g_assert(depth * BEZIER_SIZE <= gint(G_N_ELEMENTS(bezier)));
+    depth = Geom::bezier_fit_cubic_full (bezier, NULL, darray, SAMPLE_SIZE,
+                      hat1, hat2,
+                      SPIRAL_TOLERANCE*SPIRAL_TOLERANCE,
+                      FITTING_MAX_BEZIERS);
+    g_assert(depth * BEZIER_SIZE <= gint(G_N_ELEMENTS(bezier)));
 #ifdef SPIRAL_DEBUG
-       if (*t == spiral->t0 || *t == 1.0)
-               g_print ("[%s] depth=%d, dstep=%g, t0=%g, t=%g, arg=%g\n",
-                        debug_state, depth, dstep, spiral->t0, *t, spiral->arg);
+    if (*t == spiral->t0 || *t == 1.0)
+        g_print ("[%s] depth=%d, dstep=%g, t0=%g, t=%g, arg=%g\n",
+             debug_state, depth, dstep, spiral->t0, *t, spiral->arg);
 #endif
-       if (depth != -1) {
-               for (i = 0; i < 4*depth; i += 4) {
-                       c->curveto(bezier[i + 1],
-                                         bezier[i + 2],
-                                         bezier[i + 3]);
-               }
-       } else {
+    if (depth != -1) {
+        for (i = 0; i < 4*depth; i += 4) {
+            c->curveto(bezier[i + 1],
+                      bezier[i + 2],
+                      bezier[i + 3]);
+        }
+    } else {
 #ifdef SPIRAL_VERBOSE
-               g_print ("cant_fit_cubic: t=%g\n", *t);
+        g_print ("cant_fit_cubic: t=%g\n", *t);
 #endif
-               for (i = 1; i < SAMPLE_SIZE; i++)
-                       c->lineto(darray[i]);
-       }
-       *t = next_t;
-       g_assert (is_unit_vector (hat2));
+        for (i = 1; i < SAMPLE_SIZE; i++)
+            c->lineto(darray[i]);
+    }
+    *t = next_t;
+    g_assert (is_unit_vector (hat2));
 }
 
 static void
 sp_spiral_set_shape (SPShape *shape)
 {
-       Geom::Point darray[SAMPLE_SIZE + 1];
-       double t;
+    SPSpiral *spiral = SP_SPIRAL(shape);
+
+    if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) {
+        g_warning ("The spiral shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as spiral will remove the bad LPE");
+        if (SP_OBJECT_REPR(shape)->attribute("d")) {
+            // unconditionally read the curve from d, if any, to preserve appearance
+            Geom::PathVector pv = sp_svg_read_pathv(SP_OBJECT_REPR(shape)->attribute("d"));
+            SPCurve *cold = new SPCurve(pv);
+            shape->setCurveInsync( cold, TRUE);
+            cold->unref();
+        }
+        return;
+    }
 
-       SPSpiral *spiral = SP_SPIRAL(shape);
+    Geom::Point darray[SAMPLE_SIZE + 1];
+    double t;
 
-       SP_OBJECT (spiral)->requestModified(SP_OBJECT_MODIFIED_FLAG);
+    SP_OBJECT (spiral)->requestModified(SP_OBJECT_MODIFIED_FLAG);
+
+    SPCurve *c = new SPCurve ();
 
-       SPCurve *c = new SPCurve ();
-       
 #ifdef SPIRAL_VERBOSE
-       g_print ("cx=%g, cy=%g, exp=%g, revo=%g, rad=%g, arg=%g, t0=%g\n",
-                spiral->cx,
-                spiral->cy,
-                spiral->exp,
-                spiral->revo,
-                spiral->rad,
-                spiral->arg,
-                spiral->t0);
+    g_print ("cx=%g, cy=%g, exp=%g, revo=%g, rad=%g, arg=%g, t0=%g\n",
+         spiral->cx,
+         spiral->cy,
+         spiral->exp,
+         spiral->revo,
+         spiral->rad,
+         spiral->arg,
+         spiral->t0);
 #endif
 
-       /* Initial moveto. */
-       c->moveto(sp_spiral_get_xy(spiral, spiral->t0));
-
-       double const tstep = SAMPLE_STEP / spiral->revo;
-       double const dstep = tstep / (SAMPLE_SIZE - 1);
+    /* Initial moveto. */
+    c->moveto(sp_spiral_get_xy(spiral, spiral->t0));
 
-       Geom::Point hat1 = sp_spiral_get_tangent (spiral, spiral->t0);
-       Geom::Point hat2;
-       for (t = spiral->t0; t < (1.0 - tstep);) {
-               sp_spiral_fit_and_draw (spiral, c, dstep, darray, hat1, hat2, &t);
+    double const tstep = SAMPLE_STEP / spiral->revo;
+    double const dstep = tstep / (SAMPLE_SIZE - 1);
 
-               hat1 = -hat2;
-       }
-       if ((1.0 - t) > SP_EPSILON)
-               sp_spiral_fit_and_draw (spiral, c, (1.0 - t)/(SAMPLE_SIZE - 1.0),
-                                       darray, hat1, hat2, &t);
+    Geom::Point hat1 = sp_spiral_get_tangent (spiral, spiral->t0);
+    Geom::Point hat2;
+    for (t = spiral->t0; t < (1.0 - tstep);) {
+        sp_spiral_fit_and_draw (spiral, c, dstep, darray, hat1, hat2, &t);
 
-    sp_lpe_item_perform_path_effect(SP_LPE_ITEM (spiral), c);
-    sp_shape_set_curve_insync ((SPShape *) spiral, c, TRUE);
+        hat1 = -hat2;
+    }
+    if ((1.0 - t) > SP_EPSILON)
+        sp_spiral_fit_and_draw (spiral, c, (1.0 - t)/(SAMPLE_SIZE - 1.0),
+                    darray, hat1, hat2, &t);
+
+    /* Reset the shape'scurve to the "original_curve"
+     * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
+    shape->setCurveInsync( c, TRUE);
+    if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) {
+        SPCurve *c_lpe = c->copy();
+        bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe);
+        if (success) {
+            shape->setCurveInsync( c_lpe, TRUE);
+        }
+        c_lpe->unref();
+    }
     c->unref();
 }
 
@@ -465,40 +486,58 @@ sp_spiral_set_shape (SPShape *shape)
  */
 void
 sp_spiral_position_set       (SPSpiral          *spiral,
-                    gdouble            cx,
-                    gdouble            cy,
-                    gdouble            exp,
-                    gdouble            revo,
-                    gdouble            rad,
-                    gdouble            arg,
-                    gdouble            t0)
+             gdouble            cx,
+             gdouble            cy,
+             gdouble            exp,
+             gdouble            revo,
+             gdouble            rad,
+             gdouble            arg,
+             gdouble            t0)
 {
-       g_return_if_fail (spiral != NULL);
-       g_return_if_fail (SP_IS_SPIRAL (spiral));
+    g_return_if_fail (spiral != NULL);
+    g_return_if_fail (SP_IS_SPIRAL (spiral));
 
-       /** \todo
+    /** \todo
          * Consider applying CLAMP or adding in-bounds assertions for
          * some of these parameters.
          */
-       spiral->cx         = cx;
-       spiral->cy         = cy;
-       spiral->exp        = exp;
-       spiral->revo       = revo;
-       spiral->rad        = MAX (rad, 0.001);
-       spiral->arg        = arg;
-       spiral->t0         = CLAMP(t0, 0.0, 0.999);
-       
-       ((SPObject *)spiral)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+    spiral->cx         = cx;
+    spiral->cy         = cy;
+    spiral->exp        = exp;
+    spiral->revo       = revo;
+    spiral->rad        = MAX (rad, 0.0);
+    spiral->arg        = arg;
+    spiral->t0         = CLAMP(t0, 0.0, 0.999);
+
+    ((SPObject *)spiral)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
 /**
  * Virtual snappoints callback.
  */
-static void sp_spiral_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::SnapPreferences const *snapprefs)
+static void sp_spiral_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
 {
-       if (((SPItemClass *) parent_class)->snappoints) {
-               ((SPItemClass *) parent_class)->snappoints (item, p, snapprefs);
-       }
+    // We will determine the spiral's midpoint ourselves, instead of trusting on the base class
+    // Therefore setSnapObjectMidpoints() is set to false temporarily
+    Inkscape::SnapPreferences local_snapprefs = *snapprefs;
+    local_snapprefs.setSnapObjectMidpoints(false);
+
+    if (((SPItemClass *) parent_class)->snappoints) {
+        ((SPItemClass *) parent_class)->snappoints (item, p, &local_snapprefs);
+    }
+
+    // Help enforcing strict snapping, i.e. only return nodes when we're snapping nodes to nodes or a guide to nodes
+    if (!(snapprefs->getSnapModeNode() || snapprefs->getSnapModeGuide())) {
+        return;
+    }
+
+    if (snapprefs->getSnapObjectMidpoints()) {
+        Geom::Matrix const i2d (item->i2d_affine ());
+        SPSpiral *spiral = SP_SPIRAL(item);
+        p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(spiral->cx, spiral->cy) * i2d, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT));
+        // This point is the start-point of the spiral, which is also returned when _snap_to_itemnode has been set
+        // in the object snapper. In that case we will get a duplicate!
+    }
 }
 
 /**
@@ -511,19 +550,19 @@ static void sp_spiral_snappoints(SPItem const *item, SnapPointsIter p, Inkscape:
  */
 Geom::Point sp_spiral_get_xy (SPSpiral const *spiral, gdouble t)
 {
-       g_assert (spiral != NULL);
-       g_assert (SP_IS_SPIRAL(spiral));
-       g_assert (spiral->exp >= 0.0);
-       /* Otherwise we get NaN for t==0. */
-       g_assert (spiral->exp <= 1000.0);
-       /* Anything much more results in infinities.  Even allowing 1000 is somewhat overkill. */
-       g_assert (t >= 0.0);
-       /* Any callers passing -ve t will have a bug for non-integral values of exp. */
-
-       double const rad = spiral->rad * pow(t, (double) spiral->exp);
-       double const arg = 2.0 * M_PI * spiral->revo * t + spiral->arg;
-
-       return Geom::Point(rad * cos (arg) + spiral->cx,
+    g_assert (spiral != NULL);
+    g_assert (SP_IS_SPIRAL(spiral));
+    g_assert (spiral->exp >= 0.0);
+    /* Otherwise we get NaN for t==0. */
+    g_assert (spiral->exp <= 1000.0);
+    /* Anything much more results in infinities.  Even allowing 1000 is somewhat overkill. */
+    g_assert (t >= 0.0);
+    /* Any callers passing -ve t will have a bug for non-integral values of exp. */
+
+    double const rad = spiral->rad * pow(t, (double) spiral->exp);
+    double const arg = 2.0 * M_PI * spiral->revo * t + spiral->arg;
+
+    return Geom::Point(rad * cos (arg) + spiral->cx,
                            rad * sin (arg) + spiral->cy);
 }
 
@@ -540,58 +579,58 @@ Geom::Point sp_spiral_get_xy (SPSpiral const *spiral, gdouble t)
 static Geom::Point
 sp_spiral_get_tangent (SPSpiral const *spiral, gdouble t)
 {
-       Geom::Point ret(1.0, 0.0);
-       g_return_val_if_fail (( ( spiral != NULL )
-                               && SP_IS_SPIRAL(spiral) ),
-                             ret);
-       g_assert (t >= 0.0);
-       g_assert (spiral->exp >= 0.0);
-       /* See above for comments on these assertions. */
-
-       double const t_scaled = 2.0 * M_PI * spiral->revo * t;
-       double const arg = t_scaled + spiral->arg;
-       double const s = sin (arg);
-       double const c = cos (arg);
-
-       if (spiral->exp == 0.0) {
-               ret = Geom::Point(-s, c);
-       } else if (t_scaled == 0.0) {
-               ret = Geom::Point(c, s);
-       } else {
-               Geom::Point unrotated(spiral->exp, t_scaled);
-               double const s_len = L2 (unrotated);
-               g_assert (s_len != 0);
-               /** \todo
+    Geom::Point ret(1.0, 0.0);
+    g_return_val_if_fail (( ( spiral != NULL )
+                && SP_IS_SPIRAL(spiral) ),
+                  ret);
+    g_assert (t >= 0.0);
+    g_assert (spiral->exp >= 0.0);
+    /* See above for comments on these assertions. */
+
+    double const t_scaled = 2.0 * M_PI * spiral->revo * t;
+    double const arg = t_scaled + spiral->arg;
+    double const s = sin (arg);
+    double const c = cos (arg);
+
+    if (spiral->exp == 0.0) {
+        ret = Geom::Point(-s, c);
+    } else if (t_scaled == 0.0) {
+        ret = Geom::Point(c, s);
+    } else {
+        Geom::Point unrotated(spiral->exp, t_scaled);
+        double const s_len = L2 (unrotated);
+        g_assert (s_len != 0);
+        /** \todo
                  * Check that this isn't being too hopeful of the hypot
                  * function.  E.g. test with numbers around 2**-1070
                  * (denormalized numbers), preferably on a few different
                  * platforms.  However, njh says that the usual implementation
                  * does handle both very big and very small numbers.
                  */
-               unrotated /= s_len;
+        unrotated /= s_len;
 
-               /* ret = spiral->exp * (c, s) + t_scaled * (-s, c);
-                  alternatively ret = (spiral->exp, t_scaled) * (( c, s),
-                                                                 (-s, c)).*/
-               ret = Geom::Point(dot(unrotated, Geom::Point(c, -s)),
+        /* ret = spiral->exp * (c, s) + t_scaled * (-s, c);
+           alternatively ret = (spiral->exp, t_scaled) * (( c, s),
+                                  (-s, c)).*/
+        ret = Geom::Point(dot(unrotated, Geom::Point(c, -s)),
                                   dot(unrotated, Geom::Point(s, c)));
-               /* ret should already be approximately normalized: the
-                  matrix ((c, -s), (s, c)) is orthogonal (it just
-                  rotates by arg), and unrotated has been normalized,
-                  so ret is already of unit length other than numerical
-                  error in the above matrix multiplication. */
+        /* ret should already be approximately normalized: the
+           matrix ((c, -s), (s, c)) is orthogonal (it just
+           rotates by arg), and unrotated has been normalized,
+           so ret is already of unit length other than numerical
+           error in the above matrix multiplication. */
 
-               /** \todo
+        /** \todo
                  * I haven't checked how important it is for ret to be very
                  * near unit length; we could get rid of the below.
                  */
 
-               ret.normalize();
-               /* Proof that ret length is non-zero: see above.  (Should be near 1.) */
-       }
+        ret.normalize();
+        /* Proof that ret length is non-zero: see above.  (Should be near 1.) */
+    }
 
-       g_assert (is_unit_vector (ret));
-       return ret;
+    g_assert (is_unit_vector (ret));
+    return ret;
 }
 
 /**
@@ -600,13 +639,13 @@ sp_spiral_get_tangent (SPSpiral const *spiral, gdouble t)
 void
 sp_spiral_get_polar (SPSpiral const *spiral, gdouble t, gdouble *rad, gdouble *arg)
 {
-       g_return_if_fail (spiral != NULL);
-       g_return_if_fail (SP_IS_SPIRAL(spiral));
+    g_return_if_fail (spiral != NULL);
+    g_return_if_fail (SP_IS_SPIRAL(spiral));
 
-       if (rad)
-               *rad = spiral->rad * pow(t, (double) spiral->exp);
-       if (arg)
-               *arg = 2.0 * M_PI * spiral->revo * t + spiral->arg;
+    if (rad)
+        *rad = spiral->rad * pow(t, (double) spiral->exp);
+    if (arg)
+        *arg = 2.0 * M_PI * spiral->revo * t + spiral->arg;
 }
 
 /**
@@ -615,19 +654,19 @@ sp_spiral_get_polar (SPSpiral const *spiral, gdouble t, gdouble *rad, gdouble *a
 bool
 sp_spiral_is_invalid (SPSpiral const *spiral)
 {
-       gdouble rad;
-
-       sp_spiral_get_polar (spiral, 0.0, &rad, NULL);
-       if (rad < 0.0 || rad > SP_HUGE) {
-               g_print ("rad(t=0)=%g\n", rad);
-               return TRUE;
-       }
-       sp_spiral_get_polar (spiral, 1.0, &rad, NULL);
-       if (rad < 0.0 || rad > SP_HUGE) {
-               g_print ("rad(t=1)=%g\n", rad);
-               return TRUE;
-       }
-       return FALSE;
+    gdouble rad;
+
+    sp_spiral_get_polar (spiral, 0.0, &rad, NULL);
+    if (rad < 0.0 || rad > SP_HUGE) {
+        g_print ("rad(t=0)=%g\n", rad);
+        return TRUE;
+    }
+    sp_spiral_get_polar (spiral, 1.0, &rad, NULL);
+    if (rad < 0.0 || rad > SP_HUGE) {
+        g_print ("rad(t=1)=%g\n", rad);
+        return TRUE;
+    }
+    return FALSE;
 }
 
 /*
@@ -639,4 +678,4 @@ sp_spiral_is_invalid (SPSpiral const *spiral)
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :