1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 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 //---------------------------------------------------------------------------- 15 16 #ifndef AGG_SPAN_GRADIENT_INCLUDED 17 #define AGG_SPAN_GRADIENT_INCLUDED 18 19 #include <math.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include "agg_basics.h" 23 #include "agg_math.h" 24 #include "agg_array.h" 25 26 27 namespace agg 28 { 29 30 enum gradient_subpixel_scale_e 31 { 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 35 }; 36 37 38 39 //==========================================================span_gradient 40 template<class ColorT, 41 class Interpolator, 42 class GradientF, 43 class ColorF> 44 class span_gradient 45 { 46 public: 47 typedef Interpolator interpolator_type; 48 typedef ColorT color_type; 49 50 enum downscale_shift_e 51 { 52 downscale_shift = interpolator_type::subpixel_shift - 53 gradient_subpixel_shift 54 }; 55 56 //-------------------------------------------------------------------- 57 span_gradient() {} 58 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)) 69 {} 70 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; } 77 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); } 84 85 //-------------------------------------------------------------------- 86 void prepare() {} 87 88 //-------------------------------------------------------------------- 89 void generate(color_type* span, int x, int y, unsigned len) 90 { 91 int dd = m_d2 - m_d1; 92 if(dd < 1) dd = 1; 93 m_interpolator->begin(x+0.5, y+0.5, len); 94 do 95 { 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; 100 if(d < 0) d = 0; 101 if(d >= (int)m_color_function->size()) d = m_color_function->size() - 1; 102 *span++ = (*m_color_function)[d]; 103 ++(*m_interpolator); 104 } 105 while(--len); 106 } 107 108 private: 109 interpolator_type* m_interpolator; 110 const GradientF* m_gradient_function; 111 const ColorF* m_color_function; 112 int m_d1; 113 int m_d2; 114 }; 115 116 117 118 119 //=====================================================gradient_linear_color 120 template<class ColorT> 121 struct gradient_linear_color 122 { 123 typedef ColorT color_type; 124 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) {} 129 130 unsigned size() const { return m_size; } 131 color_type operator [] (unsigned v) const 132 { 133 return m_c1.gradient(m_c2, double(v) / double(m_size - 1)); 134 } 135 136 void colors(const color_type& c1, const color_type& c2, unsigned size = 256) 137 { 138 m_c1 = c1; 139 m_c2 = c2; 140 m_size = size; 141 } 142 143 color_type m_c1; 144 color_type m_c2; 145 unsigned m_size; 146 }; 147 148 149 //==========================================================gradient_circle 150 class gradient_circle 151 { 152 // Actually the same as radial. Just for compatibility 153 public: 154 static AGG_INLINE int calculate(int x, int y, int) 155 { 156 return int(fast_sqrt(x*x + y*y)); 157 } 158 }; 159 160 161 //==========================================================gradient_radial 162 class gradient_radial 163 { 164 public: 165 static AGG_INLINE int calculate(int x, int y, int) 166 { 167 return int(fast_sqrt(x*x + y*y)); 168 } 169 }; 170 171 172 //========================================================gradient_radial_d 173 class gradient_radial_d 174 { 175 public: 176 static AGG_INLINE int calculate(int x, int y, int) 177 { 178 return uround(sqrt(double(x)*double(x) + double(y)*double(y))); 179 } 180 }; 181 182 183 //====================================================gradient_radial_focus 184 class gradient_radial_focus 185 { 186 public: 187 //--------------------------------------------------------------------- 188 gradient_radial_focus() : 189 m_radius(100 * gradient_subpixel_scale), 190 m_focus_x(0), 191 m_focus_y(0) 192 { 193 update_values(); 194 } 195 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)) 201 { 202 update_values(); 203 } 204 205 //--------------------------------------------------------------------- 206 void init(double r, double fx, double fy) 207 { 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); 211 update_values(); 212 } 213 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; } 218 219 //--------------------------------------------------------------------- 220 int calculate(int x, int y, int) const 221 { 222 double solution_x; 223 double solution_y; 224 225 // Special case to avoid divide by zero or very near zero 226 //--------------------------------- 227 if(x == iround(m_focus_x)) 228 { 229 solution_x = m_focus_x; 230 solution_y = 0.0; 231 solution_y += (y > m_focus_y) ? m_trivial : -m_trivial; 232 } 233 else 234 { 235 // Slope of the focus-current line 236 //------------------------------- 237 double slope = double(y - m_focus_y) / double(x - m_focus_x); 238 239 // y-intercept of that same line 240 //-------------------------------- 241 double yint = double(y) - (slope * x); 242 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)); 250 solution_x = -b; 251 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; 256 257 // Calculating of Y is trivial 258 solution_y = (slope * solution_x) + yint; 259 } 260 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); 269 270 return iround(sqrt(cur_to_focus / int_to_focus) * m_radius); 271 } 272 273 private: 274 //--------------------------------------------------------------------- 275 void update_values() 276 { 277 // For use in the quadratic equation 278 //------------------------------- 279 m_radius2 = double(m_radius) * double(m_radius); 280 281 double dist = sqrt(double(m_focus_x) * double(m_focus_x) + 282 double(m_focus_y) * double(m_focus_y)); 283 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; 289 if(dist > r) 290 { 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)); 297 } 298 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)); 302 } 303 304 int m_radius; 305 int m_focus_x; 306 int m_focus_y; 307 double m_radius2; 308 double m_trivial; 309 }; 310 311 312 313 //==============================================================gradient_x 314 class gradient_x 315 { 316 public: 317 static int calculate(int x, int, int) { return x; } 318 }; 319 320 321 //==============================================================gradient_y 322 class gradient_y 323 { 324 public: 325 static int calculate(int, int y, int) { return y; } 326 }; 327 328 329 //========================================================gradient_diamond 330 class gradient_diamond 331 { 332 public: 333 static AGG_INLINE int calculate(int x, int y, int) 334 { 335 int ax = abs(x); 336 int ay = abs(y); 337 return ax > ay ? ax : ay; 338 } 339 }; 340 341 342 //=============================================================gradient_xy 343 class gradient_xy 344 { 345 public: 346 static AGG_INLINE int calculate(int x, int y, int d) 347 { 348 return abs(x) * abs(y) / d; 349 } 350 }; 351 352 353 //========================================================gradient_sqrt_xy 354 class gradient_sqrt_xy 355 { 356 public: 357 static AGG_INLINE int calculate(int x, int y, int) 358 { 359 return fast_sqrt(abs(x) * abs(y)); 360 } 361 }; 362 363 364 //==========================================================gradient_conic 365 class gradient_conic 366 { 367 public: 368 static AGG_INLINE int calculate(int x, int y, int d) 369 { 370 return uround(fabs(atan2(double(y), double(x))) * double(d) / pi); 371 } 372 }; 373 374 375 //=================================================gradient_repeat_adaptor 376 template<class GradientF> class gradient_repeat_adaptor 377 { 378 public: 379 gradient_repeat_adaptor(const GradientF& gradient) : 380 m_gradient(&gradient) {} 381 382 AGG_INLINE int calculate(int x, int y, int d) const 383 { 384 int ret = m_gradient->calculate(x, y, d) % d; 385 if(ret < 0) ret += d; 386 return ret; 387 } 388 389 private: 390 const GradientF* m_gradient; 391 }; 392 393 394 //================================================gradient_reflect_adaptor 395 template<class GradientF> class gradient_reflect_adaptor 396 { 397 public: 398 gradient_reflect_adaptor(const GradientF& gradient) : 399 m_gradient(&gradient) {} 400 401 AGG_INLINE int calculate(int x, int y, int d) const 402 { 403 int d2 = d << 1; 404 int ret = m_gradient->calculate(x, y, d) % d2; 405 if(ret < 0) ret += d2; 406 if(ret >= d) ret = d2 - ret; 407 return ret; 408 } 409 410 private: 411 const GradientF* m_gradient; 412 }; 413 414 415 } 416 417 #endif 418