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