agg_conv_curve.h 6.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
//----------------------------------------------------------------------------
// Anti-Grain Geometry (AGG) - Version 2.5
// A high quality rendering engine for C++
// Copyright (C) 2002-2006 Maxim Shemanarev
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://antigrain.com
// 
// AGG is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// AGG is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with AGG; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
// MA 02110-1301, USA.
//----------------------------------------------------------------------------

#ifndef AGG_CONV_CURVE_INCLUDED
#define AGG_CONV_CURVE_INCLUDED

#include "agg_basics.h"
#include "agg_curves.h"

namespace agg
{


    //---------------------------------------------------------------conv_curve
    // Curve converter class. Any path storage can have Bezier curves defined 
    // by their control points. There're two types of curves supported: curve3 
    // and curve4. Curve3 is a conic Bezier curve with 2 endpoints and 1 control
    // point. Curve4 has 2 control points (4 points in total) and can be used
    // to interpolate more complicated curves. Curve4, unlike curve3 can be used 
    // to approximate arcs, both circular and elliptical. Curves are approximated 
    // with straight lines and one of the approaches is just to store the whole 
    // sequence of vertices that approximate our curve. It takes additional 
    // memory, and at the same time the consecutive vertices can be calculated 
    // on demand. 
    //
    // Initially, path storages are not suppose to keep all the vertices of the
    // curves (although, nothing prevents us from doing so). Instead, path_storage
    // keeps only vertices, needed to calculate a curve on demand. Those vertices
    // are marked with special commands. So, if the path_storage contains curves 
    // (which are not real curves yet), and we render this storage directly, 
    // all we will see is only 2 or 3 straight line segments (for curve3 and 
    // curve4 respectively). If we need to see real curves drawn we need to 
    // include this class into the conversion pipeline. 
    //
    // Class conv_curve recognizes commands path_cmd_curve3 and path_cmd_curve4 
    // and converts these vertices into a move_to/line_to sequence. 
    //-----------------------------------------------------------------------
    template<class VertexSource, 
             class Curve3=curve3, 
             class Curve4=curve4> class conv_curve
    {
    public:
        typedef Curve3 curve3_type;
        typedef Curve4 curve4_type;
        typedef conv_curve<VertexSource, Curve3, Curve4> self_type;

        explicit conv_curve(VertexSource& source) :
          m_source(&source), m_last_x(0.0), m_last_y(0.0) {}
        void attach(VertexSource& source) { m_source = &source; }

        void approximation_method(curve_approximation_method_e v) 
        { 
            m_curve3.approximation_method(v);
            m_curve4.approximation_method(v);
        }

        curve_approximation_method_e approximation_method() const 
        { 
            return m_curve4.approximation_method();
        }

        void approximation_scale(double s) 
        { 
            m_curve3.approximation_scale(s); 
            m_curve4.approximation_scale(s); 
        }

        double approximation_scale() const 
        { 
            return m_curve4.approximation_scale();  
        }

        void angle_tolerance(double v) 
        { 
            m_curve3.angle_tolerance(v); 
            m_curve4.angle_tolerance(v); 
        }

        double angle_tolerance() const 
        { 
            return m_curve4.angle_tolerance();  
        }

        void cusp_limit(double v) 
        { 
            m_curve3.cusp_limit(v); 
            m_curve4.cusp_limit(v); 
        }

        double cusp_limit() const 
        { 
            return m_curve4.cusp_limit();  
        }

        void     rewind(unsigned path_id); 
        unsigned vertex(double* x, double* y);

    private:
        conv_curve(const self_type&);
        const self_type& operator = (const self_type&);

        VertexSource* m_source;
        double        m_last_x;
        double        m_last_y;
        curve3_type   m_curve3;
        curve4_type   m_curve4;
    };



    //------------------------------------------------------------------------
    template<class VertexSource, class Curve3, class Curve4>
    void conv_curve<VertexSource, Curve3, Curve4>::rewind(unsigned path_id)
    {
        m_source->rewind(path_id);
        m_last_x = 0.0;
        m_last_y = 0.0;
        m_curve3.reset();
        m_curve4.reset();
    }


    //------------------------------------------------------------------------
    template<class VertexSource, class Curve3, class Curve4>
    unsigned conv_curve<VertexSource, Curve3, Curve4>::vertex(double* x, double* y)
    {
        if(!is_stop(m_curve3.vertex(x, y)))
        {
            m_last_x = *x;
            m_last_y = *y;
            return path_cmd_line_to;
        }

        if(!is_stop(m_curve4.vertex(x, y)))
        {
            m_last_x = *x;
            m_last_y = *y;
            return path_cmd_line_to;
        }

        double ct2_x;
        double ct2_y;
        double end_x;
        double end_y;

        unsigned cmd = m_source->vertex(x, y);
        switch(cmd)
        {
        case path_cmd_curve3:
            m_source->vertex(&end_x, &end_y);

            m_curve3.init(m_last_x, m_last_y, 
                          *x,       *y, 
                          end_x,     end_y);

            m_curve3.vertex(x, y);    // First call returns path_cmd_move_to
            m_curve3.vertex(x, y);    // This is the first vertex of the curve
            cmd = path_cmd_line_to;
            break;

        case path_cmd_curve4:
            m_source->vertex(&ct2_x, &ct2_y);
            m_source->vertex(&end_x, &end_y);

            m_curve4.init(m_last_x, m_last_y, 
                          *x,       *y, 
                          ct2_x,    ct2_y, 
                          end_x,    end_y);

            m_curve4.vertex(x, y);    // First call returns path_cmd_move_to
            m_curve4.vertex(x, y);    // This is the first vertex of the curve
            cmd = path_cmd_line_to;
            break;
        }
        m_last_x = *x;
        m_last_y = *y;
        return cmd;
    }


}



#endif