X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-spiral.cpp;h=c309c60ccfd8059ec75e516beb342b88e670cd20;hb=c559a44911579b77710f6698f1a064195da7c292;hp=71906fcc0c3b65d394e6333dd163c7640a7ddaed;hpb=6cf09988babf3a59ea36c6a48fba90177699a4c3;p=inkscape.git diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 71906fcc0..c309c60cc 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -20,6 +20,7 @@ #include "svg/svg.h" #include "attributes.h" #include <2geom/bezier-utils.h> +#include <2geom/pathvector.h> #include "display/curve.h" #include #include "xml/repr.h" @@ -36,7 +37,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, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs); +static void sp_spiral_snappoints(SPItem const *item, std::vector &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 +52,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 +78,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 +111,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 +126,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); + + 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"); } /** @@ -143,25 +144,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 +190,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 +252,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 +286,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)) { + sp_shape_set_shape ((SPShape *) object); + } - 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 +320,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 (_("Spiral 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 (_("Spiral with %3f turns"), SP_SPIRAL(item)->revo); } @@ -334,34 +335,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,83 +378,95 @@ 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 = 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))); + 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); + sp_shape_set_curve_insync (shape, 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)); + /* 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); + double const tstep = SAMPLE_STEP / spiral->revo; + double const dstep = tstep / (SAMPLE_SIZE - 1); - 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); + 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); - 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); + 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)*/ @@ -474,59 +487,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.0); - 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, bool const target, SnapPointsWithType &p, Inkscape::SnapPreferences const *snapprefs) +static void sp_spiral_snappoints(SPItem const *item, std::vector &p, Inkscape::SnapPreferences const *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, target, 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 (sp_item_i2d_affine (item)); - SPSpiral *spiral = SP_SPIRAL(item); - int type = target ? int(Inkscape::SNAPTARGET_OBJECT_MIDPOINT) : int(Inkscape::SNAPSOURCE_OBJECT_MIDPOINT); - p.push_back(std::make_pair(Geom::Point(spiral->cx, spiral->cy) * i2d, type)); - // 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! - } + // 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 (sp_item_i2d_affine (item)); + 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! + } } /** @@ -539,19 +551,19 @@ static void sp_spiral_snappoints(SPItem const *item, bool const target, SnapPoin */ 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); } @@ -568,58 +580,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; } /** @@ -628,13 +640,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; } /** @@ -643,19 +655,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; } /* @@ -667,4 +679,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 :