sp-spiral.cpp revision 614803e35e3ee7d3f0d70185487258fd7595daf6
#define __SP_SPIRAL_C__
/** \file
* <sodipodi:spiral> implementation
*/
/*
* Authors:
* Mitsuru Oka <oka326@parkcity.ne.jp>
* Lauris Kaplinski <lauris@kaplinski.com>
*
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "config.h"
#include "attributes.h"
#include "display/bezier-utils.h"
#include "sp-spiral.h"
static Inkscape::XML::Node *sp_spiral_write (SPObject *object, Inkscape::XML::Node *repr, guint flags);
static SPShapeClass *parent_class;
/**
* Register SPSpiral class and return its type number.
*/
sp_spiral_get_type (void)
{
static GType spiral_type = 0;
if (!spiral_type) {
GTypeInfo spiral_info = {
sizeof (SPSpiralClass),
NULL, /* base_init */
NULL, /* base_finalize */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (SPSpiral),
16, /* n_preallocs */
NULL, /* value_table */
};
}
return spiral_type;
}
/**
* SPSpiral vtable initialization.
*/
static void
{
}
/**
* Callback for SPSpiral object initialization.
*/
static void
{
}
/**
* Virtual build: set spiral properties from corresponding repr.
*/
static void
{
}
/**
* Virtual write: write spiral attributes to corresponding repr.
*/
{
}
if (flags & SP_OBJECT_WRITE_EXT) {
/* Fixme: we may replace these attributes by
* sodipodi:spiral="cx cy exp revo rad arg t0"
*/
}
// make sure the curve is rebuilt with all up-to-date parameters
//Duplicate the path
//Nulls might be possible if this called iteratively
if ( !curve ) {
//g_warning("sp_spiral_write(): No path to copy\n");
return NULL;
}
if ( !bpath ) {
//g_warning("sp_spiral_write(): No path to copy\n");
return NULL;
}
char *d = sp_svg_write_path ( bpath );
g_free (d);
return repr;
}
/**
* Virtual set: change spiral object attribute.
*/
static void
{
/// \todo fixme: we should really collect updates
switch (key) {
case SP_ATTR_SODIPODI_CX:
}
break;
case SP_ATTR_SODIPODI_CY:
}
break;
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).
* to be valid numbers.
*/
} else {
}
break;
if (value) {
} else {
}
break;
case SP_ATTR_SODIPODI_RADIUS:
}
break;
if (value) {
/** \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
* modulo 2*pi. If so, then change the knot editors,
* which use atan2 - revo*2*pi, which typically
* results in very negative arg.
*/
} else {
}
break;
case SP_ATTR_SODIPODI_T0:
if (value) {
/** \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 {
}
break;
default:
break;
}
}
/**
* Virtual update callback.
*/
static void
{
if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
}
}
/**
* Return textual description of spiral.
*/
static gchar *
{
// TRANSLATORS: since turn count isn't an integer, please adjust the
// string as needed to deal with an localized plural forms.
}
/**
* Fit beziers together to spiral and draw it.
*
* \pre dstep \> 0.
* \pre is_unit_vector(*hat1).
* \post is_unit_vector(*hat2).
**/
static void
SPCurve *c,
double dstep,
double *t)
{
#define BEZIER_SIZE 4
#define FITTING_MAX_BEZIERS 4
double d;
int depth, i;
for (d = *t, i = 0; i <= SAMPLE_SIZE; d += dstep, i++) {
/* Avoid useless adjacent dups. (Otherwise we can have all of darray filled with
the same value, which upsets chord_length_parameterize.) */
if ((i != 0)
&& (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.
*/
/** \todo
* Get the function itself to decide what value of d
* to use next: ensure that we move at least 0.25 *
* stroke width, for example. The derivative (as used
* for get_tangent before normalization) would be
* useful for estimating the appropriate d value. Or
* perhaps just start with a small dstep and scale by
* some small number until we move >= 0.25 *
* stroke_width. Must revert to the original dstep
* value for next iteration to avoid the problem
* mentioned above.
*/
}
}
/* == t + (SAMPLE_SIZE - 1) * dstep, in absence of dups. */
/** \todo
* We should use better algorithm to specify maximum error.
*/
#ifdef SPIRAL_DEBUG
g_print ("[%s] depth=%d, dstep=%g, t0=%g, t=%g, arg=%g\n",
#endif
if (depth != -1) {
sp_curve_curveto (c,
bezier[i + 1],
bezier[i + 2],
bezier[i + 3]);
}
} else {
#ifdef SPIRAL_VERBOSE
g_print ("cant_fit_cubic: t=%g\n", *t);
#endif
for (i = 1; i < SAMPLE_SIZE; i++)
sp_curve_lineto (c, darray[i]);
}
*t = next_t;
}
static void
{
double t;
SPCurve *c = sp_curve_new ();
#ifdef SPIRAL_VERBOSE
g_print ("cx=%g, cy=%g, exp=%g, revo=%g, rad=%g, arg=%g, t0=%g\n",
#endif
/* Initial moveto. */
}
if ((1.0 - t) > SP_EPSILON)
sp_curve_unref (c);
}
/**
* Set spiral properties and update display.
*/
void
{
/** \todo
* Consider applying CLAMP or adding in-bounds assertions for
* some of these parameters.
*/
}
/**
* Virtual snappoints callback.
*/
{
}
}
/**
* Return one of the points on the spiral.
*
* \param t specifies how far along the spiral.
* \pre \a t in [0.0, 2.03]. (It doesn't make sense for t to be much more
* than 1.0, though some callers go slightly beyond 1.0 for curve-fitting
* purposes.)
*/
{
/* Otherwise we get NaN for t==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. */
}
/**
* Returns the derivative of sp_spiral_get_xy with respect to t,
* scaled to a unit vector.
*
* \pre spiral != 0.
* \pre 0 \<= t.
* \pre p != NULL.
* \post is_unit_vector(*p).
*/
{
&& SP_IS_SPIRAL(spiral) ),
ret);
g_assert (t >= 0.0);
/* See above for comments on these assertions. */
} else if (t_scaled == 0.0) {
} else {
/** \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.
*/
/* ret = spiral->exp * (c, s) + t_scaled * (-s, c);
alternatively ret = (spiral->exp, t_scaled) * (( c, s),
(-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. */
/** \todo
* I haven't checked how important it is for ret to be very
* near unit length; we could get rid of the below.
*/
/* Proof that ret length is non-zero: see above. (Should be near 1.) */
}
return ret;
}
/**
*/
void
{
if (rad)
if (arg)
}
/**
* Return true if spiral has properties that make it invalid.
*/
bool
{
return TRUE;
}
return TRUE;
}
return FALSE;
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :