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 //----------------------------------------------------------------------------
16 #ifndef AGG_SPAN_GRADIENT_INCLUDED
17 #define AGG_SPAN_GRADIENT_INCLUDED
22 #include "agg_basics.h"
23 #include "agg_span_generator.h"
25 #include "agg_array.h"
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
,
45 class Allocator
= span_allocator
<ColorT
> >
46 class span_gradient
: public span_generator
<ColorT
, Allocator
>
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
;
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_
) :
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();
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
;
105 if(d
>= (int)m_color_function
->size()) d
= m_color_function
->size() - 1;
106 *span
++ = (*m_color_function
)[d
];
110 return base_type::allocator().span();
114 interpolator_type
* m_interpolator
;
115 const GradientF
* m_gradient_function
;
116 const ColorF
* m_color_function
;
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)
154 //==========================================================gradient_circle
155 class gradient_circle
157 // Actually the same as radial. Just for compatibility
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
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
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
192 //---------------------------------------------------------------------
193 gradient_radial_focus() :
194 m_radius(100 * gradient_subpixel_size
),
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
))
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
);
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
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
;
236 solution_y
+= (y
> m_focus_y
) ? m_trivial
: -m_trivial
;
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
));
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
);
279 //---------------------------------------------------------------------
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;
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
));
318 //==============================================================gradient_x
322 static int calculate(int x
, int, int) { return x
; }
326 //==============================================================gradient_y
330 static int calculate(int, int y
, int) { return y
; }
334 //========================================================gradient_diamond
335 class gradient_diamond
338 static AGG_INLINE
int calculate(int x
, int y
, int)
342 return ax
> ay
? ax
: ay
;
347 //=============================================================gradient_xy
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
362 static AGG_INLINE
int calculate(int x
, int y
, int)
364 return fast_sqrt(abs(x
) * abs(y
));
369 //==========================================================gradient_conic
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
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
;
395 const GradientF
* m_gradient
;
399 //================================================gradient_reflect_adaptor
400 template<class GradientF
> class gradient_reflect_adaptor
403 gradient_reflect_adaptor(const GradientF
& gradient
) :
404 m_gradient(&gradient
) {}
406 AGG_INLINE
int calculate(int x
, int y
, int d
) const
409 int ret
= m_gradient
->calculate(x
, y
, d
) % d2
;
410 if(ret
< 0) ret
+= d2
;
411 if(ret
>= d
) ret
= d2
- ret
;
416 const GradientF
* m_gradient
;