1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
18 //----------------------------------------------------------------------------
21 #include "agg_bspline.h"
26 //------------------------------------------------------------------------
33 //------------------------------------------------------------------------
44 //------------------------------------------------------------------------
45 bspline::bspline(int num
) :
56 //------------------------------------------------------------------------
57 bspline::bspline(int num
, const double* x
, const double* y
) :
69 //------------------------------------------------------------------------
70 void bspline::init(int max
)
72 if(max
> 2 && max
> m_max
)
75 m_am
= new double[max
* 3];
78 m_y
= m_am
+ m_max
* 2;
85 //------------------------------------------------------------------------
86 void bspline::add_point(double x
, double y
)
97 //------------------------------------------------------------------------
98 void bspline::prepare()
107 double h
, p
, d
, f
, e
;
109 for(k
= 0; k
< m_num
; k
++)
119 for(k
= 0; k
< n1
; k
++)
125 s
= temp
+ m_num
* 2;
129 e
= (m_y
[1] - m_y
[0]) / d
;
131 for(k
= 1; k
< n1
; k
++)
134 d
= m_x
[k
+ 1] - m_x
[k
];
136 e
= (m_y
[k
+ 1] - m_y
[k
]) / d
;
139 s
[k
] = 6.0 * (e
- f
) / (h
+ d
);
142 for(k
= 1; k
< n1
; k
++)
144 p
= 1.0 / (r
[k
] * al
[k
- 1] + 2.0);
146 s
[k
] = (s
[k
] - r
[k
] * s
[k
- 1]) * p
;
150 al
[n1
- 1] = s
[n1
- 1];
151 m_am
[n1
- 1] = al
[n1
- 1];
153 for(k
= n1
- 2, i
= 0; i
< m_num
- 2; i
++, k
--)
155 al
[k
] = al
[k
] * al
[k
+ 1] + s
[k
];
165 //------------------------------------------------------------------------
166 void bspline::init(int num
, const double* x
, const double* y
)
172 for(i
= 0; i
< num
; i
++)
174 add_point(*x
++, *y
++);
182 //------------------------------------------------------------------------
183 void bspline::bsearch(int n
, const double *x
, double x0
, int *i
)
188 for(*i
= 0; (j
- *i
) > 1; )
190 if(x0
< x
[k
= (*i
+ j
) >> 1]) j
= k
;
197 //------------------------------------------------------------------------
198 double bspline::interpolation(double x
, int i
) const
201 double d
= m_x
[i
] - m_x
[j
];
202 double h
= x
- m_x
[j
];
203 double r
= m_x
[i
] - x
;
204 double p
= d
* d
/ 6.0;
205 return (m_am
[j
] * r
* r
* r
+ m_am
[i
] * h
* h
* h
) / 6.0 / d
+
206 ((m_y
[j
] - m_am
[j
] * p
) * r
+ (m_y
[i
] - m_am
[i
] * p
) * h
) / d
;
210 //------------------------------------------------------------------------
211 double bspline::extrapolation_left(double x
) const
213 double d
= m_x
[1] - m_x
[0];
214 return (-d
* m_am
[1] / 6 + (m_y
[1] - m_y
[0]) / d
) *
219 //------------------------------------------------------------------------
220 double bspline::extrapolation_right(double x
) const
222 double d
= m_x
[m_num
- 1] - m_x
[m_num
- 2];
223 return (d
* m_am
[m_num
- 2] / 6 + (m_y
[m_num
- 1] - m_y
[m_num
- 2]) / d
) *
224 (x
- m_x
[m_num
- 1]) +
228 //------------------------------------------------------------------------
229 double bspline::get(double x
) const
235 // Extrapolation on the left
236 if(x
< m_x
[0]) return extrapolation_left(x
);
238 // Extrapolation on the right
239 if(x
>= m_x
[m_num
- 1]) return extrapolation_right(x
);
242 bsearch(m_num
, m_x
, x
, &i
);
243 return interpolation(x
, i
);
249 //------------------------------------------------------------------------
250 double bspline::get_stateful(double x
) const
254 // Extrapolation on the left
255 if(x
< m_x
[0]) return extrapolation_left(x
);
257 // Extrapolation on the right
258 if(x
>= m_x
[m_num
- 1]) return extrapolation_right(x
);
262 // Check if x is not in current range
263 if(x
< m_x
[m_last_idx
] || x
> m_x
[m_last_idx
+ 1])
265 // Check if x between next points (most probably)
266 if(m_last_idx
< m_num
- 2 &&
267 x
>= m_x
[m_last_idx
+ 1] &&
268 x
<= m_x
[m_last_idx
+ 2])
274 x
>= m_x
[m_last_idx
- 1] &&
275 x
<= m_x
[m_last_idx
])
277 // x is between pevious points
282 // Else perform full search
283 bsearch(m_num
, m_x
, x
, &m_last_idx
);
286 return interpolation(x
, m_last_idx
);
291 bsearch(m_num
, m_x
, x
, &m_last_idx
);
292 return interpolation(x
, m_last_idx
);