1//----------------------------------------------------------------------------
2// Anti-Grain Geometry - Version 2.4
3// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4//
5// Permission to copy, use, modify, sell and distribute this software
6// is granted provided this copyright notice appears in all copies.
7// This software is provided "as is" without express or implied
8// warranty, and with no claim as to its suitability for any purpose.
9//
10//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15//
16// vertex_sequence container and vertex_dist struct
17//
18//----------------------------------------------------------------------------
19#ifndef AGG_VERTEX_SEQUENCE_INCLUDED
20#define AGG_VERTEX_SEQUENCE_INCLUDED
21
22#include "agg_basics.h"
23#include "agg_array.h"
24#include "agg_math.h"
25
26namespace agg
27{
28
29    //----------------------------------------------------------vertex_sequence
30    // Modified agg::pod_bvector. The data is interpreted as a sequence
31    // of vertices. It means that the type T must expose:
32    //
33    // bool T::operator() (const T& val)
34    //
35    // that is called every time new vertex is being added. The main purpose
36    // of this operator is the possibility to calculate some values during
37    // adding and to return true if the vertex fits some criteria or false if
38    // it doesn't. In the last case the new vertex is not added.
39    //
40    // The simple example is filtering coinciding vertices with calculation
41    // of the distance between the current and previous ones:
42    //
43    //    struct vertex_dist
44    //    {
45    //        double   x;
46    //        double   y;
47    //        double   dist;
48    //
49    //        vertex_dist() {}
50    //        vertex_dist(double x_, double y_) :
51    //            x(x_),
52    //            y(y_),
53    //            dist(0.0)
54    //        {
55    //        }
56    //
57    //        bool operator () (const vertex_dist& val)
58    //        {
59    //            return (dist = calc_distance(x, y, val.x, val.y)) > EPSILON;
60    //        }
61    //    };
62    //
63    // Function close() calls this operator and removes the last vertex if
64    // necessary.
65    //------------------------------------------------------------------------
66    template<class T, unsigned S=6>
67    class vertex_sequence : public pod_bvector<T, S>
68    {
69    public:
70        typedef pod_bvector<T, S> base_type;
71
72        void add(const T& val);
73        void modify_last(const T& val);
74        void close(bool remove_flag);
75    };
76
77
78
79    //------------------------------------------------------------------------
80    template<class T, unsigned S>
81    void vertex_sequence<T, S>::add(const T& val)
82    {
83        if(base_type::size() > 1)
84        {
85            if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1]))
86            {
87                base_type::remove_last();
88            }
89        }
90        base_type::add(val);
91    }
92
93
94    //------------------------------------------------------------------------
95    template<class T, unsigned S>
96    void vertex_sequence<T, S>::modify_last(const T& val)
97    {
98        base_type::remove_last();
99        add(val);
100    }
101
102
103
104    //------------------------------------------------------------------------
105    template<class T, unsigned S>
106    void vertex_sequence<T, S>::close(bool closed)
107    {
108        while(base_type::size() > 1)
109        {
110            if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) break;
111            T t = (*this)[base_type::size() - 1];
112            base_type::remove_last();
113            modify_last(t);
114        }
115
116        if(closed)
117        {
118            while(base_type::size() > 1)
119            {
120                if((*this)[base_type::size() - 1]((*this)[0])) break;
121                base_type::remove_last();
122            }
123        }
124    }
125
126
127    //-------------------------------------------------------------vertex_dist
128    // Vertex (x, y) with the distance to the next one. The last vertex has
129    // distance between the last and the first points if the polygon is closed
130    // and 0.0 if it's a polyline.
131    struct vertex_dist
132    {
133        double   x;
134        double   y;
135        double   dist;
136
137        vertex_dist() {}
138        vertex_dist(double x_, double y_) :
139            x(x_),
140            y(y_),
141            dist(0.0)
142        {
143        }
144
145        bool operator () (const vertex_dist& val)
146        {
147            bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon;
148            if(!ret) dist = 1.0 / vertex_dist_epsilon;
149            return ret;
150        }
151    };
152
153
154
155    //--------------------------------------------------------vertex_dist_cmd
156    // Save as the above but with additional "command" value
157    struct vertex_dist_cmd : public vertex_dist
158    {
159        unsigned cmd;
160
161        vertex_dist_cmd() {}
162        vertex_dist_cmd(double x_, double y_, unsigned cmd_) :
163            vertex_dist(x_, y_),
164            cmd(cmd_)
165        {
166        }
167    };
168
169
170}
171
172#endif
173