source: josm/trunk/src/com/kitfox/svg/batik/RadialGradientPaintContext.java@ 10746

Last change on this file since 10746 was 8084, checked in by bastiK, 10 years ago

add svn:eol-style=native for svgsalamander

  • Property svn:eol-style set to native
File size: 30.4 KB
Line 
1/*****************************************************************************
2 * Copyright (C) The Apache Software Foundation. All rights reserved. *
3 * ------------------------------------------------------------------------- *
4 * This software is published under the terms of the Apache Software License *
5 * version 1.1, a copy of which has been included with this distribution in *
6 * the LICENSE file. *
7 *****************************************************************************/
8
9package com.kitfox.svg.batik;
10
11import java.awt.Color;
12import java.awt.Rectangle;
13import java.awt.RenderingHints;
14import java.awt.geom.AffineTransform;
15import java.awt.geom.NoninvertibleTransformException;
16import java.awt.geom.Rectangle2D;
17import java.awt.image.ColorModel;
18
19/**
20 * Provides the actual implementation for the RadialGradientPaint.
21 * This is where the pixel processing is done. A RadialGradienPaint
22 * only supports circular gradients, but it should be possible to scale
23 * the circle to look approximately elliptical, by means of a
24 * gradient transform passed into the RadialGradientPaint constructor.
25 *
26 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
27 * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
28 * @version $Id: RadialGradientPaintContext.java,v 1.2 2005/10/12 20:36:55 kitfox Exp $
29 *
30 */
31final class RadialGradientPaintContext extends MultipleGradientPaintContext {
32
33 /** True when (focus == center) */
34 private boolean isSimpleFocus = false;
35
36 /** True when (cycleMethod == NO_CYCLE) */
37 private boolean isNonCyclic = false;
38
39 /** Radius of the outermost circle defining the 100% gradient stop. */
40 private float radius;
41
42 /** Variables representing center and focus points. */
43 private float centerX, centerY, focusX, focusY;
44
45 /** Radius of the gradient circle squared. */
46 private float radiusSq;
47
48 /** Constant part of X, Y user space coordinates. */
49 private float constA, constB;
50
51 /** This value represents the solution when focusX == X. It is called
52 * trivial because it is easier to calculate than the general case.
53 */
54 private float trivial;
55
56 private static final int FIXED_POINT_IMPL = 1;
57 private static final int DEFAULT_IMPL = 2;
58 private static final int ANTI_ALIAS_IMPL = 3;
59
60 private int fillMethod;
61
62 /** Amount for offset when clamping focus. */
63 private static final float SCALEBACK = .97f;
64
65 /**
66 * Constructor for RadialGradientPaintContext.
67 *
68 * @param cm {@link ColorModel} that receives
69 * the <code>Paint</code> data. This is used only as a hint.
70 *
71 * @param deviceBounds the device space bounding box of the
72 * graphics primitive being rendered
73 *
74 * @param userBounds the user space bounding box of the
75 * graphics primitive being rendered
76 *
77 * @param t the {@link AffineTransform} from user
78 * space into device space (gradientTransform should be
79 * concatenated with this)
80 *
81 * @param hints the hints that the context object uses to choose
82 * between rendering alternatives
83 *
84 * @param cx the center point in user space of the circle defining
85 * the gradient. The last color of the gradient is mapped to the
86 * perimeter of this circle X coordinate
87 *
88 * @param cy the center point in user space of the circle defining
89 * the gradient. The last color of the gradient is mapped to the
90 * perimeter of this circle Y coordinate
91 *
92 * @param r the radius of the circle defining the extents of the
93 * color gradient
94 *
95 * @param fx the point in user space to which the first color is mapped
96 * X coordinate
97 *
98 * @param fy the point in user space to which the first color is mapped
99 * Y coordinate
100 *
101 * @param fractions the fractions specifying the gradient distribution
102 *
103 * @param colors the gradient colors
104 *
105 * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
106 *
107 * @param colorSpace which colorspace to use for interpolation,
108 * either SRGB or LINEAR_RGB
109 *
110 */
111 public RadialGradientPaintContext(ColorModel cm,
112 Rectangle deviceBounds,
113 Rectangle2D userBounds,
114 AffineTransform t,
115 RenderingHints hints,
116 float cx, float cy,
117 float r,
118 float fx, float fy,
119 float[] fractions,
120 Color[] colors,
121 MultipleGradientPaint.CycleMethodEnum
122 cycleMethod,
123 MultipleGradientPaint.ColorSpaceEnum
124 colorSpace)
125 throws NoninvertibleTransformException
126 {
127 super(cm, deviceBounds, userBounds, t, hints, fractions, colors,
128 cycleMethod, colorSpace);
129
130 //copy some parameters.
131 centerX = cx;
132 centerY = cy;
133 focusX = fx;
134 focusY = fy;
135 radius = r;
136
137 this.isSimpleFocus = (focusX == centerX) && (focusY == centerY);
138 this.isNonCyclic = (cycleMethod == RadialGradientPaint.NO_CYCLE);
139
140 //for use in the quadractic equation
141 radiusSq = radius * radius;
142
143 float dX = focusX - centerX;
144 float dY = focusY - centerY;
145
146 double dist = Math.sqrt((dX * dX) + (dY * dY));
147
148 //test if distance from focus to center is greater than the radius
149 if (dist > radius* SCALEBACK) { //clamp focus to radius
150 double angle = Math.atan2(dY, dX);
151
152 //x = r cos theta, y = r sin theta
153 focusX = (float)(SCALEBACK * radius * Math.cos(angle)) + centerX;
154
155 focusY = (float)(SCALEBACK * radius * Math.sin(angle)) + centerY;
156 }
157
158 //calculate the solution to be used in the case where X == focusX
159 //in cyclicCircularGradientFillRaster
160 dX = focusX - centerX;
161 trivial = (float)Math.sqrt(radiusSq - (dX * dX));
162
163 // constant parts of X, Y user space coordinates
164 constA = a02 - centerX;
165 constB = a12 - centerY;
166
167 Object colorRend;
168 Object rend;
169 //hints can be null on Mac OSX
170 if (hints == null)
171 {
172 colorRend = RenderingHints.VALUE_COLOR_RENDER_DEFAULT;
173 rend = RenderingHints.VALUE_RENDER_DEFAULT;
174 }
175 else
176 {
177 colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING);
178 rend = hints.get(RenderingHints.KEY_RENDERING);
179 }
180
181 fillMethod = 0;
182
183 if ((rend == RenderingHints.VALUE_RENDER_QUALITY) ||
184 (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY)) {
185 // System.out.println("AAHints set: " + rend + ", " + colorRend);
186 fillMethod = ANTI_ALIAS_IMPL;
187 }
188
189 if ((rend == RenderingHints.VALUE_RENDER_SPEED) ||
190 (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED)) {
191 // System.out.println("SPHints set: " + rend + ", " + colorRend);
192 fillMethod = DEFAULT_IMPL;
193 }
194
195 // We are in the 'default' case, no hint or hint set to
196 // DEFAULT values...
197 if (fillMethod == 0) {
198 // For now we will always use the 'default' impl if
199 // one is not specified.
200 fillMethod = DEFAULT_IMPL;
201
202 if (false) {
203 // This could be used for a 'smart' choice in
204 // the default case, if the gradient has obvious
205 // discontinuites use AA, otherwise default
206 if (hasDiscontinuity) {
207 fillMethod = ANTI_ALIAS_IMPL;
208 } else {
209 fillMethod = DEFAULT_IMPL;
210 }
211 }
212 }
213
214 if ((fillMethod == DEFAULT_IMPL) &&
215 (isSimpleFocus && isNonCyclic && isSimpleLookup)) {
216 this.calculateFixedPointSqrtLookupTable();
217 fillMethod = FIXED_POINT_IMPL;
218 }
219 }
220
221 /**
222 * Return a Raster containing the colors generated for the graphics
223 * operation.
224 * @param x,y,w,h The area in device space for which colors are
225 * generated.
226 */
227 protected void fillRaster(int pixels[], int off, int adjust,
228 int x, int y, int w, int h) {
229 switch(fillMethod) {
230 case FIXED_POINT_IMPL:
231 // System.out.println("Calling FP");
232 fixedPointSimplestCaseNonCyclicFillRaster(pixels, off, adjust, x,
233 y, w, h);
234 break;
235 case ANTI_ALIAS_IMPL:
236 // System.out.println("Calling AA");
237 antiAliasFillRaster(pixels, off, adjust, x, y, w, h);
238 break;
239 case DEFAULT_IMPL:
240 default:
241 // System.out.println("Calling Default");
242 cyclicCircularGradientFillRaster(pixels, off, adjust, x, y, w, h);
243 }
244 }
245
246 /**
247 * This code works in the simplest of cases, where the focus == center
248 * point, the gradient is noncyclic, and the gradient lookup method is
249 * fast (single array index, no conversion necessary).
250 *
251 */
252 private void fixedPointSimplestCaseNonCyclicFillRaster(int pixels[],
253 int off,
254 int adjust,
255 int x, int y,
256 int w, int h) {
257 float iSq=0; // Square distance index
258 final float indexFactor = fastGradientArraySize / radius;
259
260 //constant part of X and Y coordinates for the entire raster
261 final float constX = (a00*x) + (a01*y) + constA;
262 final float constY = (a10*x) + (a11*y) + constB;
263 final float deltaX = indexFactor * a00; //incremental change in dX
264 final float deltaY = indexFactor * a10; //incremental change in dY
265 float dX, dY; //the current distance from center
266 final int fixedArraySizeSq=
267 (fastGradientArraySize * fastGradientArraySize);
268 float g, gDelta, gDeltaDelta, temp; //gradient square value
269 int gIndex; // integer number used to index gradient array
270 int iSqInt; // Square distance index
271
272 int end, j; //indexing variables
273 int indexer = off;//used to index pixels array
274
275 temp = ((deltaX * deltaX) + (deltaY * deltaY));
276 gDeltaDelta = ((temp * 2));
277
278 if (temp > fixedArraySizeSq) {
279 // This combination of scale and circle radius means
280 // essentially no pixels will be anything but the end
281 // stop color. This also avoids math problems.
282 final int val = gradientOverflow;
283 for(j = 0; j < h; j++){ //for every row
284 //for every column (inner loop begins here)
285 for (end = indexer+w; indexer < end; indexer++)
286 pixels[indexer] = val;
287 indexer += adjust;
288 }
289 return;
290 }
291
292 // For every point in the raster, calculate the color at that point
293 for(j = 0; j < h; j++){ //for every row
294 //x and y (in user space) of the first pixel of this row
295 dX = indexFactor * ((a01*j) + constX);
296 dY = indexFactor * ((a11*j) + constY);
297
298 // these values below here allow for an incremental calculation
299 // of dX^2 + dY^2
300
301 //initialize to be equal to distance squared
302 g = (((dY * dY) + (dX * dX)) );
303 gDelta = (((((deltaY * dY) + (deltaX * dX))* 2) +
304 temp));
305
306 //for every column (inner loop begins here)
307 for (end = indexer+w; indexer < end; indexer++) {
308 //determine the distance to the center
309
310 //since this is a non cyclic fill raster, crop at "1" and 0
311 if (g >= fixedArraySizeSq) {
312 pixels[indexer] = gradientOverflow;
313 }
314
315 // This should not happen as gIndex is a square
316 // quantity. Code commented out on purpose, can't underflow.
317 // else if (g < 0) {
318 // gIndex = 0;
319 // }
320
321 else {
322 iSq = (g * invSqStepFloat);
323
324 iSqInt = (int)iSq; //chop off fractional part
325 iSq -= iSqInt;
326 gIndex = sqrtLutFixed[iSqInt];
327 gIndex += (int)(iSq * (sqrtLutFixed[iSqInt + 1]-gIndex));
328 pixels[indexer] = gradient[gIndex];
329 }
330
331
332 //incremental calculation
333 g += gDelta;
334 gDelta += gDeltaDelta;
335 }
336 indexer += adjust;
337 }
338 }
339
340 /** Length of a square distance intervale in the lookup table */
341 private float invSqStepFloat;
342
343 /** Used to limit the size of the square root lookup table */
344 private int MAX_PRECISION = 256;
345
346 /** Square root lookup table */
347 private int sqrtLutFixed[] = new int[MAX_PRECISION];
348
349 /**
350 * Build square root lookup table
351 */
352 private void calculateFixedPointSqrtLookupTable() {
353 float sqStepFloat;
354 sqStepFloat = ((fastGradientArraySize * fastGradientArraySize)
355 / (MAX_PRECISION - 2));
356
357 // The last two values are the same so that linear square root
358 // interpolation can happen on the maximum reachable element in the
359 // lookup table (precision-2)
360 int i;
361 for (i = 0; i < MAX_PRECISION - 1; i++) {
362 sqrtLutFixed[i] = (int)(Math.sqrt(i*sqStepFloat));
363 }
364 sqrtLutFixed[i] = sqrtLutFixed[i-1];
365 invSqStepFloat = 1/sqStepFloat;
366 }
367
368 /** Fill the raster, cycling the gradient colors when a point falls outside
369 * of the perimeter of the 100% stop circle.
370 *
371 * This calculation first computes the intersection point of the line
372 * from the focus through the current point in the raster, and the
373 * perimeter of the gradient circle.
374 *
375 * Then it determines the percentage distance of the current point along
376 * that line (focus is 0%, perimeter is 100%).
377 *
378 * Equation of a circle centered at (a,b) with radius r:
379 * (x-a)^2 + (y-b)^2 = r^2
380 * Equation of a line with slope m and y-intercept b
381 * y = mx + b
382 * replacing y in the cirlce equation and solving using the quadratic
383 * formula produces the following set of equations. Constant factors have
384 * been extracted out of the inner loop.
385 *
386 */
387 private void cyclicCircularGradientFillRaster(int pixels[], int off,
388 int adjust,
389 int x, int y,
390 int w, int h) {
391 // Constant part of the C factor of the quadratic equation
392 final double constC =
393 -(radiusSq) + (centerX * centerX) + (centerY * centerY);
394 double A; //coefficient of the quadratic equation (Ax^2 + Bx + C = 0)
395 double B; //coefficient of the quadratic equation
396 double C; //coefficient of the quadratic equation
397 double slope; //slope of the focus-perimeter line
398 double yintcpt; //y-intercept of the focus-perimeter line
399 double solutionX;//intersection with circle X coordinate
400 double solutionY;//intersection with circle Y coordinate
401 final float constX = (a00*x) + (a01*y) + a02;//const part of X coord
402 final float constY = (a10*x) + (a11*y) + a12; //const part of Y coord
403 final float precalc2 = 2 * centerY;//const in inner loop quad. formula
404 final float precalc3 =-2 * centerX;//const in inner loop quad. formula
405 float X; // User space point X coordinate
406 float Y; // User space point Y coordinate
407 float g;//value between 0 and 1 specifying position in the gradient
408 float det; //determinant of quadratic formula (should always be >0)
409 float currentToFocusSq;//sq distance from the current pt. to focus
410 float intersectToFocusSq;//sq distance from the intersect pt. to focus
411 float deltaXSq; //temp variable for a change in X squared.
412 float deltaYSq; //temp variable for a change in Y squared.
413 int indexer = off; //index variable for pixels array
414 int i, j; //indexing variables for FOR loops
415 int pixInc = w+adjust;//incremental index change for pixels array
416
417 for (j = 0; j < h; j++) { //for every row
418
419 X = (a01*j) + constX; //constants from column to column
420 Y = (a11*j) + constY;
421
422 //for every column (inner loop begins here)
423 for (i = 0; i < w; i++) {
424
425 // special case to avoid divide by zero or very near zero
426 if (((X-focusX)>-0.000001) &&
427 ((X-focusX)< 0.000001)) {
428 solutionX = focusX;
429
430 solutionY = centerY;
431
432 solutionY += (Y > focusY)?trivial:-trivial;
433 }
434
435 else {
436
437 //slope of the focus-current line
438 slope = (Y - focusY) / (X - focusX);
439
440 yintcpt = Y - (slope * X); //y-intercept of that same line
441
442 //use the quadratic formula to calculate the intersection
443 //point
444 A = (slope * slope) + 1;
445
446 B = precalc3 + (-2 * slope * (centerY - yintcpt));
447
448 C = constC + (yintcpt* (yintcpt - precalc2));
449
450 det = (float)Math.sqrt((B * B) - ( 4 * A * C));
451
452 solutionX = -B;
453
454 //choose the positive or negative root depending
455 //on where the X coord lies with respect to the focus.
456 solutionX += (X < focusX)?-det:det;
457
458 solutionX = solutionX / (2 * A);//divisor
459
460 solutionY = (slope * solutionX) + yintcpt;
461 }
462
463 //calculate the square of the distance from the current point
464 //to the focus and the square of the distance from the
465 //intersection point to the focus. Want the squares so we can
466 //do 1 square root after division instead of 2 before.
467
468 deltaXSq = (float)solutionX - focusX;
469 deltaXSq = deltaXSq * deltaXSq;
470
471 deltaYSq = (float)solutionY - focusY;
472 deltaYSq = deltaYSq * deltaYSq;
473
474 intersectToFocusSq = deltaXSq + deltaYSq;
475
476 deltaXSq = X - focusX;
477 deltaXSq = deltaXSq * deltaXSq;
478
479 deltaYSq = Y - focusY;
480 deltaYSq = deltaYSq * deltaYSq;
481
482 currentToFocusSq = deltaXSq + deltaYSq;
483
484 //want the percentage (0-1) of the current point along the
485 //focus-circumference line
486 g = (float)Math.sqrt(currentToFocusSq / intersectToFocusSq);
487
488 //Get the color at this point
489 pixels[indexer + i] = indexIntoGradientsArrays(g);
490
491 X += a00; //incremental change in X, Y
492 Y += a10;
493 } //end inner loop
494 indexer += pixInc;
495 } //end outer loop
496 }
497
498
499 /** Fill the raster, cycling the gradient colors when a point
500 * falls outside of the perimeter of the 100% stop circle. Use
501 * the anti-aliased gradient lookup.
502 *
503 * This calculation first computes the intersection point of the line
504 * from the focus through the current point in the raster, and the
505 * perimeter of the gradient circle.
506 *
507 * Then it determines the percentage distance of the current point along
508 * that line (focus is 0%, perimeter is 100%).
509 *
510 * Equation of a circle centered at (a,b) with radius r:
511 * (x-a)^2 + (y-b)^2 = r^2
512 * Equation of a line with slope m and y-intercept b
513 * y = mx + b
514 * replacing y in the cirlce equation and solving using the quadratic
515 * formula produces the following set of equations. Constant factors have
516 * been extracted out of the inner loop.
517 * */
518 private void antiAliasFillRaster(int pixels[], int off,
519 int adjust,
520 int x, int y,
521 int w, int h) {
522 // Constant part of the C factor of the quadratic equation
523 final double constC =
524 -(radiusSq) + (centerX * centerX) + (centerY * centerY);
525 //coefficients of the quadratic equation (Ax^2 + Bx + C = 0)
526 final float precalc2 = 2 * centerY;//const in inner loop quad. formula
527 final float precalc3 =-2 * centerX;//const in inner loop quad. formula
528
529 //const part of X,Y coord (shifted to bottom left corner of pixel.
530 final float constX = (a00*(x-.5f)) + (a01*(y+.5f)) + a02;
531 final float constY = (a10*(x-.5f)) + (a11*(y+.5f)) + a12;
532 float X; // User space point X coordinate
533 float Y; // User space point Y coordinate
534 int i, j; //indexing variables for FOR loops
535 int indexer = off-1; //index variable for pixels array
536
537 // Size of a pixel in user space.
538 double pixSzSq = (float)(a00*a00+a01*a01+a10*a10+a11*a11);
539 double [] prevGs = new double[w+1];
540 double deltaXSq, deltaYSq;
541 double solutionX, solutionY;
542 double slope, yintcpt, A, B, C, det;
543 double intersectToFocusSq, currentToFocusSq;
544 double g00, g01, g10, g11;
545
546 // Set X,Y to top left corner of first pixel of first row.
547 X = constX - a01;
548 Y = constY - a11;
549
550 // Calc top row of g's.
551 for (i=0; i <= w; i++) {
552 // special case to avoid divide by zero or very near zero
553 if (((X-focusX)>-0.000001) &&
554 ((X-focusX)< 0.000001)) {
555 solutionX = focusX;
556 solutionY = centerY;
557 solutionY += (Y > focusY)?trivial:-trivial;
558 }
559 else {
560 // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0
561 // Formula line: Y = Slope*x + Y0;
562 //
563 // So you substitue line into Circle and apply
564 // Quadradic formula.
565
566
567 //slope of the focus-current line
568 slope = (Y - focusY) / (X - focusX);
569
570 yintcpt = Y - (slope * X); //y-intercept of that same line
571
572 //use the quadratic formula to calculate the intersection
573 //point
574 A = (slope * slope) + 1;
575
576 B = precalc3 + (-2 * slope * (centerY - yintcpt));
577
578 C = constC + (yintcpt* (yintcpt - precalc2));
579
580 det = Math.sqrt((B * B) - ( 4 * A * C));
581
582 solutionX = -B;
583
584 //choose the positive or negative root depending
585 //on where the X coord lies with respect to the focus.
586 solutionX += (X < focusX)?-det:det;
587
588 solutionX = solutionX / (2 * A);//divisor
589
590 solutionY = (slope * solutionX) + yintcpt;
591 }
592
593 //calculate the square of the distance from the current point
594 //to the focus and the square of the distance from the
595 //intersection point to the focus. Want the squares so we can
596 //do 1 square root after division instead of 2 before.
597 deltaXSq = solutionX - focusX;
598 deltaXSq = deltaXSq * deltaXSq;
599
600 deltaYSq = solutionY - focusY;
601 deltaYSq = deltaYSq * deltaYSq;
602
603 intersectToFocusSq = deltaXSq + deltaYSq;
604
605 deltaXSq = X - focusX;
606 deltaXSq = deltaXSq * deltaXSq;
607
608 deltaYSq = Y - focusY;
609 deltaYSq = deltaYSq * deltaYSq;
610
611 currentToFocusSq = deltaXSq + deltaYSq;
612
613 //want the percentage (0-1) of the current point along the
614 //focus-circumference line
615 prevGs[i] = Math.sqrt(currentToFocusSq / intersectToFocusSq);
616
617 X += a00; //incremental change in X, Y
618 Y += a10;
619 }
620
621 for (j = 0; j < h; j++) { //for every row
622
623 // Set X,Y to bottom edge of pixel row.
624 X = (a01*j) + constX; //constants from row to row
625 Y = (a11*j) + constY;
626
627 g10 = prevGs[0];
628 // special case to avoid divide by zero or very near zero
629 if (((X-focusX)>-0.000001) &&
630 ((X-focusX)< 0.000001)) {
631 solutionX = focusX;
632 solutionY = centerY;
633 solutionY += (Y > focusY)?trivial:-trivial;
634 }
635 else {
636 // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0
637 // Formula line: Y = Slope*x + Y0;
638 //
639 // So you substitue line into Circle and apply
640 // Quadradic formula.
641
642
643 //slope of the focus-current line
644 slope = (Y - focusY) / (X - focusX);
645
646 yintcpt = Y - (slope * X); //y-intercept of that same line
647
648 //use the quadratic formula to calculate the intersection
649 //point
650 A = (slope * slope) + 1;
651
652 B = precalc3 + (-2 * slope * (centerY - yintcpt));
653
654 C = constC + (yintcpt* (yintcpt - precalc2));
655
656 det = Math.sqrt((B * B) - ( 4 * A * C));
657
658 solutionX = -B;
659
660 //choose the positive or negative root depending
661 //on where the X coord lies with respect to the focus.
662 solutionX += (X < focusX)?-det:det;
663
664 solutionX = solutionX / (2 * A);//divisor
665
666 solutionY = (slope * solutionX) + yintcpt;
667 }
668
669 //calculate the square of the distance from the current point
670 //to the focus and the square of the distance from the
671 //intersection point to the focus. Want the squares so we can
672 //do 1 square root after division instead of 2 before.
673 deltaXSq = solutionX - focusX;
674 deltaXSq = deltaXSq * deltaXSq;
675
676 deltaYSq = solutionY - focusY;
677 deltaYSq = deltaYSq * deltaYSq;
678
679 intersectToFocusSq = deltaXSq + deltaYSq;
680
681 deltaXSq = X - focusX;
682 deltaXSq = deltaXSq * deltaXSq;
683
684 deltaYSq = Y - focusY;
685 deltaYSq = deltaYSq * deltaYSq;
686
687 currentToFocusSq = deltaXSq + deltaYSq;
688 g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq);
689 prevGs[0] = g11;
690
691 X += a00; //incremental change in X, Y
692 Y += a10;
693
694 //for every column (inner loop begins here)
695 for (i=1; i <= w; i++) {
696 g00 = g10;
697 g01 = g11;
698 g10 = prevGs[i];
699
700 // special case to avoid divide by zero or very near zero
701 if (((X-focusX)>-0.000001) &&
702 ((X-focusX)< 0.000001)) {
703 solutionX = focusX;
704 solutionY = centerY;
705 solutionY += (Y > focusY)?trivial:-trivial;
706 }
707 else {
708 // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0
709 // Formula line: Y = Slope*x + Y0;
710 //
711 // So you substitue line into Circle and apply
712 // Quadradic formula.
713
714
715 //slope of the focus-current line
716 slope = (Y - focusY) / (X - focusX);
717
718 yintcpt = Y - (slope * X); //y-intercept of that same line
719
720 //use the quadratic formula to calculate the intersection
721 //point
722 A = (slope * slope) + 1;
723
724 B = precalc3 + (-2 * slope * (centerY - yintcpt));
725
726 C = constC + (yintcpt* (yintcpt - precalc2));
727
728 det = Math.sqrt((B * B) - ( 4 * A * C));
729
730 solutionX = -B;
731
732 //choose the positive or negative root depending
733 //on where the X coord lies with respect to the focus.
734 solutionX += (X < focusX)?-det:det;
735
736 solutionX = solutionX / (2 * A);//divisor
737
738 solutionY = (slope * solutionX) + yintcpt;
739 }
740
741 //calculate the square of the distance from the current point
742 //to the focus and the square of the distance from the
743 //intersection point to the focus. Want the squares so we can
744 //do 1 square root after division instead of 2 before.
745 deltaXSq = solutionX - focusX;
746 deltaXSq = deltaXSq * deltaXSq;
747
748 deltaYSq = solutionY - focusY;
749 deltaYSq = deltaYSq * deltaYSq;
750
751 intersectToFocusSq = deltaXSq + deltaYSq;
752
753 deltaXSq = X - focusX;
754 deltaXSq = deltaXSq * deltaXSq;
755
756 deltaYSq = Y - focusY;
757 deltaYSq = deltaYSq * deltaYSq;
758
759 currentToFocusSq = deltaXSq + deltaYSq;
760 g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq);
761 prevGs[i] = g11;
762
763 //Get the color at this point
764 pixels[indexer+i] = indexGradientAntiAlias
765 ((float)((g00+g01+g10+g11)/4),
766 (float)Math.max(Math.abs(g11-g00),
767 Math.abs(g10-g01)));
768
769 X += a00; //incremental change in X, Y
770 Y += a10;
771 } //end inner loop
772 indexer += (w+adjust);
773 } //end outer loop
774 }
775}
Note: See TracBrowser for help on using the repository browser.