1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.2 3 // Copyright (C) 2002-2004 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 //---------------------------------------------------------------------------- 15 16 #ifndef AGG_SPAN_GRADIENT_INCLUDED 17 #define AGG_SPAN_GRADIENT_INCLUDED 18 19 #include <math.h> 20 #include <stdlib.h> 21 #include "agg_basics.h" 22 #include "agg_span_generator.h" 23 #include "agg_math.h" 24 25 26 namespace agg 27 { 28 29 enum 30 { 31 gradient_subpixel_shift = 4, 32 gradient_subpixel_size = 1 << gradient_subpixel_shift, 33 gradient_subpixel_mask = gradient_subpixel_size - 1 34 }; 35 36 37 //==========================================================span_gradient 38 template<class ColorT, 39 class Interpolator, 40 class GradientF, 41 class ColorF, 42 class Allocator = span_allocator<ColorT> > 43 class span_gradient : public span_generator<ColorT, Allocator> 44 { 45 public: 46 typedef Interpolator interpolator_type; 47 typedef Allocator alloc_type; 48 typedef ColorT color_type; 49 typedef span_generator<color_type, alloc_type> base_type; 50 51 enum 52 { 53 base_shift = 8, 54 base_size = 1 << base_shift, 55 base_mask = base_size - 1, 56 downscale_shift = interpolator_type::subpixel_shift - gradient_subpixel_shift 57 }; 58 59 60 //-------------------------------------------------------------------- 61 span_gradient(alloc_type& alloc) : base_type(alloc) {} 62 63 //-------------------------------------------------------------------- 64 span_gradient(alloc_type& alloc, 65 interpolator_type& inter, 66 const GradientF& gradient_function, 67 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)) 75 {} 76 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; } 83 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(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); } 90 91 //-------------------------------------------------------------------- 92 color_type* generate(int x, int y, unsigned len) 93 { 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); 98 do 99 { 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) << base_shift) / dd; 104 if(d < 0) d = 0; 105 if(d > base_mask) d = base_mask; 106 *span++ = m_color_function[d]; 107 ++(*m_interpolator); 108 } 109 while(--len); 110 return base_type::allocator().span(); 111 } 112 113 private: 114 interpolator_type* m_interpolator; 115 const GradientF* m_gradient_function; 116 ColorF m_color_function; 117 int m_d1; 118 int m_d2; 119 }; 120 121 122 123 124 //=====================================================gradient_linear_color 125 template<class ColorT, unsigned BaseShift=8> 126 struct gradient_linear_color 127 { 128 typedef ColorT color_type; 129 enum 130 { 131 base_shift = BaseShift, 132 base_size = 1 << base_shift, 133 base_mask = base_size - 1 134 }; 135 136 gradient_linear_color() {} 137 gradient_linear_color(const color_type& c1, const color_type& c2) : 138 m_c1(c1), m_c2(c2) {} 139 140 color_type operator [] (unsigned v) const 141 { 142 return m_c1.gradient(m_c2, double(v) / double(base_mask)); 143 } 144 145 void colors(const color_type& c1, const color_type& c2) 146 { 147 m_c1 = c1; 148 m_c2 = c2; 149 } 150 151 color_type m_c1; 152 color_type m_c2; 153 }; 154 155 156 //==========================================================gradient_circle 157 class gradient_circle 158 { 159 // Actually the same as radial. Just for compatibility 160 public: 161 static int calculate(int x, int y, int) 162 { 163 return int(fast_sqrt(x*x + y*y)); 164 } 165 }; 166 167 168 //==========================================================gradient_radial 169 class gradient_radial 170 { 171 public: 172 static int calculate(int x, int y, int) 173 { 174 return int(fast_sqrt(x*x + y*y)); 175 } 176 }; 177 178 179 //========================================================gradient_radial_d 180 class gradient_radial_d 181 { 182 public: 183 static int calculate(int x, int y, int) 184 { 185 return int(sqrt(double(x)*double(x) + double(y)*double(y))); 186 } 187 }; 188 189 190 //====================================================gradient_radial_focus 191 class gradient_radial_focus 192 { 193 public: 194 //--------------------------------------------------------------------- 195 gradient_radial_focus() : 196 m_radius(100 * gradient_subpixel_size), 197 m_focus_x(0), 198 m_focus_y(0) 199 { 200 update_values(); 201 } 202 203 //--------------------------------------------------------------------- 204 gradient_radial_focus(double r, double fx, double fy) : 205 m_radius (int(r * gradient_subpixel_size)), 206 m_focus_x(int(fx * gradient_subpixel_size)), 207 m_focus_y(int(fy * gradient_subpixel_size)) 208 { 209 update_values(); 210 } 211 212 //--------------------------------------------------------------------- 213 void init(double r, double fx, double fy) 214 { 215 m_radius = int(r * gradient_subpixel_size); 216 m_focus_x = int(fx * gradient_subpixel_size); 217 m_focus_y = int(fy * gradient_subpixel_size); 218 update_values(); 219 } 220 221 //--------------------------------------------------------------------- 222 double radius() const { return double(m_radius) / gradient_subpixel_size; } 223 double focus_x() const { return double(m_focus_x) / gradient_subpixel_size; } 224 double focus_y() const { return double(m_focus_y) / gradient_subpixel_size; } 225 226 //--------------------------------------------------------------------- 227 int calculate(int x, int y, int d) const 228 { 229 double solution_x; 230 double solution_y; 231 232 // Special case to avoid divide by zero or very near zero 233 //--------------------------------- 234 if(x == int(m_focus_x)) 235 { 236 solution_x = m_focus_x; 237 solution_y = 0.0; 238 solution_y += (y > m_focus_y) ? m_trivial : -m_trivial; 239 } 240 else 241 { 242 // Slope of the focus-current line 243 //------------------------------- 244 double slope = double(y - m_focus_y) / double(x - m_focus_x); 245 246 // y-intercept of that same line 247 //-------------------------------- 248 double yint = double(y) - (slope * x); 249 250 // Use the classical quadratic formula to calculate 251 // the intersection point 252 //-------------------------------- 253 double a = (slope * slope) + 1; 254 double b = 2 * slope * yint; 255 double c = yint * yint - m_radius2; 256 double det = sqrt((b * b) - (4.0 * a * c)); 257 solution_x = -b; 258 259 // Choose the positive or negative root depending 260 // on where the X coord lies with respect to the focus. 261 solution_x += (x < m_focus_x) ? -det : det; 262 solution_x /= 2.0 * a; 263 264 // Calculating of Y is trivial 265 solution_y = (slope * solution_x) + yint; 266 } 267 268 // Calculate the percentage (0...1) of the current point along the 269 // focus-circumference line and return the normalized (0...d) value 270 //------------------------------- 271 solution_x -= double(m_focus_x); 272 solution_y -= double(m_focus_y); 273 double int_to_focus = solution_x * solution_x + solution_y * solution_y; 274 double cur_to_focus = double(x - m_focus_x) * double(x - m_focus_x) + 275 double(y - m_focus_y) * double(y - m_focus_y); 276 277 return int(sqrt(cur_to_focus / int_to_focus) * d); 278 } 279 280 private: 281 //--------------------------------------------------------------------- 282 void update_values() 283 { 284 // For use in the quadractic equation 285 //------------------------------- 286 m_radius2 = double(m_radius) * double(m_radius); 287 288 double dist = sqrt(double(m_focus_x) * double(m_focus_x) + 289 double(m_focus_y) * double(m_focus_y)); 290 291 // Test if distance from focus to center is greater than the radius 292 // For the sake of assurance factor restrict the point to be 293 // no further than 99% of the radius. 294 //------------------------------- 295 double r = m_radius * 0.99; 296 if(dist > r) 297 { 298 // clamp focus to radius 299 // x = r cos theta, y = r sin theta 300 //------------------------ 301 double a = atan2(double(m_focus_y), double(m_focus_x)); 302 m_focus_x = int(r * cos(a)); 303 m_focus_y = int(r * sin(a)); 304 } 305 306 // Calculate the solution to be used in the case where x == focus_x 307 //------------------------------ 308 m_trivial = sqrt(m_radius2 - (m_focus_x * m_focus_x)); 309 } 310 311 int m_radius; 312 int m_focus_x; 313 int m_focus_y; 314 double m_radius2; 315 double m_trivial; 316 }; 317 318 319 320 //==============================================================gradient_x 321 class gradient_x 322 { 323 public: 324 static int calculate(int x, int, int) { return x; } 325 }; 326 327 328 //==============================================================gradient_y 329 class gradient_y 330 { 331 public: 332 static int calculate(int, int y, int) { return y; } 333 }; 334 335 336 //========================================================gradient_diamond 337 class gradient_diamond 338 { 339 public: 340 static int calculate(int x, int y, int) 341 { 342 int ax = abs(x); 343 int ay = abs(y); 344 return ax > ay ? ax : ay; 345 } 346 }; 347 348 349 //=============================================================gradient_xy 350 class gradient_xy 351 { 352 public: 353 static int calculate(int x, int y, int d) 354 { 355 return abs(x) * abs(y) / d; 356 } 357 }; 358 359 360 //========================================================gradient_sqrt_xy 361 class gradient_sqrt_xy 362 { 363 public: 364 static int calculate(int x, int y, int) 365 { 366 return fast_sqrt(abs(x) * abs(y)); 367 } 368 }; 369 370 371 //==========================================================gradient_conic 372 class gradient_conic 373 { 374 public: 375 static int calculate(int x, int y, int d) 376 { 377 return int(fabs(atan2(double(y), double(x))) * double(d) / pi); 378 } 379 }; 380 381 382 //=================================================gradient_repeat_adaptor 383 template<class GradientF> class gradient_repeat_adaptor 384 { 385 public: 386 gradient_repeat_adaptor(const GradientF& gradient) : 387 m_gradient(&gradient) {} 388 389 int calculate(int x, int y, int d) const 390 { 391 int ret = m_gradient->calculate(x, y, d) % d; 392 if(ret < 0) ret += d; 393 return ret; 394 } 395 396 private: 397 const GradientF* m_gradient; 398 }; 399 400 401 //================================================gradient_reflect_adaptor 402 template<class GradientF> class gradient_reflect_adaptor 403 { 404 public: 405 gradient_reflect_adaptor(const GradientF& gradient) : 406 m_gradient(&gradient) {} 407 408 int calculate(int x, int y, int d) const 409 { 410 int d2 = d << 1; 411 int ret = m_gradient->calculate(x, y, d) % d2; 412 if(ret < 0) ret += d2; 413 if(ret >= d) ret = d2 - ret; 414 return ret; 415 } 416 417 private: 418 const GradientF* m_gradient; 419 }; 420 421 422 } 423 424 #endif 425