1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
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 //----------------------------------------------------------------------------
16 #ifndef AGG_SPAN_GRADIENT_INCLUDED
17 #define AGG_SPAN_GRADIENT_INCLUDED
22 #include "agg_basics.h"
24 #include "agg_array.h"
30 enum gradient_subpixel_scale_e
32 gradient_subpixel_shift
= 4, //-----gradient_subpixel_shift
33 gradient_subpixel_scale
= 1 << gradient_subpixel_shift
, //-----gradient_subpixel_scale
34 gradient_subpixel_mask
= gradient_subpixel_scale
- 1 //-----gradient_subpixel_mask
39 //==========================================================span_gradient
40 template<class ColorT
,
47 typedef Interpolator interpolator_type
;
48 typedef ColorT color_type
;
50 enum downscale_shift_e
52 downscale_shift
= interpolator_type::subpixel_shift
-
53 gradient_subpixel_shift
56 //--------------------------------------------------------------------
59 //--------------------------------------------------------------------
60 span_gradient(interpolator_type
& inter
,
61 const GradientF
& gradient_function
,
62 const ColorF
& color_function
,
63 double d1
, double d2
) :
64 m_interpolator(&inter
),
65 m_gradient_function(&gradient_function
),
66 m_color_function(&color_function
),
67 m_d1(iround(d1
* gradient_subpixel_scale
)),
68 m_d2(iround(d2
* gradient_subpixel_scale
))
71 //--------------------------------------------------------------------
72 interpolator_type
& interpolator() { return *m_interpolator
; }
73 const GradientF
& gradient_function() const { return *m_gradient_function
; }
74 const ColorF
& color_function() const { return *m_color_function
; }
75 double d1() const { return double(m_d1
) / gradient_subpixel_scale
; }
76 double d2() const { return double(m_d2
) / gradient_subpixel_scale
; }
78 //--------------------------------------------------------------------
79 void interpolator(interpolator_type
& i
) { m_interpolator
= &i
; }
80 void gradient_function(const GradientF
& gf
) { m_gradient_function
= &gf
; }
81 void color_function(const ColorF
& cf
) { m_color_function
= &cf
; }
82 void d1(double v
) { m_d1
= iround(v
* gradient_subpixel_scale
); }
83 void d2(double v
) { m_d2
= iround(v
* gradient_subpixel_scale
); }
85 //--------------------------------------------------------------------
88 //--------------------------------------------------------------------
89 void generate(color_type
* span
, int x
, int y
, unsigned len
)
93 m_interpolator
->begin(x
+0.5, y
+0.5, len
);
96 m_interpolator
->coordinates(&x
, &y
);
97 int d
= m_gradient_function
->calculate(x
>> downscale_shift
,
98 y
>> downscale_shift
, m_d2
);
99 d
= ((d
- m_d1
) * (int)m_color_function
->size()) / dd
;
101 if(d
>= (int)m_color_function
->size()) d
= m_color_function
->size() - 1;
102 *span
++ = (*m_color_function
)[d
];
109 interpolator_type
* m_interpolator
;
110 const GradientF
* m_gradient_function
;
111 const ColorF
* m_color_function
;
119 //=====================================================gradient_linear_color
120 template<class ColorT
>
121 struct gradient_linear_color
123 typedef ColorT color_type
;
125 gradient_linear_color() {}
126 gradient_linear_color(const color_type
& c1
, const color_type
& c2
,
127 unsigned size
= 256) :
128 m_c1(c1
), m_c2(c2
), m_size(size
) {}
130 unsigned size() const { return m_size
; }
131 color_type
operator [] (unsigned v
) const
133 return m_c1
.gradient(m_c2
, double(v
) / double(m_size
- 1));
136 void colors(const color_type
& c1
, const color_type
& c2
, unsigned size
= 256)
149 //==========================================================gradient_circle
150 class gradient_circle
152 // Actually the same as radial. Just for compatibility
154 static AGG_INLINE
int calculate(int x
, int y
, int)
156 return int(fast_sqrt(x
*x
+ y
*y
));
161 //==========================================================gradient_radial
162 class gradient_radial
165 static AGG_INLINE
int calculate(int x
, int y
, int)
167 return int(fast_sqrt(x
*x
+ y
*y
));
172 //========================================================gradient_radial_d
173 class gradient_radial_d
176 static AGG_INLINE
int calculate(int x
, int y
, int)
178 return uround(sqrt(double(x
)*double(x
) + double(y
)*double(y
)));
183 //====================================================gradient_radial_focus
184 class gradient_radial_focus
187 //---------------------------------------------------------------------
188 gradient_radial_focus() :
189 m_radius(100 * gradient_subpixel_scale
),
196 //---------------------------------------------------------------------
197 gradient_radial_focus(double r
, double fx
, double fy
) :
198 m_radius (iround(r
* gradient_subpixel_scale
)),
199 m_focus_x(iround(fx
* gradient_subpixel_scale
)),
200 m_focus_y(iround(fy
* gradient_subpixel_scale
))
205 //---------------------------------------------------------------------
206 void init(double r
, double fx
, double fy
)
208 m_radius
= iround(r
* gradient_subpixel_scale
);
209 m_focus_x
= iround(fx
* gradient_subpixel_scale
);
210 m_focus_y
= iround(fy
* gradient_subpixel_scale
);
214 //---------------------------------------------------------------------
215 double radius() const { return double(m_radius
) / gradient_subpixel_scale
; }
216 double focus_x() const { return double(m_focus_x
) / gradient_subpixel_scale
; }
217 double focus_y() const { return double(m_focus_y
) / gradient_subpixel_scale
; }
219 //---------------------------------------------------------------------
220 int calculate(int x
, int y
, int) const
225 // Special case to avoid divide by zero or very near zero
226 //---------------------------------
227 if(x
== iround(m_focus_x
))
229 solution_x
= m_focus_x
;
231 solution_y
+= (y
> m_focus_y
) ? m_trivial
: -m_trivial
;
235 // Slope of the focus-current line
236 //-------------------------------
237 double slope
= double(y
- m_focus_y
) / double(x
- m_focus_x
);
239 // y-intercept of that same line
240 //--------------------------------
241 double yint
= double(y
) - (slope
* x
);
243 // Use the classical quadratic formula to calculate
244 // the intersection point
245 //--------------------------------
246 double a
= (slope
* slope
) + 1;
247 double b
= 2 * slope
* yint
;
248 double c
= yint
* yint
- m_radius2
;
249 double det
= sqrt((b
* b
) - (4.0 * a
* c
));
252 // Choose the positive or negative root depending
253 // on where the X coord lies with respect to the focus.
254 solution_x
+= (x
< m_focus_x
) ? -det
: det
;
255 solution_x
/= 2.0 * a
;
257 // Calculating of Y is trivial
258 solution_y
= (slope
* solution_x
) + yint
;
261 // Calculate the percentage (0...1) of the current point along the
262 // focus-circumference line and return the normalized (0...d) value
263 //-------------------------------
264 solution_x
-= double(m_focus_x
);
265 solution_y
-= double(m_focus_y
);
266 double int_to_focus
= solution_x
* solution_x
+ solution_y
* solution_y
;
267 double cur_to_focus
= double(x
- m_focus_x
) * double(x
- m_focus_x
) +
268 double(y
- m_focus_y
) * double(y
- m_focus_y
);
270 return iround(sqrt(cur_to_focus
/ int_to_focus
) * m_radius
);
274 //---------------------------------------------------------------------
277 // For use in the quadratic equation
278 //-------------------------------
279 m_radius2
= double(m_radius
) * double(m_radius
);
281 double dist
= sqrt(double(m_focus_x
) * double(m_focus_x
) +
282 double(m_focus_y
) * double(m_focus_y
));
284 // Test if distance from focus to center is greater than the radius
285 // For the sake of assurance factor restrict the point to be
286 // no further than 99% of the radius.
287 //-------------------------------
288 double r
= m_radius
* 0.99;
291 // clamp focus to radius
292 // x = r cos theta, y = r sin theta
293 //------------------------
294 double a
= atan2(double(m_focus_y
), double(m_focus_x
));
295 m_focus_x
= iround(r
* cos(a
));
296 m_focus_y
= iround(r
* sin(a
));
299 // Calculate the solution to be used in the case where x == focus_x
300 //------------------------------
301 m_trivial
= sqrt(m_radius2
- (m_focus_x
* m_focus_x
));
313 //==============================================================gradient_x
317 static int calculate(int x
, int, int) { return x
; }
321 //==============================================================gradient_y
325 static int calculate(int, int y
, int) { return y
; }
329 //========================================================gradient_diamond
330 class gradient_diamond
333 static AGG_INLINE
int calculate(int x
, int y
, int)
337 return ax
> ay
? ax
: ay
;
342 //=============================================================gradient_xy
346 static AGG_INLINE
int calculate(int x
, int y
, int d
)
348 return abs(x
) * abs(y
) / d
;
353 //========================================================gradient_sqrt_xy
354 class gradient_sqrt_xy
357 static AGG_INLINE
int calculate(int x
, int y
, int)
359 return fast_sqrt(abs(x
) * abs(y
));
364 //==========================================================gradient_conic
368 static AGG_INLINE
int calculate(int x
, int y
, int d
)
370 return uround(fabs(atan2(double(y
), double(x
))) * double(d
) / pi
);
375 //=================================================gradient_repeat_adaptor
376 template<class GradientF
> class gradient_repeat_adaptor
379 gradient_repeat_adaptor(const GradientF
& gradient
) :
380 m_gradient(&gradient
) {}
382 AGG_INLINE
int calculate(int x
, int y
, int d
) const
384 int ret
= m_gradient
->calculate(x
, y
, d
) % d
;
385 if(ret
< 0) ret
+= d
;
390 const GradientF
* m_gradient
;
394 //================================================gradient_reflect_adaptor
395 template<class GradientF
> class gradient_reflect_adaptor
398 gradient_reflect_adaptor(const GradientF
& gradient
) :
399 m_gradient(&gradient
) {}
401 AGG_INLINE
int calculate(int x
, int y
, int d
) const
404 int ret
= m_gradient
->calculate(x
, y
, d
) % d2
;
405 if(ret
< 0) ret
+= d2
;
406 if(ret
>= d
) ret
= d2
- ret
;
411 const GradientF
* m_gradient
;