curve.cpp revision 016c69eca6f4b8a49961d6073a0c7935ab625d0c
#define __CURVE_C__
/** \file
* Routines for SPCurve and for NArtBpath arrays in general.
*/
/*
* Author:
* Lauris Kaplinski <lauris@kaplinski.com>
*
* Copyright (C) 2000 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
* Copyright (C) 2002 Lauris Kaplinski
*
* Released under GNU GPL
*/
#include <libnr/n-art-bpath.h>
#include <libnr/nr-point-matrix-ops.h>
#include <libnr/nr-translate-ops.h>
#define SP_CURVE_LENSTEP 32
/* Constructors */
/**
* The returned curve's state is as if sp_curve_reset has just been called on it.
*/
SPCurve *
{
return sp_curve_new_sized(SP_CURVE_LENSTEP);
}
/**
* Like sp_curve_new, but overriding the default initial capacity.
*
* The returned curve's state is as if sp_curve_reset has just been called on it.
*
* \param length Initial number of NArtBpath elements allocated for bpath (including NR_END
* element).
*/
SPCurve *
{
return curve;
}
/**
* Convert NArtBpath object to SPCurve object.
*
* \return new SPCurve, or NULL if the curve was not created for some reason.
*/
SPCurve *
{
return curve;
}
/**
* Convert const NArtBpath array to SPCurve.
*
* \return new SPCurve, or NULL if the curve was not created for some reason.
*/
{
if (!sp_bpath_good(bpath)) {
} else {
}
for (; i > 0; i--)
break;
return curve;
}
/**
* Increase refcount of curve.
*
* \todo should this be shared with other refcounting code?
*/
SPCurve *
{
return curve;
}
/**
* Decrease refcount of curve, with possible destruction.
*
* \todo should this be shared with other refcounting code?
*/
SPCurve *
{
}
}
return NULL;
}
/**
* Add space for more paths in curve.
*/
static void
{
g_return_if_fail(space > 0);
return;
if (space < SP_CURVE_LENSTEP)
}
/**
* Create new curve from its own bpath array.
*/
SPCurve *
{
}
/**
* Return new curve that is the concatenation of all curves in list.
*/
SPCurve *
{
}
}
gint i;
break;
}
return new_curve;
}
/**
* Returns a list of new curves corresponding to the subpaths in \a curve.
*/
GSList *
{
gint p = 0;
gint i = 1;
i++;
l = g_slist_append(l, new_curve);
/** \todo
* effic: Use g_slist_prepend instead. Either work backwards from
* the end of curve, or work forwards as at present but do
* g_slist_reverse before returning.
*/
p += i;
}
return l;
}
/**
* Transform all paths in curve, template helper.
*/
template<class M>
static void
{
switch (p->code) {
case NR_MOVETO:
case NR_MOVETO_OPEN:
case NR_LINETO: {
break;
}
case NR_CURVETO:
for (unsigned i = 1; i <= 3; ++i) {
p->setC(i, p->c(i) * m);
}
break;
default:
break;
}
}
}
/**
* Transform all paths in curve using matrix.
*/
void
{
}
/**
* Transform all paths in curve using NR::translate.
*/
void
{
}
/* Methods */
/**
* Set curve to empty curve.
*/
void
{
}
/* Several consecutive movetos are ALLOWED */
/**
* Calls sp_curve_moveto() with point made of given coordinates.
*/
void
{
}
/**
* Perform a moveto to a point, thus starting a new subpath.
*/
void
{
}
/**
* Calls sp_curve_lineto() with a point's coordinates.
*/
void
{
}
/**
* Adds a line to the current subpath.
*/
void
{
/* fix endpoint */
return;
}
/* start a new segment */
bp++;
bp++;
return;
}
/* add line */
bp++;
}
/// Unused
void
{
/* change endpoint */
return;
}
/* start a new segment */
bp++;
bp++;
return;
}
/* add line */
bp++;
}
/**
* Calls sp_curve_curveto() with coordinates of three points.
*/
void
{
using NR::X;
using NR::Y;
}
/**
* Adds a bezier segment to the current subpath.
*/
void
sp_curve_curveto(SPCurve *curve, gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
{
/* start a new segment */
bp++;
bp++;
return;
}
/* add curve */
bp++;
}
/**
* Close current subpath by possibly adding a line between start and end.
*/
void
{
/* We need at least moveto, curveto, end. */
{
}
}
/** \todo
* effic: Maintain a count of NR_MOVETO_OPEN's (e.g. instead of
* the closed boolean).
*/
break;
}
}
}
/** Like sp_curve_closepath() but sets the end point of the current
command to the subpath start point instead of adding a new lineto.
Used for freehand drawing when the user draws back to the start point.
**/
void
{
/* We need at least moveto, curveto, end. */
{
}
/** \todo
* effic: Maintain a count of NR_MOVETO_OPEN's (e.g. instead of
* the closed boolean).
*/
break;
}
}
}
/**
* True if no paths are in curve.
*/
bool
{
}
/**
* Return last subpath or NULL.
*/
{
return NULL;
}
}
/**
* Return first subpath or NULL.
*/
{
return NULL;
}
}
/**
* Return first point of first subpath or (0,0).
*/
{
return bpath->c(3);
}
/**
* Return the second point of first subpath or curve->movePos if curve too short.
*/
{
}
} else {
}
return bpath->c(3);
}
/**
* Return the second-last point of last subpath or curve->movePos if curve too short.
*/
{
}
return bpath->c(3);
}
/**
* Return last point of last subpath or (0,0).
*/
{
return bpath->c(3);
}
inline static bool
is_moveto(NRPathcode const c)
{
return c == NR_MOVETO || c == NR_MOVETO_OPEN;
}
/**
* Returns \a curve but drawn in the opposite direction.
* Should result in the same shape, but
* with all its markers drawn facing the other direction.
**/
SPCurve *
{
/* We need at least moveto, curveto, end. */
case NR_MOVETO:
/* FALL-THROUGH */
case NR_MOVETO_OPEN:
return new_curve;
}
break;
case NR_LINETO:
break;
case NR_CURVETO:
break;
default:
}
}
}
/**
* Append \a curve2 to \a curve.
*/
void
bool use_lineto)
{
return;
case NR_MOVETO_OPEN:
use_lineto = FALSE;
} else {
}
closed = false;
break;
case NR_MOVETO:
use_lineto = FALSE;
} else {
}
closed = true;
break;
case NR_LINETO:
break;
case NR_CURVETO:
break;
case NR_END:
}
}
if (closed) {
}
}
/**
* Append \a c1 to \a c0 with possible fusing of close endpoints.
*/
SPCurve *
{
return c0;
}
if (be) {
if ( bs
{
/** \todo
* fixme: Strictly we mess in case of multisegment mixed
*/
bool closed = false;
case NR_MOVETO_OPEN:
closed = false;
break;
case NR_MOVETO:
closed = true;
break;
case NR_LINETO:
break;
case NR_CURVETO:
break;
case NR_END:
}
}
} else {
}
} else {
}
return c0;
}
/**
* Remove last segment of curve.
*/
void
{
{
}
}
}
}
/* Private methods */
/**
* True if all subpaths in bpath array pass consistency check.
*/
{
return false;
}
return true;
}
/**
* Return copy of a bpath array, discarding any inconsistencies.
*/
{
if (sp_bpath_check_subpath(bp)) {
} else {
bp++;
bp++;
}
}
return NULL;
}
np += 1;
return new_bpath;
}
/**
* Perform consistency check of bpath array.
* \return Address of NR_END node or NULL.
*/
{
bool closed;
closed = true;
closed = false;
} else {
return NULL;
}
gint i;
/** \todo
*/
for (i = 1; (bpath[i].code != NR_END) && (bpath[i].code != NR_MOVETO) && (bpath[i].code != NR_MOVETO_OPEN); i++) {
case NR_LINETO:
case NR_CURVETO:
len++;
break;
default:
return NULL;
}
}
if (closed) {
if (len < 1)
return NULL;
return NULL;
} else {
if (len < 1)
return NULL;
}
return bpath + i;
}
/**
* Returns index of first NR_END bpath in array.
*/
{
unsigned ret = 0;
++ret;
}
++ret;
return ret;
}
/**
* \brief
*
* \todo
* fixme: this is bogus -- it doesn't check for nr_moveto, which will indicate
* a closing of the subpath it's nonsense to talk about a path as a whole
* being closed, although maybe someone would want that for some other reason?
* Oh, also, if the bpath just ends, then it's *open*. I hope nobody is using
* this code for anything.
*/
{
return false;
}
}
return true;
}
/**
* Returns length of bezier segment.
*/
static double
double const threshold)
{
/** \todo
* The SVG spec claims that a closed form exists, but for the moment I'll
* use a stupid algorithm.
*/
double ret;
} else {
ret = bezier_len(c0, a1, a2, midpoint, rec_threshold) + bezier_len(midpoint, b1, b2, c3, rec_threshold);
g_warning("ret=%f outside of expected bounds [%f, %f] for {(%.0f %.0f) (%.0f %.0f) (%.0f %.0f) (%.0f %.0f)}",
}
}
return ret;
}
/**
* Returns total length of curve, excluding length of closepath segments.
*/
static double
{
double ret = 0.0;
return ret;
}
double seg_len = 0;
switch (p.code) {
case NR_MOVETO_OPEN:
case NR_MOVETO:
case NR_LINETO:
break;
case NR_CURVETO:
break;
case NR_END:
return ret;
}
prev = p.c(3);
}
return ret;
}
/**
* Like sp_curve_distance_including_space(), but ensures that the
* result >= 1e-18: uses 1 per segment if necessary.
*/
static double
{
if (real_dist >= 1e-18) {
return real_dist;
} else {
for (unsigned i = 0; i < nSegs; ++i) {
seg2len[i] = 1.;
}
return (double) nSegs;
}
}
void
{
if (sp_curve_empty(curve)) {
return;
}
double begin_dist = 0.;
switch (p.code) {
case NR_LINETO:
case NR_MOVETO:
case NR_MOVETO_OPEN:
break;
case NR_CURVETO:
}
break;
default:
}
}
/* Explicit set for better numerical properties. */
delete [] seg2len;
}
void
{
if (sp_curve_empty(curve)) {
return;
}
}
/*
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 :