00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef AGG_SPAN_GRADIENT_INCLUDED
00017 #define AGG_SPAN_GRADIENT_INCLUDED
00018
00019 #include <math.h>
00020 #include <stdlib.h>
00021 #include "agg_basics.h"
00022 #include "agg_span_generator.h"
00023 #include "agg_math.h"
00024
00025
00026 namespace agg
00027 {
00028
00029 enum
00030 {
00031 gradient_subpixel_shift = 4,
00032 gradient_subpixel_size = 1 << gradient_subpixel_shift,
00033 gradient_subpixel_mask = gradient_subpixel_size - 1
00034 };
00035
00036
00037
00038 template<class ColorT,
00039 class Interpolator,
00040 class GradientF,
00041 class ColorF,
00042 class Allocator = span_allocator<ColorT> >
00043 class span_gradient : public span_generator<ColorT, Allocator>
00044 {
00045 public:
00046 typedef Interpolator interpolator_type;
00047 typedef Allocator alloc_type;
00048 typedef ColorT color_type;
00049 typedef span_generator<color_type, alloc_type> base_type;
00050
00051 enum
00052 {
00053 base_shift = 8,
00054 base_size = 1 << base_shift,
00055 base_mask = base_size - 1,
00056 downscale_shift = interpolator_type::subpixel_shift - gradient_subpixel_shift
00057 };
00058
00059
00060
00061 span_gradient(alloc_type& alloc) : base_type(alloc) {}
00062
00063
00064 span_gradient(alloc_type& alloc,
00065 interpolator_type& inter,
00066 const GradientF& gradient_function,
00067 ColorF color_function,
00068 double d1, double d2) :
00069 base_type(alloc),
00070 m_interpolator(&inter),
00071 m_gradient_function(&gradient_function),
00072 m_color_function(color_function),
00073 m_d1(int(d1 * gradient_subpixel_size)),
00074 m_d2(int(d2 * gradient_subpixel_size))
00075 {}
00076
00077
00078 interpolator_type& interpolator() { return *m_interpolator; }
00079 const GradientF& gradient_function() const { return *m_gradient_function; }
00080 const ColorF color_function() const { return m_color_function; }
00081 double d1() const { return double(m_d1) / gradient_subpixel_size; }
00082 double d2() const { return double(m_d2) / gradient_subpixel_size; }
00083
00084
00085 void interpolator(interpolator_type& i) { m_interpolator = &i; }
00086 void gradient_function(const GradientF& gf) { m_gradient_function = &gf; }
00087 void color_function(ColorF cf) { m_color_function = cf; }
00088 void d1(double v) { m_d1 = int(v * gradient_subpixel_size); }
00089 void d2(double v) { m_d2 = int(v * gradient_subpixel_size); }
00090
00091
00092 color_type* generate(int x, int y, unsigned len)
00093 {
00094 color_type* span = base_type::allocator().span();
00095 int dd = m_d2 - m_d1;
00096 if(dd < 1) dd = 1;
00097 m_interpolator->begin(x+0.5, y+0.5, len);
00098 do
00099 {
00100 m_interpolator->coordinates(&x, &y);
00101 int d = m_gradient_function->calculate(x >> downscale_shift,
00102 y >> downscale_shift, dd);
00103 d = ((d - m_d1) << base_shift) / dd;
00104 if(d < 0) d = 0;
00105 if(d > base_mask) d = base_mask;
00106 *span++ = m_color_function[d];
00107 ++(*m_interpolator);
00108 }
00109 while(--len);
00110 return base_type::allocator().span();
00111 }
00112
00113 private:
00114 interpolator_type* m_interpolator;
00115 const GradientF* m_gradient_function;
00116 ColorF m_color_function;
00117 int m_d1;
00118 int m_d2;
00119 };
00120
00121
00122
00123
00124
00125 template<class ColorT, unsigned BaseShift=8>
00126 struct gradient_linear_color
00127 {
00128 typedef ColorT color_type;
00129 enum
00130 {
00131 base_shift = BaseShift,
00132 base_size = 1 << base_shift,
00133 base_mask = base_size - 1
00134 };
00135
00136 gradient_linear_color() {}
00137 gradient_linear_color(const color_type& c1, const color_type& c2) :
00138 m_c1(c1), m_c2(c2) {}
00139
00140 color_type operator [] (unsigned v) const
00141 {
00142 return m_c1.gradient(m_c2, double(v) / double(base_mask));
00143 }
00144
00145 void colors(const color_type& c1, const color_type& c2)
00146 {
00147 m_c1 = c1;
00148 m_c2 = c2;
00149 }
00150
00151 color_type m_c1;
00152 color_type m_c2;
00153 };
00154
00155
00156
00157 class gradient_circle
00158 {
00159
00160 public:
00161 static int calculate(int x, int y, int)
00162 {
00163 return int(fast_sqrt(x*x + y*y));
00164 }
00165 };
00166
00167
00168
00169 class gradient_radial
00170 {
00171 public:
00172 static int calculate(int x, int y, int)
00173 {
00174 return int(fast_sqrt(x*x + y*y));
00175 }
00176 };
00177
00178
00179
00180 class gradient_radial_d
00181 {
00182 public:
00183 static int calculate(int x, int y, int)
00184 {
00185 return int(sqrt(double(x)*double(x) + double(y)*double(y)));
00186 }
00187 };
00188
00189
00190
00191 class gradient_radial_focus
00192 {
00193 public:
00194
00195 gradient_radial_focus() :
00196 m_radius(100 * gradient_subpixel_size),
00197 m_focus_x(0),
00198 m_focus_y(0)
00199 {
00200 update_values();
00201 }
00202
00203
00204 gradient_radial_focus(double r, double fx, double fy) :
00205 m_radius (int(r * gradient_subpixel_size)),
00206 m_focus_x(int(fx * gradient_subpixel_size)),
00207 m_focus_y(int(fy * gradient_subpixel_size))
00208 {
00209 update_values();
00210 }
00211
00212
00213 void init(double r, double fx, double fy)
00214 {
00215 m_radius = int(r * gradient_subpixel_size);
00216 m_focus_x = int(fx * gradient_subpixel_size);
00217 m_focus_y = int(fy * gradient_subpixel_size);
00218 update_values();
00219 }
00220
00221
00222 double radius() const { return double(m_radius) / gradient_subpixel_size; }
00223 double focus_x() const { return double(m_focus_x) / gradient_subpixel_size; }
00224 double focus_y() const { return double(m_focus_y) / gradient_subpixel_size; }
00225
00226
00227 int calculate(int x, int y, int d) const
00228 {
00229 double solution_x;
00230 double solution_y;
00231
00232
00233
00234 if(x == int(m_focus_x))
00235 {
00236 solution_x = m_focus_x;
00237 solution_y = 0.0;
00238 solution_y += (y > m_focus_y) ? m_trivial : -m_trivial;
00239 }
00240 else
00241 {
00242
00243
00244 double slope = double(y - m_focus_y) / double(x - m_focus_x);
00245
00246
00247
00248 double yint = double(y) - (slope * x);
00249
00250
00251
00252
00253 double a = (slope * slope) + 1;
00254 double b = 2 * slope * yint;
00255 double c = yint * yint - m_radius2;
00256 double det = sqrt((b * b) - (4.0 * a * c));
00257 solution_x = -b;
00258
00259
00260
00261 solution_x += (x < m_focus_x) ? -det : det;
00262 solution_x /= 2.0 * a;
00263
00264
00265 solution_y = (slope * solution_x) + yint;
00266 }
00267
00268
00269
00270
00271 solution_x -= double(m_focus_x);
00272 solution_y -= double(m_focus_y);
00273 double int_to_focus = solution_x * solution_x + solution_y * solution_y;
00274 double cur_to_focus = double(x - m_focus_x) * double(x - m_focus_x) +
00275 double(y - m_focus_y) * double(y - m_focus_y);
00276
00277 return int(sqrt(cur_to_focus / int_to_focus) * d);
00278 }
00279
00280 private:
00281
00282 void update_values()
00283 {
00284
00285
00286 m_radius2 = double(m_radius) * double(m_radius);
00287
00288 double dist = sqrt(double(m_focus_x) * double(m_focus_x) +
00289 double(m_focus_y) * double(m_focus_y));
00290
00291
00292
00293
00294
00295 double r = m_radius * 0.99;
00296 if(dist > r)
00297 {
00298
00299
00300
00301 double a = atan2(double(m_focus_y), double(m_focus_x));
00302 m_focus_x = int(r * cos(a));
00303 m_focus_y = int(r * sin(a));
00304 }
00305
00306
00307
00308 m_trivial = sqrt(m_radius2 - (m_focus_x * m_focus_x));
00309 }
00310
00311 int m_radius;
00312 int m_focus_x;
00313 int m_focus_y;
00314 double m_radius2;
00315 double m_trivial;
00316 };
00317
00318
00319
00320
00321 class gradient_x
00322 {
00323 public:
00324 static int calculate(int x, int, int) { return x; }
00325 };
00326
00327
00328
00329 class gradient_y
00330 {
00331 public:
00332 static int calculate(int, int y, int) { return y; }
00333 };
00334
00335
00336
00337 class gradient_diamond
00338 {
00339 public:
00340 static int calculate(int x, int y, int)
00341 {
00342 int ax = abs(x);
00343 int ay = abs(y);
00344 return ax > ay ? ax : ay;
00345 }
00346 };
00347
00348
00349
00350 class gradient_xy
00351 {
00352 public:
00353 static int calculate(int x, int y, int d)
00354 {
00355 return abs(x) * abs(y) / d;
00356 }
00357 };
00358
00359
00360
00361 class gradient_sqrt_xy
00362 {
00363 public:
00364 static int calculate(int x, int y, int)
00365 {
00366 return fast_sqrt(abs(x) * abs(y));
00367 }
00368 };
00369
00370
00371
00372 class gradient_conic
00373 {
00374 public:
00375 static int calculate(int x, int y, int d)
00376 {
00377 return int(fabs(atan2(double(y), double(x))) * double(d) / pi);
00378 }
00379 };
00380
00381
00382
00383 template<class GradientF> class gradient_repeat_adaptor
00384 {
00385 public:
00386 gradient_repeat_adaptor(const GradientF& gradient) :
00387 m_gradient(&gradient) {}
00388
00389 int calculate(int x, int y, int d) const
00390 {
00391 int ret = m_gradient->calculate(x, y, d) % d;
00392 if(ret < 0) ret += d;
00393 return ret;
00394 }
00395
00396 private:
00397 const GradientF* m_gradient;
00398 };
00399
00400
00401
00402 template<class GradientF> class gradient_reflect_adaptor
00403 {
00404 public:
00405 gradient_reflect_adaptor(const GradientF& gradient) :
00406 m_gradient(&gradient) {}
00407
00408 int calculate(int x, int y, int d) const
00409 {
00410 int d2 = d << 1;
00411 int ret = m_gradient->calculate(x, y, d) % d2;
00412 if(ret < 0) ret += d2;
00413 if(ret >= d) ret = d2 - ret;
00414 return ret;
00415 }
00416
00417 private:
00418 const GradientF* m_gradient;
00419 };
00420
00421
00422 }
00423
00424 #endif