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#include "agg_math.h"
17#include "agg_trans_double_path.h"
18
19namespace agg
20{
21
22    //------------------------------------------------------------------------
23    trans_double_path::trans_double_path() :
24        m_base_length(0.0),
25        m_base_height(1.0),
26        m_kindex1(0.0),
27        m_kindex2(0.0),
28        m_status1(initial),
29        m_status2(initial),
30        m_preserve_x_scale(true)
31    {
32    }
33
34
35        //------------------------------------------------------------------------
36    void trans_double_path::reset()
37    {
38        m_src_vertices1.remove_all();
39        m_src_vertices2.remove_all();
40        m_kindex1 = 0.0;
41        m_kindex2 = 0.0;
42        m_status1 = initial;
43        m_status2 = initial;
44    }
45
46
47    //------------------------------------------------------------------------
48    void trans_double_path::move_to1(double x, double y)
49    {
50        if(m_status1 == initial)
51        {
52            m_src_vertices1.modify_last(vertex_dist(x, y));
53            m_status1 = making_path;
54        }
55        else
56        {
57            line_to1(x, y);
58        }
59    }
60
61
62    //------------------------------------------------------------------------
63    void trans_double_path::line_to1(double x, double y)
64    {
65        if(m_status1 == making_path)
66        {
67            m_src_vertices1.add(vertex_dist(x, y));
68        }
69    }
70
71
72    //------------------------------------------------------------------------
73    void trans_double_path::move_to2(double x, double y)
74    {
75        if(m_status2 == initial)
76        {
77            m_src_vertices2.modify_last(vertex_dist(x, y));
78            m_status2 = making_path;
79        }
80        else
81        {
82            line_to2(x, y);
83        }
84    }
85
86
87    //------------------------------------------------------------------------
88    void trans_double_path::line_to2(double x, double y)
89    {
90        if(m_status2 == making_path)
91        {
92            m_src_vertices2.add(vertex_dist(x, y));
93        }
94    }
95
96
97    //------------------------------------------------------------------------
98    double trans_double_path::finalize_path(vertex_storage& vertices)
99    {
100        unsigned i;
101        double dist;
102        double d;
103
104        vertices.close(false);
105        if(vertices.size() > 2)
106        {
107            if(vertices[vertices.size() - 2].dist * 10.0 <
108               vertices[vertices.size() - 3].dist)
109            {
110                d = vertices[vertices.size() - 3].dist +
111                    vertices[vertices.size() - 2].dist;
112
113                vertices[vertices.size() - 2] =
114                    vertices[vertices.size() - 1];
115
116                vertices.remove_last();
117                vertices[vertices.size() - 2].dist = d;
118            }
119        }
120
121        dist = 0;
122        for(i = 0; i < vertices.size(); i++)
123        {
124            vertex_dist& v = vertices[i];
125            d = v.dist;
126            v.dist = dist;
127            dist += d;
128        }
129
130        return (vertices.size() - 1) / dist;
131    }
132
133
134    //------------------------------------------------------------------------
135    void trans_double_path::finalize_paths()
136    {
137        if(m_status1 == making_path && m_src_vertices1.size() > 1 &&
138           m_status2 == making_path && m_src_vertices2.size() > 1)
139        {
140            m_kindex1 = finalize_path(m_src_vertices1);
141            m_kindex2 = finalize_path(m_src_vertices2);
142            m_status1 = ready;
143            m_status2 = ready;
144        }
145    }
146
147
148    //------------------------------------------------------------------------
149    double trans_double_path::total_length1() const
150    {
151        if(m_base_length >= 1e-10) return m_base_length;
152        return (m_status1 == ready) ?
153            m_src_vertices1[m_src_vertices1.size() - 1].dist :
154            0.0;
155    }
156
157
158    //------------------------------------------------------------------------
159    double trans_double_path::total_length2() const
160    {
161        if(m_base_length >= 1e-10) return m_base_length;
162        return (m_status2 == ready) ?
163            m_src_vertices2[m_src_vertices2.size() - 1].dist :
164            0.0;
165    }
166
167
168    //------------------------------------------------------------------------
169    void trans_double_path::transform1(const vertex_storage& vertices,
170                                       double kindex, double kx,
171                                       double *x, double* y) const
172    {
173        double x1 = 0.0;
174        double y1 = 0.0;
175        double dx = 1.0;
176        double dy = 1.0;
177        double d  = 0.0;
178        double dd = 1.0;
179        *x *= kx;
180        if(*x < 0.0)
181        {
182            // Extrapolation on the left
183            //--------------------------
184            x1 = vertices[0].x;
185            y1 = vertices[0].y;
186            dx = vertices[1].x - x1;
187            dy = vertices[1].y - y1;
188            dd = vertices[1].dist - vertices[0].dist;
189            d  = *x;
190        }
191        else
192        if(*x > vertices[vertices.size() - 1].dist)
193        {
194            // Extrapolation on the right
195            //--------------------------
196            unsigned i = vertices.size() - 2;
197            unsigned j = vertices.size() - 1;
198            x1 = vertices[j].x;
199            y1 = vertices[j].y;
200            dx = x1 - vertices[i].x;
201            dy = y1 - vertices[i].y;
202            dd = vertices[j].dist - vertices[i].dist;
203            d  = *x - vertices[j].dist;
204        }
205        else
206        {
207            // Interpolation
208            //--------------------------
209            unsigned i = 0;
210            unsigned j = vertices.size() - 1;
211            if(m_preserve_x_scale)
212            {
213                unsigned k;
214                for(i = 0; (j - i) > 1; )
215                {
216                    if(*x < vertices[k = (i + j) >> 1].dist)
217                    {
218                        j = k;
219                    }
220                    else
221                    {
222                        i = k;
223                    }
224                }
225                d  = vertices[i].dist;
226                dd = vertices[j].dist - d;
227                d  = *x - d;
228            }
229            else
230            {
231                i = unsigned(*x * kindex);
232                j = i + 1;
233                dd = vertices[j].dist - vertices[i].dist;
234                d = ((*x * kindex) - i) * dd;
235            }
236            x1 = vertices[i].x;
237            y1 = vertices[i].y;
238            dx = vertices[j].x - x1;
239            dy = vertices[j].y - y1;
240        }
241        *x = x1 + dx * d / dd;
242        *y = y1 + dy * d / dd;
243    }
244
245
246    //------------------------------------------------------------------------
247    void trans_double_path::transform(double *x, double *y) const
248    {
249        if(m_status1 == ready && m_status2 == ready)
250        {
251            if(m_base_length > 1e-10)
252            {
253                *x *= m_src_vertices1[m_src_vertices1.size() - 1].dist /
254                      m_base_length;
255            }
256
257            double x1 = *x;
258            double y1 = *y;
259            double x2 = *x;
260            double y2 = *y;
261            double dd = m_src_vertices2[m_src_vertices2.size() - 1].dist /
262                        m_src_vertices1[m_src_vertices1.size() - 1].dist;
263
264            transform1(m_src_vertices1, m_kindex1, 1.0, &x1, &y1);
265            transform1(m_src_vertices2, m_kindex2, dd,  &x2, &y2);
266
267            *x = x1 + *y * (x2 - x1) / m_base_height;
268            *y = y1 + *y * (y2 - y1) / m_base_height;
269        }
270    }
271
272}
273
274