update dev300-m58
[ooovba.git] / agg / inc / agg_span_gradient.h
blobada67795148766896986f999304059fde55c5f55
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
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 //----------------------------------------------------------------------------
16 #ifndef AGG_SPAN_GRADIENT_INCLUDED
17 #define AGG_SPAN_GRADIENT_INCLUDED
19 #include <math.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "agg_basics.h"
23 #include "agg_span_generator.h"
24 #include "agg_math.h"
25 #include "agg_array.h"
28 namespace agg
31 enum
33 gradient_subpixel_shift = 4, //-----gradient_subpixel_shift
34 gradient_subpixel_size = 1 << gradient_subpixel_shift, //-----gradient_subpixel_size
35 gradient_subpixel_mask = gradient_subpixel_size - 1 //-----gradient_subpixel_mask
40 //==========================================================span_gradient
41 template<class ColorT,
42 class Interpolator,
43 class GradientF,
44 class ColorF,
45 class Allocator = span_allocator<ColorT> >
46 class span_gradient : public span_generator<ColorT, Allocator>
48 public:
49 typedef Interpolator interpolator_type;
50 typedef Allocator alloc_type;
51 typedef ColorT color_type;
52 typedef span_generator<color_type, alloc_type> base_type;
54 enum
56 downscale_shift = interpolator_type::subpixel_shift -
57 gradient_subpixel_shift
60 //--------------------------------------------------------------------
61 span_gradient(alloc_type& alloc) : base_type(alloc) {}
63 //--------------------------------------------------------------------
64 span_gradient(alloc_type& alloc,
65 interpolator_type& inter,
66 const GradientF& gradient_function_,
67 const ColorF& color_function_,
68 double d1_, double d2_) :
69 base_type(alloc),
70 m_interpolator(&inter),
71 m_gradient_function(&gradient_function_),
72 m_color_function(&color_function_),
73 m_d1(int(d1_ * gradient_subpixel_size)),
74 m_d2(int(d2_ * gradient_subpixel_size))
77 //--------------------------------------------------------------------
78 interpolator_type& interpolator() { return *m_interpolator; }
79 const GradientF& gradient_function() const { return *m_gradient_function; }
80 const ColorF& color_function() const { return *m_color_function; }
81 double d1() const { return double(m_d1) / gradient_subpixel_size; }
82 double d2() const { return double(m_d2) / gradient_subpixel_size; }
84 //--------------------------------------------------------------------
85 void interpolator(interpolator_type& i) { m_interpolator = &i; }
86 void gradient_function(const GradientF& gf) { m_gradient_function = &gf; }
87 void color_function(const ColorF& cf) { m_color_function = &cf; }
88 void d1(double v) { m_d1 = int(v * gradient_subpixel_size); }
89 void d2(double v) { m_d2 = int(v * gradient_subpixel_size); }
91 //--------------------------------------------------------------------
92 color_type* generate(int x, int y, unsigned len)
94 color_type* span = base_type::allocator().span();
95 int dd = m_d2 - m_d1;
96 if(dd < 1) dd = 1;
97 m_interpolator->begin(x+0.5, y+0.5, len);
100 m_interpolator->coordinates(&x, &y);
101 int d = m_gradient_function->calculate(x >> downscale_shift,
102 y >> downscale_shift, dd);
103 d = ((d - m_d1) * (int)m_color_function->size()) / dd;
104 if(d < 0) d = 0;
105 if(d >= (int)m_color_function->size()) d = m_color_function->size() - 1;
106 *span++ = (*m_color_function)[d];
107 ++(*m_interpolator);
109 while(--len);
110 return base_type::allocator().span();
113 private:
114 interpolator_type* m_interpolator;
115 const GradientF* m_gradient_function;
116 const ColorF* m_color_function;
117 int m_d1;
118 int m_d2;
124 //=====================================================gradient_linear_color
125 template<class ColorT>
126 struct gradient_linear_color
128 typedef ColorT color_type;
130 gradient_linear_color() {}
131 gradient_linear_color(const color_type& c1, const color_type& c2,
132 unsigned size = 256) :
133 m_c1(c1), m_c2(c2), m_size(size) {}
135 unsigned size() const { return m_size; }
136 color_type operator [] (unsigned v) const
138 return m_c1.gradient(m_c2, double(v) / double(m_size - 1));
141 void colors(const color_type& c1, const color_type& c2, unsigned size = 256)
143 m_c1 = c1;
144 m_c2 = c2;
145 m_size = size;
148 color_type m_c1;
149 color_type m_c2;
150 unsigned m_size;
154 //==========================================================gradient_circle
155 class gradient_circle
157 // Actually the same as radial. Just for compatibility
158 public:
159 static AGG_INLINE int calculate(int x, int y, int)
161 return int(fast_sqrt(x*x + y*y));
166 //==========================================================gradient_radial
167 class gradient_radial
169 public:
170 static AGG_INLINE int calculate(int x, int y, int)
172 return int(fast_sqrt(x*x + y*y));
177 //========================================================gradient_radial_d
178 class gradient_radial_d
180 public:
181 static AGG_INLINE int calculate(int x, int y, int)
183 return int(sqrt(double(x)*double(x) + double(y)*double(y)));
188 //====================================================gradient_radial_focus
189 class gradient_radial_focus
191 public:
192 //---------------------------------------------------------------------
193 gradient_radial_focus() :
194 m_radius(100 * gradient_subpixel_size),
195 m_focus_x(0),
196 m_focus_y(0)
198 update_values();
201 //---------------------------------------------------------------------
202 gradient_radial_focus(double r, double fx, double fy) :
203 m_radius (int(r * gradient_subpixel_size)),
204 m_focus_x(int(fx * gradient_subpixel_size)),
205 m_focus_y(int(fy * gradient_subpixel_size))
207 update_values();
210 //---------------------------------------------------------------------
211 void init(double r, double fx, double fy)
213 m_radius = int(r * gradient_subpixel_size);
214 m_focus_x = int(fx * gradient_subpixel_size);
215 m_focus_y = int(fy * gradient_subpixel_size);
216 update_values();
219 //---------------------------------------------------------------------
220 double radius() const { return double(m_radius) / gradient_subpixel_size; }
221 double focus_x() const { return double(m_focus_x) / gradient_subpixel_size; }
222 double focus_y() const { return double(m_focus_y) / gradient_subpixel_size; }
224 //---------------------------------------------------------------------
225 int calculate(int x, int y, int d) const
227 double solution_x;
228 double solution_y;
230 // Special case to avoid divide by zero or very near zero
231 //---------------------------------
232 if(x == int(m_focus_x))
234 solution_x = m_focus_x;
235 solution_y = 0.0;
236 solution_y += (y > m_focus_y) ? m_trivial : -m_trivial;
238 else
240 // Slope of the focus-current line
241 //-------------------------------
242 double slope = double(y - m_focus_y) / double(x - m_focus_x);
244 // y-intercept of that same line
245 //--------------------------------
246 double yint = double(y) - (slope * x);
248 // Use the classical quadratic formula to calculate
249 // the intersection point
250 //--------------------------------
251 double a = (slope * slope) + 1;
252 double b = 2 * slope * yint;
253 double c = yint * yint - m_radius2;
254 double det = sqrt((b * b) - (4.0 * a * c));
255 solution_x = -b;
257 // Choose the positive or negative root depending
258 // on where the X coord lies with respect to the focus.
259 solution_x += (x < m_focus_x) ? -det : det;
260 solution_x /= 2.0 * a;
262 // Calculating of Y is trivial
263 solution_y = (slope * solution_x) + yint;
266 // Calculate the percentage (0...1) of the current point along the
267 // focus-circumference line and return the normalized (0...d) value
268 //-------------------------------
269 solution_x -= double(m_focus_x);
270 solution_y -= double(m_focus_y);
271 double int_to_focus = solution_x * solution_x + solution_y * solution_y;
272 double cur_to_focus = double(x - m_focus_x) * double(x - m_focus_x) +
273 double(y - m_focus_y) * double(y - m_focus_y);
275 return int(sqrt(cur_to_focus / int_to_focus) * d);
278 private:
279 //---------------------------------------------------------------------
280 void update_values()
282 // For use in the quadractic equation
283 //-------------------------------
284 m_radius2 = double(m_radius) * double(m_radius);
286 double dist = sqrt(double(m_focus_x) * double(m_focus_x) +
287 double(m_focus_y) * double(m_focus_y));
289 // Test if distance from focus to center is greater than the radius
290 // For the sake of assurance factor restrict the point to be
291 // no further than 99% of the radius.
292 //-------------------------------
293 double r = m_radius * 0.99;
294 if(dist > r)
296 // clamp focus to radius
297 // x = r cos theta, y = r sin theta
298 //------------------------
299 double a = atan2(double(m_focus_y), double(m_focus_x));
300 m_focus_x = int(r * cos(a));
301 m_focus_y = int(r * sin(a));
304 // Calculate the solution to be used in the case where x == focus_x
305 //------------------------------
306 m_trivial = sqrt(m_radius2 - (m_focus_x * m_focus_x));
309 int m_radius;
310 int m_focus_x;
311 int m_focus_y;
312 double m_radius2;
313 double m_trivial;
318 //==============================================================gradient_x
319 class gradient_x
321 public:
322 static int calculate(int x, int, int) { return x; }
326 //==============================================================gradient_y
327 class gradient_y
329 public:
330 static int calculate(int, int y, int) { return y; }
334 //========================================================gradient_diamond
335 class gradient_diamond
337 public:
338 static AGG_INLINE int calculate(int x, int y, int)
340 int ax = abs(x);
341 int ay = abs(y);
342 return ax > ay ? ax : ay;
347 //=============================================================gradient_xy
348 class gradient_xy
350 public:
351 static AGG_INLINE int calculate(int x, int y, int d)
353 return abs(x) * abs(y) / d;
358 //========================================================gradient_sqrt_xy
359 class gradient_sqrt_xy
361 public:
362 static AGG_INLINE int calculate(int x, int y, int)
364 return fast_sqrt(abs(x) * abs(y));
369 //==========================================================gradient_conic
370 class gradient_conic
372 public:
373 static AGG_INLINE int calculate(int x, int y, int d)
375 return int(fabs(atan2(double(y), double(x))) * double(d) / pi);
380 //=================================================gradient_repeat_adaptor
381 template<class GradientF> class gradient_repeat_adaptor
383 public:
384 gradient_repeat_adaptor(const GradientF& gradient) :
385 m_gradient(&gradient) {}
387 AGG_INLINE int calculate(int x, int y, int d) const
389 int ret = m_gradient->calculate(x, y, d) % d;
390 if(ret < 0) ret += d;
391 return ret;
394 private:
395 const GradientF* m_gradient;
399 //================================================gradient_reflect_adaptor
400 template<class GradientF> class gradient_reflect_adaptor
402 public:
403 gradient_reflect_adaptor(const GradientF& gradient) :
404 m_gradient(&gradient) {}
406 AGG_INLINE int calculate(int x, int y, int d) const
408 int d2 = d << 1;
409 int ret = m_gradient->calculate(x, y, d) % d2;
410 if(ret < 0) ret += d2;
411 if(ret >= d) ret = d2 - ret;
412 return ret;
415 private:
416 const GradientF* m_gradient;
422 #endif