diff options
Diffstat (limited to '')
| -rw-r--r-- | src/2geom/elliptical-arc-from-sbasis.cpp (renamed from src/2geom/svg-elliptical-arc.cpp) | 172 |
1 files changed, 121 insertions, 51 deletions
diff --git a/src/2geom/svg-elliptical-arc.cpp b/src/2geom/elliptical-arc-from-sbasis.cpp index 3a5154d08..54f995fb6 100644 --- a/src/2geom/svg-elliptical-arc.cpp +++ b/src/2geom/elliptical-arc-from-sbasis.cpp @@ -1,6 +1,8 @@ -/* - * SVG Elliptical Arc Class +/** @file + * @brief Fitting elliptical arc to SBasis * + * This file contains the implementation of the function arc_from_sbasis. + *//* * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com> * * This library is free software; you can redistribute it and/or @@ -27,33 +29,120 @@ * the specific language governing rights and limitations. */ - +#include <2geom/curve.h> +#include <2geom/angle.h> +#include <2geom/utils.h> #include <2geom/bezier-curve.h> -#include <2geom/ellipse.h> -#include <2geom/numeric/fitting-model.h> -#include <2geom/numeric/fitting-tool.h> +#include <2geom/elliptical-arc.h> +#include <2geom/sbasis-curve.h> // for non-native methods #include <2geom/numeric/vector.h> -#include <2geom/poly.h> -#include <2geom/sbasis-geometric.h> -#include <2geom/svg-elliptical-arc.h> - -#include <cfloat> -#include <limits> -#include <memory> +#include <2geom/numeric/fitting-tool.h> +#include <2geom/numeric/fitting-model.h> +#include <algorithm> +namespace Geom { -namespace Geom +// forward declation +namespace detail { + struct ellipse_equation; +} -/** - * @class SVGEllipticalArc - * @brief SVG 1.1-compliant elliptical arc. +/* + * make_elliptical_arc * - * This class is almost identical to the normal elliptical arc, but it differs slightly - * in the handling of degenerate arcs to be compliant with SVG 1.1 implementation guidelines. + * convert a parametric polynomial curve given in symmetric power basis form + * into an EllipticalArc type; in order to be successfull the input curve + * has to look like an actual elliptical arc even if a certain tolerance + * is allowed through an ad-hoc parameter. + * The conversion is performed through an interpolation on a certain amount of + * sample points computed on the input curve; + * the interpolation computes the coefficients of the general implicit equation + * of an ellipse (A*X^2 + B*XY + C*Y^2 + D*X + E*Y + F = 0), then from the + * implicit equation we compute the parametric form. * - * @ingroup Curves */ +class make_elliptical_arc +{ + public: + typedef D2<SBasis> curve_type; + + /* + * constructor + * + * it doesn't execute the conversion but set the input and output parameters + * + * _ea: the output EllipticalArc that will be generated; + * _curve: the input curve to be converted; + * _total_samples: the amount of sample points to be taken + * on the input curve for performing the conversion + * _tolerance: how much likelihood is required between the input curve + * and the generated elliptical arc; the smaller it is the + * the tolerance the higher it is the likelihood. + */ + make_elliptical_arc( EllipticalArc& _ea, + curve_type const& _curve, + unsigned int _total_samples, + double _tolerance ); + + private: + bool bound_exceeded( unsigned int k, detail::ellipse_equation const & ee, + double e1x, double e1y, double e2 ); + + bool check_bound(double A, double B, double C, double D, double E, double F); + + void fit(); + + bool make_elliptiarc(); + + void print_bound_error(unsigned int k) + { + std::cerr + << "tolerance error" << std::endl + << "at point: " << k << std::endl + << "error value: "<< dist_err << std::endl + << "bound: " << dist_bound << std::endl + << "angle error: " << angle_err + << " (" << angle_tol << ")" << std::endl; + } + + public: + /* + * perform the actual conversion + * return true if the conversion is successfull, false on the contrary + */ + bool operator()() + { + // initialize the reference + const NL::Vector & coeff = fitter.result(); + fit(); + if ( !check_bound(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]) ) + return false; + if ( !(make_elliptiarc()) ) return false; + return true; + } + + private: + EllipticalArc& ea; // output elliptical arc + const curve_type & curve; // input curve + Piecewise<D2<SBasis> > dcurve; // derivative of the input curve + NL::LFMEllipse model; // model used for fitting + // perform the actual fitting task + NL::least_squeares_fitter<NL::LFMEllipse> fitter; + // tolerance: the user-defined tolerance parameter; + // tol_at_extr: the tolerance at end-points automatically computed + // on the value of "tolerance", and usually more strict; + // tol_at_center: tolerance at the center of the ellipse + // angle_tol: tolerance for the angle btw the input curve tangent + // versor and the ellipse normal versor at the sample points + double tolerance, tol_at_extr, tol_at_center, angle_tol; + Point initial_point, final_point; // initial and final end-points + unsigned int N; // total samples + unsigned int last; // N-1 + double partitions; // N-1 + std::vector<Point> p; // sample points + double dist_err, dist_bound, angle_err; +}; namespace detail { @@ -97,7 +186,7 @@ struct ellipse_equation double A, B, C, D, E, F; }; -} +} // end namespace detail make_elliptical_arc:: make_elliptical_arc( EllipticalArc& _ea, @@ -110,8 +199,7 @@ make_elliptical_arc( EllipticalArc& _ea, tolerance(_tolerance), tol_at_extr(tolerance/2), tol_at_center(0.1), angle_tol(0.1), initial_point(curve.at0()), final_point(curve.at1()), - N(_total_samples), last(N-1), partitions(N-1), p(N), - svg_compliant(true) + N(_total_samples), last(N-1), partitions(N-1), p(N) { } @@ -216,33 +304,12 @@ bool make_elliptical_arc::make_elliptiarc() Point inner_point = curve(0.5); - if (svg_compliant_flag()) - { -#ifdef CPP11 - std::unique_ptr<EllipticalArc> arc( e.arc(initial_point, inner_point, final_point, true) ); -#else - std::auto_ptr<EllipticalArc> arc( e.arc(initial_point, inner_point, final_point, true) ); -#endif - ea = *arc; - } - else - { - try - { #ifdef CPP11 - std::unique_ptr<EllipticalArc> + std::unique_ptr<EllipticalArc> arc( e.arc(initial_point, inner_point, final_point) ); #else - std::auto_ptr<EllipticalArc> + std::auto_ptr<EllipticalArc> arc( e.arc(initial_point, inner_point, final_point) ); #endif - eap( e.arc(initial_point, inner_point, final_point, false) ); - ea = *eap; - } - catch(RangeError const &exc) - { - return false; - } - } - + ea = *arc; if ( !are_near( e.center(), ea.center(), @@ -257,10 +324,14 @@ bool make_elliptical_arc::make_elliptiarc() -} // end namespace Geom - - +bool arc_from_sbasis(EllipticalArc &ea, D2<SBasis> const &in, + double tolerance, unsigned num_samples) +{ + make_elliptical_arc convert(ea, in, num_samples, tolerance); + return convert(); +} +} // end namespace Geom /* Local Variables: @@ -272,4 +343,3 @@ bool make_elliptical_arc::make_elliptiarc() End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : - |
