1 18 package org.apache.batik.ext.awt; 19 20 import java.awt.Color ; 21 import java.awt.Rectangle ; 22 import java.awt.RenderingHints ; 23 import java.awt.geom.AffineTransform ; 24 import java.awt.geom.NoninvertibleTransformException ; 25 import java.awt.geom.Rectangle2D ; 26 import java.awt.image.ColorModel ; 27 28 40 final class RadialGradientPaintContext extends MultipleGradientPaintContext { 41 42 43 private boolean isSimpleFocus = false; 44 45 46 private boolean isNonCyclic = false; 47 48 49 private float radius; 50 51 52 private float centerX, centerY, focusX, focusY; 53 54 55 private float radiusSq; 56 57 58 private float constA, constB; 59 60 63 private float trivial; 64 65 private static final int FIXED_POINT_IMPL = 1; 66 private static final int DEFAULT_IMPL = 2; 67 private static final int ANTI_ALIAS_IMPL = 3; 68 69 private int fillMethod; 70 71 72 private static final float SCALEBACK = .97f; 73 74 120 public RadialGradientPaintContext(ColorModel cm, 121 Rectangle deviceBounds, 122 Rectangle2D userBounds, 123 AffineTransform t, 124 RenderingHints hints, 125 float cx, float cy, 126 float r, 127 float fx, float fy, 128 float[] fractions, 129 Color [] colors, 130 MultipleGradientPaint.CycleMethodEnum 131 cycleMethod, 132 MultipleGradientPaint.ColorSpaceEnum 133 colorSpace) 134 throws NoninvertibleTransformException 135 { 136 super(cm, deviceBounds, userBounds, t, hints, fractions, colors, 137 cycleMethod, colorSpace); 138 139 centerX = cx; 141 centerY = cy; 142 focusX = fx; 143 focusY = fy; 144 radius = r; 145 146 this.isSimpleFocus = (focusX == centerX) && (focusY == centerY); 147 this.isNonCyclic = (cycleMethod == RadialGradientPaint.NO_CYCLE); 148 149 radiusSq = radius * radius; 151 152 float dX = focusX - centerX; 153 float dY = focusY - centerY; 154 155 double dist = Math.sqrt((dX * dX) + (dY * dY)); 156 157 if (dist > radius* SCALEBACK) { double angle = Math.atan2(dY, dX); 160 161 focusX = (float)(SCALEBACK * radius * Math.cos(angle)) + centerX; 163 164 focusY = (float)(SCALEBACK * radius * Math.sin(angle)) + centerY; 165 } 166 167 dX = focusX - centerX; 170 trivial = (float)Math.sqrt(radiusSq - (dX * dX)); 171 172 constA = a02 - centerX; 174 constB = a12 - centerY; 175 176 Object colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING); 177 Object rend = hints.get(RenderingHints.KEY_RENDERING); 178 179 fillMethod = 0; 180 181 if ((rend == RenderingHints.VALUE_RENDER_QUALITY) || 182 (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { 183 fillMethod = ANTI_ALIAS_IMPL; 185 } 186 187 if ((rend == RenderingHints.VALUE_RENDER_SPEED) || 188 (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED)) { 189 fillMethod = DEFAULT_IMPL; 191 } 192 193 if (fillMethod == 0) { 196 fillMethod = DEFAULT_IMPL; 199 200 if (false) { 201 if (hasDiscontinuity) { 205 fillMethod = ANTI_ALIAS_IMPL; 206 } else { 207 fillMethod = DEFAULT_IMPL; 208 } 209 } 210 } 211 212 if ((fillMethod == DEFAULT_IMPL) && 213 (isSimpleFocus && isNonCyclic && isSimpleLookup)) { 214 this.calculateFixedPointSqrtLookupTable(); 215 fillMethod = FIXED_POINT_IMPL; 216 } 217 } 218 219 225 protected void fillRaster(int pixels[], int off, int adjust, 226 int x, int y, int w, int h) { 227 switch(fillMethod) { 228 case FIXED_POINT_IMPL: 229 fixedPointSimplestCaseNonCyclicFillRaster(pixels, off, adjust, x, 231 y, w, h); 232 break; 233 case ANTI_ALIAS_IMPL: 234 antiAliasFillRaster(pixels, off, adjust, x, y, w, h); 236 break; 237 case DEFAULT_IMPL: 238 default: 239 cyclicCircularGradientFillRaster(pixels, off, adjust, x, y, w, h); 241 } 242 } 243 244 250 private void fixedPointSimplestCaseNonCyclicFillRaster(int pixels[], 251 int off, 252 int adjust, 253 int x, int y, 254 int w, int h) { 255 float iSq=0; final float indexFactor = fastGradientArraySize / radius; 257 258 final float constX = (a00*x) + (a01*y) + constA; 260 final float constY = (a10*x) + (a11*y) + constB; 261 final float deltaX = indexFactor * a00; final float deltaY = indexFactor * a10; float dX, dY; final int fixedArraySizeSq= 265 (fastGradientArraySize * fastGradientArraySize); 266 float g, gDelta, gDeltaDelta, temp; int gIndex; int iSqInt; 270 int end, j; int indexer = off; 273 temp = ((deltaX * deltaX) + (deltaY * deltaY)); 274 gDeltaDelta = ((temp * 2)); 275 276 if (temp > fixedArraySizeSq) { 277 final int val = gradientOverflow; 281 for(j = 0; j < h; j++){ for (end = indexer+w; indexer < end; indexer++) 284 pixels[indexer] = val; 285 indexer += adjust; 286 } 287 return; 288 } 289 290 for(j = 0; j < h; j++){ dX = indexFactor * ((a01*j) + constX); 294 dY = indexFactor * ((a11*j) + constY); 295 296 299 g = (((dY * dY) + (dX * dX)) ); 301 gDelta = (((((deltaY * dY) + (deltaX * dX))* 2) + 302 temp)); 303 304 for (end = indexer+w; indexer < end; indexer++) { 306 308 if (g >= fixedArraySizeSq) { 310 pixels[indexer] = gradientOverflow; 311 } 312 313 319 else { 320 iSq = (g * invSqStepFloat); 321 322 iSqInt = (int)iSq; iSq -= iSqInt; 324 gIndex = sqrtLutFixed[iSqInt]; 325 gIndex += (int)(iSq * (sqrtLutFixed[iSqInt + 1]-gIndex)); 326 pixels[indexer] = gradient[gIndex]; 327 } 328 329 330 g += gDelta; 332 gDelta += gDeltaDelta; 333 } 334 indexer += adjust; 335 } 336 } 337 338 339 private float invSqStepFloat; 340 341 342 private int MAX_PRECISION = 256; 343 344 345 private int sqrtLutFixed[] = new int[MAX_PRECISION]; 346 347 350 private void calculateFixedPointSqrtLookupTable() { 351 float sqStepFloat; 352 sqStepFloat = ((fastGradientArraySize * fastGradientArraySize) 353 / (MAX_PRECISION - 2)); 354 355 int i; 359 for (i = 0; i < MAX_PRECISION - 1; i++) { 360 sqrtLutFixed[i] = (int)(Math.sqrt(i*sqStepFloat)); 361 } 362 sqrtLutFixed[i] = sqrtLutFixed[i-1]; 363 invSqStepFloat = 1/sqStepFloat; 364 } 365 366 385 private void cyclicCircularGradientFillRaster(int pixels[], int off, 386 int adjust, 387 int x, int y, 388 int w, int h) { 389 final double constC = 391 -(radiusSq) + (centerX * centerX) + (centerY * centerY); 392 double A; double B; double C; double slope; double yintcpt; double solutionX; double solutionY; final float constX = (a00*x) + (a01*y) + a02; final float constY = (a10*x) + (a11*y) + a12; final float precalc2 = 2 * centerY; final float precalc3 =-2 * centerX; float X; float Y; float g; float det; float currentToFocusSq; float intersectToFocusSq; float deltaXSq; float deltaYSq; int indexer = off; int i, j; int pixInc = w+adjust; 415 for (j = 0; j < h; j++) { 417 X = (a01*j) + constX; Y = (a11*j) + constY; 419 420 for (i = 0; i < w; i++) { 422 423 if (((X-focusX)>-0.000001) && 425 ((X-focusX)< 0.000001)) { 426 solutionX = focusX; 427 428 solutionY = centerY; 429 430 solutionY += (Y > focusY)?trivial:-trivial; 431 } 432 433 else { 434 435 slope = (Y - focusY) / (X - focusX); 437 438 yintcpt = Y - (slope * X); 440 A = (slope * slope) + 1; 443 444 B = precalc3 + (-2 * slope * (centerY - yintcpt)); 445 446 C = constC + (yintcpt* (yintcpt - precalc2)); 447 448 det = (float)Math.sqrt((B * B) - ( 4 * A * C)); 449 450 solutionX = -B; 451 452 solutionX += (X < focusX)?-det:det; 455 456 solutionX = solutionX / (2 * A); 458 solutionY = (slope * solutionX) + yintcpt; 459 } 460 461 466 deltaXSq = (float)solutionX - focusX; 467 deltaXSq = deltaXSq * deltaXSq; 468 469 deltaYSq = (float)solutionY - focusY; 470 deltaYSq = deltaYSq * deltaYSq; 471 472 intersectToFocusSq = deltaXSq + deltaYSq; 473 474 deltaXSq = X - focusX; 475 deltaXSq = deltaXSq * deltaXSq; 476 477 deltaYSq = Y - focusY; 478 deltaYSq = deltaYSq * deltaYSq; 479 480 currentToFocusSq = deltaXSq + deltaYSq; 481 482 g = (float)Math.sqrt(currentToFocusSq / intersectToFocusSq); 485 486 pixels[indexer + i] = indexIntoGradientsArrays(g); 488 489 X += a00; Y += a10; 491 } indexer += pixInc; 493 } } 495 496 497 516 private void antiAliasFillRaster(int pixels[], int off, 517 int adjust, 518 int x, int y, 519 int w, int h) { 520 final double constC = 522 -(radiusSq) + (centerX * centerX) + (centerY * centerY); 523 final float precalc2 = 2 * centerY; final float precalc3 =-2 * centerX; 527 final float constX = (a00*(x-.5f)) + (a01*(y+.5f)) + a02; 529 final float constY = (a10*(x-.5f)) + (a11*(y+.5f)) + a12; 530 float X; float Y; int i, j; int indexer = off-1; 535 double [] prevGs = new double[w+1]; 536 double deltaXSq, deltaYSq; 537 double solutionX, solutionY; 538 double slope, yintcpt, A, B, C, det; 539 double intersectToFocusSq, currentToFocusSq; 540 double g00, g01, g10, g11; 541 542 X = constX - a01; 544 Y = constY - a11; 545 546 for (i=0; i <= w; i++) { 548 if (((X-focusX)>-0.000001) && 550 ((X-focusX)< 0.000001)) { 551 solutionX = focusX; 552 solutionY = centerY; 553 solutionY += (Y > focusY)?trivial:-trivial; 554 } 555 else { 556 562 563 slope = (Y - focusY) / (X - focusX); 565 566 yintcpt = Y - (slope * X); 568 A = (slope * slope) + 1; 571 572 B = precalc3 + (-2 * slope * (centerY - yintcpt)); 573 574 C = constC + (yintcpt* (yintcpt - precalc2)); 575 576 det = Math.sqrt((B * B) - ( 4 * A * C)); 577 578 solutionX = -B; 579 580 solutionX += (X < focusX)?-det:det; 583 584 solutionX = solutionX / (2 * A); 586 solutionY = (slope * solutionX) + yintcpt; 587 } 588 589 deltaXSq = solutionX - focusX; 594 deltaXSq = deltaXSq * deltaXSq; 595 596 deltaYSq = solutionY - focusY; 597 deltaYSq = deltaYSq * deltaYSq; 598 599 intersectToFocusSq = deltaXSq + deltaYSq; 600 601 deltaXSq = X - focusX; 602 deltaXSq = deltaXSq * deltaXSq; 603 604 deltaYSq = Y - focusY; 605 deltaYSq = deltaYSq * deltaYSq; 606 607 currentToFocusSq = deltaXSq + deltaYSq; 608 609 prevGs[i] = Math.sqrt(currentToFocusSq / intersectToFocusSq); 612 613 X += a00; Y += a10; 615 } 616 617 for (j = 0; j < h; j++) { 619 X = (a01*j) + constX; Y = (a11*j) + constY; 622 623 g10 = prevGs[0]; 624 if (((X-focusX)>-0.000001) && 626 ((X-focusX)< 0.000001)) { 627 solutionX = focusX; 628 solutionY = centerY; 629 solutionY += (Y > focusY)?trivial:-trivial; 630 } 631 else { 632 638 639 slope = (Y - focusY) / (X - focusX); 641 642 yintcpt = Y - (slope * X); 644 A = (slope * slope) + 1; 647 648 B = precalc3 + (-2 * slope * (centerY - yintcpt)); 649 650 C = constC + (yintcpt* (yintcpt - precalc2)); 651 652 det = Math.sqrt((B * B) - ( 4 * A * C)); 653 654 solutionX = -B; 655 656 solutionX += (X < focusX)?-det:det; 659 660 solutionX = solutionX / (2 * A); 662 solutionY = (slope * solutionX) + yintcpt; 663 } 664 665 deltaXSq = solutionX - focusX; 670 deltaXSq = deltaXSq * deltaXSq; 671 672 deltaYSq = solutionY - focusY; 673 deltaYSq = deltaYSq * deltaYSq; 674 675 intersectToFocusSq = deltaXSq + deltaYSq; 676 677 deltaXSq = X - focusX; 678 deltaXSq = deltaXSq * deltaXSq; 679 680 deltaYSq = Y - focusY; 681 deltaYSq = deltaYSq * deltaYSq; 682 683 currentToFocusSq = deltaXSq + deltaYSq; 684 g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq); 685 prevGs[0] = g11; 686 687 X += a00; Y += a10; 689 690 for (i=1; i <= w; i++) { 692 g00 = g10; 693 g01 = g11; 694 g10 = prevGs[i]; 695 696 if (((X-focusX)>-0.000001) && 698 ((X-focusX)< 0.000001)) { 699 solutionX = focusX; 700 solutionY = centerY; 701 solutionY += (Y > focusY)?trivial:-trivial; 702 } 703 else { 704 710 711 slope = (Y - focusY) / (X - focusX); 713 714 yintcpt = Y - (slope * X); 716 A = (slope * slope) + 1; 719 720 B = precalc3 + (-2 * slope * (centerY - yintcpt)); 721 722 C = constC + (yintcpt* (yintcpt - precalc2)); 723 724 det = Math.sqrt((B * B) - ( 4 * A * C)); 725 726 solutionX = -B; 727 728 solutionX += (X < focusX)?-det:det; 731 732 solutionX = solutionX / (2 * A); 734 solutionY = (slope * solutionX) + yintcpt; 735 } 736 737 deltaXSq = solutionX - focusX; 742 deltaXSq = deltaXSq * deltaXSq; 743 744 deltaYSq = solutionY - focusY; 745 deltaYSq = deltaYSq * deltaYSq; 746 747 intersectToFocusSq = deltaXSq + deltaYSq; 748 749 deltaXSq = X - focusX; 750 deltaXSq = deltaXSq * deltaXSq; 751 752 deltaYSq = Y - focusY; 753 deltaYSq = deltaYSq * deltaYSq; 754 755 currentToFocusSq = deltaXSq + deltaYSq; 756 g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq); 757 prevGs[i] = g11; 758 759 pixels[indexer+i] = indexGradientAntiAlias 761 ((float)((g00+g01+g10+g11)/4), 762 (float)Math.max(Math.abs(g11-g00), 763 Math.abs(g10-g01))); 764 765 X += a00; Y += a10; 767 } indexer += (w+adjust); 769 } } 771 } 772 | Popular Tags |