summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/kitfox/svg/batik/RadialGradientPaintContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/kitfox/svg/batik/RadialGradientPaintContext.java')
-rw-r--r--src/main/java/com/kitfox/svg/batik/RadialGradientPaintContext.java775
1 files changed, 775 insertions, 0 deletions
diff --git a/src/main/java/com/kitfox/svg/batik/RadialGradientPaintContext.java b/src/main/java/com/kitfox/svg/batik/RadialGradientPaintContext.java
new file mode 100644
index 0000000..5b097fd
--- /dev/null
+++ b/src/main/java/com/kitfox/svg/batik/RadialGradientPaintContext.java
@@ -0,0 +1,775 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package com.kitfox.svg.batik;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+/**
+ * Provides the actual implementation for the RadialGradientPaint.
+ * This is where the pixel processing is done. A RadialGradienPaint
+ * only supports circular gradients, but it should be possible to scale
+ * the circle to look approximately elliptical, by means of a
+ * gradient transform passed into the RadialGradientPaint constructor.
+ *
+ * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ * @version $Id: RadialGradientPaintContext.java,v 1.2 2005/10/12 20:36:55 kitfox Exp $
+ *
+ */
+final class RadialGradientPaintContext extends MultipleGradientPaintContext {
+
+ /** True when (focus == center) */
+ private boolean isSimpleFocus = false;
+
+ /** True when (cycleMethod == NO_CYCLE) */
+ private boolean isNonCyclic = false;
+
+ /** Radius of the outermost circle defining the 100% gradient stop. */
+ private float radius;
+
+ /** Variables representing center and focus points. */
+ private float centerX, centerY, focusX, focusY;
+
+ /** Radius of the gradient circle squared. */
+ private float radiusSq;
+
+ /** Constant part of X, Y user space coordinates. */
+ private float constA, constB;
+
+ /** This value represents the solution when focusX == X. It is called
+ * trivial because it is easier to calculate than the general case.
+ */
+ private float trivial;
+
+ private static final int FIXED_POINT_IMPL = 1;
+ private static final int DEFAULT_IMPL = 2;
+ private static final int ANTI_ALIAS_IMPL = 3;
+
+ private int fillMethod;
+
+ /** Amount for offset when clamping focus. */
+ private static final float SCALEBACK = .97f;
+
+ /**
+ * Constructor for RadialGradientPaintContext.
+ *
+ * @param cm {@link ColorModel} that receives
+ * the <code>Paint</code> data. This is used only as a hint.
+ *
+ * @param deviceBounds the device space bounding box of the
+ * graphics primitive being rendered
+ *
+ * @param userBounds the user space bounding box of the
+ * graphics primitive being rendered
+ *
+ * @param t the {@link AffineTransform} from user
+ * space into device space (gradientTransform should be
+ * concatenated with this)
+ *
+ * @param hints the hints that the context object uses to choose
+ * between rendering alternatives
+ *
+ * @param cx the center point in user space of the circle defining
+ * the gradient. The last color of the gradient is mapped to the
+ * perimeter of this circle X coordinate
+ *
+ * @param cy the center point in user space of the circle defining
+ * the gradient. The last color of the gradient is mapped to the
+ * perimeter of this circle Y coordinate
+ *
+ * @param r the radius of the circle defining the extents of the
+ * color gradient
+ *
+ * @param fx the point in user space to which the first color is mapped
+ * X coordinate
+ *
+ * @param fy the point in user space to which the first color is mapped
+ * Y coordinate
+ *
+ * @param fractions the fractions specifying the gradient distribution
+ *
+ * @param colors the gradient colors
+ *
+ * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
+ *
+ * @param colorSpace which colorspace to use for interpolation,
+ * either SRGB or LINEAR_RGB
+ *
+ */
+ public RadialGradientPaintContext(ColorModel cm,
+ Rectangle deviceBounds,
+ Rectangle2D userBounds,
+ AffineTransform t,
+ RenderingHints hints,
+ float cx, float cy,
+ float r,
+ float fx, float fy,
+ float[] fractions,
+ Color[] colors,
+ MultipleGradientPaint.CycleMethodEnum
+ cycleMethod,
+ MultipleGradientPaint.ColorSpaceEnum
+ colorSpace)
+ throws NoninvertibleTransformException
+ {
+ super(cm, deviceBounds, userBounds, t, hints, fractions, colors,
+ cycleMethod, colorSpace);
+
+ //copy some parameters.
+ centerX = cx;
+ centerY = cy;
+ focusX = fx;
+ focusY = fy;
+ radius = r;
+
+ this.isSimpleFocus = (focusX == centerX) && (focusY == centerY);
+ this.isNonCyclic = (cycleMethod == RadialGradientPaint.NO_CYCLE);
+
+ //for use in the quadractic equation
+ radiusSq = radius * radius;
+
+ float dX = focusX - centerX;
+ float dY = focusY - centerY;
+
+ double dist = Math.sqrt((dX * dX) + (dY * dY));
+
+ //test if distance from focus to center is greater than the radius
+ if (dist > radius* SCALEBACK) { //clamp focus to radius
+ double angle = Math.atan2(dY, dX);
+
+ //x = r cos theta, y = r sin theta
+ focusX = (float)(SCALEBACK * radius * Math.cos(angle)) + centerX;
+
+ focusY = (float)(SCALEBACK * radius * Math.sin(angle)) + centerY;
+ }
+
+ //calculate the solution to be used in the case where X == focusX
+ //in cyclicCircularGradientFillRaster
+ dX = focusX - centerX;
+ trivial = (float)Math.sqrt(radiusSq - (dX * dX));
+
+ // constant parts of X, Y user space coordinates
+ constA = a02 - centerX;
+ constB = a12 - centerY;
+
+ Object colorRend;
+ Object rend;
+ //hints can be null on Mac OSX
+ if (hints == null)
+ {
+ colorRend = RenderingHints.VALUE_COLOR_RENDER_DEFAULT;
+ rend = RenderingHints.VALUE_RENDER_DEFAULT;
+ }
+ else
+ {
+ colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING);
+ rend = hints.get(RenderingHints.KEY_RENDERING);
+ }
+
+ fillMethod = 0;
+
+ if ((rend == RenderingHints.VALUE_RENDER_QUALITY) ||
+ (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY)) {
+ // System.out.println("AAHints set: " + rend + ", " + colorRend);
+ fillMethod = ANTI_ALIAS_IMPL;
+ }
+
+ if ((rend == RenderingHints.VALUE_RENDER_SPEED) ||
+ (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED)) {
+ // System.out.println("SPHints set: " + rend + ", " + colorRend);
+ fillMethod = DEFAULT_IMPL;
+ }
+
+ // We are in the 'default' case, no hint or hint set to
+ // DEFAULT values...
+ if (fillMethod == 0) {
+ // For now we will always use the 'default' impl if
+ // one is not specified.
+ fillMethod = DEFAULT_IMPL;
+
+ if (false) {
+ // This could be used for a 'smart' choice in
+ // the default case, if the gradient has obvious
+ // discontinuites use AA, otherwise default
+ if (hasDiscontinuity) {
+ fillMethod = ANTI_ALIAS_IMPL;
+ } else {
+ fillMethod = DEFAULT_IMPL;
+ }
+ }
+ }
+
+ if ((fillMethod == DEFAULT_IMPL) &&
+ (isSimpleFocus && isNonCyclic && isSimpleLookup)) {
+ this.calculateFixedPointSqrtLookupTable();
+ fillMethod = FIXED_POINT_IMPL;
+ }
+ }
+
+ /**
+ * Return a Raster containing the colors generated for the graphics
+ * operation.
+ * @param x,y,w,h The area in device space for which colors are
+ * generated.
+ */
+ protected void fillRaster(int pixels[], int off, int adjust,
+ int x, int y, int w, int h) {
+ switch(fillMethod) {
+ case FIXED_POINT_IMPL:
+ // System.out.println("Calling FP");
+ fixedPointSimplestCaseNonCyclicFillRaster(pixels, off, adjust, x,
+ y, w, h);
+ break;
+ case ANTI_ALIAS_IMPL:
+ // System.out.println("Calling AA");
+ antiAliasFillRaster(pixels, off, adjust, x, y, w, h);
+ break;
+ case DEFAULT_IMPL:
+ default:
+ // System.out.println("Calling Default");
+ cyclicCircularGradientFillRaster(pixels, off, adjust, x, y, w, h);
+ }
+ }
+
+ /**
+ * This code works in the simplest of cases, where the focus == center
+ * point, the gradient is noncyclic, and the gradient lookup method is
+ * fast (single array index, no conversion necessary).
+ *
+ */
+ private void fixedPointSimplestCaseNonCyclicFillRaster(int pixels[],
+ int off,
+ int adjust,
+ int x, int y,
+ int w, int h) {
+ float iSq=0; // Square distance index
+ final float indexFactor = fastGradientArraySize / radius;
+
+ //constant part of X and Y coordinates for the entire raster
+ final float constX = (a00*x) + (a01*y) + constA;
+ final float constY = (a10*x) + (a11*y) + constB;
+ final float deltaX = indexFactor * a00; //incremental change in dX
+ final float deltaY = indexFactor * a10; //incremental change in dY
+ float dX, dY; //the current distance from center
+ final int fixedArraySizeSq=
+ (fastGradientArraySize * fastGradientArraySize);
+ float g, gDelta, gDeltaDelta, temp; //gradient square value
+ int gIndex; // integer number used to index gradient array
+ int iSqInt; // Square distance index
+
+ int end, j; //indexing variables
+ int indexer = off;//used to index pixels array
+
+ temp = ((deltaX * deltaX) + (deltaY * deltaY));
+ gDeltaDelta = ((temp * 2));
+
+ if (temp > fixedArraySizeSq) {
+ // This combination of scale and circle radius means
+ // essentially no pixels will be anything but the end
+ // stop color. This also avoids math problems.
+ final int val = gradientOverflow;
+ for(j = 0; j < h; j++){ //for every row
+ //for every column (inner loop begins here)
+ for (end = indexer+w; indexer < end; indexer++)
+ pixels[indexer] = val;
+ indexer += adjust;
+ }
+ return;
+ }
+
+ // For every point in the raster, calculate the color at that point
+ for(j = 0; j < h; j++){ //for every row
+ //x and y (in user space) of the first pixel of this row
+ dX = indexFactor * ((a01*j) + constX);
+ dY = indexFactor * ((a11*j) + constY);
+
+ // these values below here allow for an incremental calculation
+ // of dX^2 + dY^2
+
+ //initialize to be equal to distance squared
+ g = (((dY * dY) + (dX * dX)) );
+ gDelta = (((((deltaY * dY) + (deltaX * dX))* 2) +
+ temp));
+
+ //for every column (inner loop begins here)
+ for (end = indexer+w; indexer < end; indexer++) {
+ //determine the distance to the center
+
+ //since this is a non cyclic fill raster, crop at "1" and 0
+ if (g >= fixedArraySizeSq) {
+ pixels[indexer] = gradientOverflow;
+ }
+
+ // This should not happen as gIndex is a square
+ // quantity. Code commented out on purpose, can't underflow.
+ // else if (g < 0) {
+ // gIndex = 0;
+ // }
+
+ else {
+ iSq = (g * invSqStepFloat);
+
+ iSqInt = (int)iSq; //chop off fractional part
+ iSq -= iSqInt;
+ gIndex = sqrtLutFixed[iSqInt];
+ gIndex += (int)(iSq * (sqrtLutFixed[iSqInt + 1]-gIndex));
+ pixels[indexer] = gradient[gIndex];
+ }
+
+
+ //incremental calculation
+ g += gDelta;
+ gDelta += gDeltaDelta;
+ }
+ indexer += adjust;
+ }
+ }
+
+ /** Length of a square distance intervale in the lookup table */
+ private float invSqStepFloat;
+
+ /** Used to limit the size of the square root lookup table */
+ private int MAX_PRECISION = 256;
+
+ /** Square root lookup table */
+ private int sqrtLutFixed[] = new int[MAX_PRECISION];
+
+ /**
+ * Build square root lookup table
+ */
+ private void calculateFixedPointSqrtLookupTable() {
+ float sqStepFloat;
+ sqStepFloat = ((fastGradientArraySize * fastGradientArraySize)
+ / (MAX_PRECISION - 2));
+
+ // The last two values are the same so that linear square root
+ // interpolation can happen on the maximum reachable element in the
+ // lookup table (precision-2)
+ int i;
+ for (i = 0; i < MAX_PRECISION - 1; i++) {
+ sqrtLutFixed[i] = (int)(Math.sqrt(i*sqStepFloat));
+ }
+ sqrtLutFixed[i] = sqrtLutFixed[i-1];
+ invSqStepFloat = 1/sqStepFloat;
+ }
+
+ /** Fill the raster, cycling the gradient colors when a point falls outside
+ * of the perimeter of the 100% stop circle.
+ *
+ * This calculation first computes the intersection point of the line
+ * from the focus through the current point in the raster, and the
+ * perimeter of the gradient circle.
+ *
+ * Then it determines the percentage distance of the current point along
+ * that line (focus is 0%, perimeter is 100%).
+ *
+ * Equation of a circle centered at (a,b) with radius r:
+ * (x-a)^2 + (y-b)^2 = r^2
+ * Equation of a line with slope m and y-intercept b
+ * y = mx + b
+ * replacing y in the cirlce equation and solving using the quadratic
+ * formula produces the following set of equations. Constant factors have
+ * been extracted out of the inner loop.
+ *
+ */
+ private void cyclicCircularGradientFillRaster(int pixels[], int off,
+ int adjust,
+ int x, int y,
+ int w, int h) {
+ // Constant part of the C factor of the quadratic equation
+ final double constC =
+ -(radiusSq) + (centerX * centerX) + (centerY * centerY);
+ double A; //coefficient of the quadratic equation (Ax^2 + Bx + C = 0)
+ double B; //coefficient of the quadratic equation
+ double C; //coefficient of the quadratic equation
+ double slope; //slope of the focus-perimeter line
+ double yintcpt; //y-intercept of the focus-perimeter line
+ double solutionX;//intersection with circle X coordinate
+ double solutionY;//intersection with circle Y coordinate
+ final float constX = (a00*x) + (a01*y) + a02;//const part of X coord
+ final float constY = (a10*x) + (a11*y) + a12; //const part of Y coord
+ final float precalc2 = 2 * centerY;//const in inner loop quad. formula
+ final float precalc3 =-2 * centerX;//const in inner loop quad. formula
+ float X; // User space point X coordinate
+ float Y; // User space point Y coordinate
+ float g;//value between 0 and 1 specifying position in the gradient
+ float det; //determinant of quadratic formula (should always be >0)
+ float currentToFocusSq;//sq distance from the current pt. to focus
+ float intersectToFocusSq;//sq distance from the intersect pt. to focus
+ float deltaXSq; //temp variable for a change in X squared.
+ float deltaYSq; //temp variable for a change in Y squared.
+ int indexer = off; //index variable for pixels array
+ int i, j; //indexing variables for FOR loops
+ int pixInc = w+adjust;//incremental index change for pixels array
+
+ for (j = 0; j < h; j++) { //for every row
+
+ X = (a01*j) + constX; //constants from column to column
+ Y = (a11*j) + constY;
+
+ //for every column (inner loop begins here)
+ for (i = 0; i < w; i++) {
+
+ // special case to avoid divide by zero or very near zero
+ if (((X-focusX)>-0.000001) &&
+ ((X-focusX)< 0.000001)) {
+ solutionX = focusX;
+
+ solutionY = centerY;
+
+ solutionY += (Y > focusY)?trivial:-trivial;
+ }
+
+ else {
+
+ //slope of the focus-current line
+ slope = (Y - focusY) / (X - focusX);
+
+ yintcpt = Y - (slope * X); //y-intercept of that same line
+
+ //use the quadratic formula to calculate the intersection
+ //point
+ A = (slope * slope) + 1;
+
+ B = precalc3 + (-2 * slope * (centerY - yintcpt));
+
+ C = constC + (yintcpt* (yintcpt - precalc2));
+
+ det = (float)Math.sqrt((B * B) - ( 4 * A * C));
+
+ solutionX = -B;
+
+ //choose the positive or negative root depending
+ //on where the X coord lies with respect to the focus.
+ solutionX += (X < focusX)?-det:det;
+
+ solutionX = solutionX / (2 * A);//divisor
+
+ solutionY = (slope * solutionX) + yintcpt;
+ }
+
+ //calculate the square of the distance from the current point
+ //to the focus and the square of the distance from the
+ //intersection point to the focus. Want the squares so we can
+ //do 1 square root after division instead of 2 before.
+
+ deltaXSq = (float)solutionX - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = (float)solutionY - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ intersectToFocusSq = deltaXSq + deltaYSq;
+
+ deltaXSq = X - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = Y - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ currentToFocusSq = deltaXSq + deltaYSq;
+
+ //want the percentage (0-1) of the current point along the
+ //focus-circumference line
+ g = (float)Math.sqrt(currentToFocusSq / intersectToFocusSq);
+
+ //Get the color at this point
+ pixels[indexer + i] = indexIntoGradientsArrays(g);
+
+ X += a00; //incremental change in X, Y
+ Y += a10;
+ } //end inner loop
+ indexer += pixInc;
+ } //end outer loop
+ }
+
+
+ /** Fill the raster, cycling the gradient colors when a point
+ * falls outside of the perimeter of the 100% stop circle. Use
+ * the anti-aliased gradient lookup.
+ *
+ * This calculation first computes the intersection point of the line
+ * from the focus through the current point in the raster, and the
+ * perimeter of the gradient circle.
+ *
+ * Then it determines the percentage distance of the current point along
+ * that line (focus is 0%, perimeter is 100%).
+ *
+ * Equation of a circle centered at (a,b) with radius r:
+ * (x-a)^2 + (y-b)^2 = r^2
+ * Equation of a line with slope m and y-intercept b
+ * y = mx + b
+ * replacing y in the cirlce equation and solving using the quadratic
+ * formula produces the following set of equations. Constant factors have
+ * been extracted out of the inner loop.
+ * */
+ private void antiAliasFillRaster(int pixels[], int off,
+ int adjust,
+ int x, int y,
+ int w, int h) {
+ // Constant part of the C factor of the quadratic equation
+ final double constC =
+ -(radiusSq) + (centerX * centerX) + (centerY * centerY);
+ //coefficients of the quadratic equation (Ax^2 + Bx + C = 0)
+ final float precalc2 = 2 * centerY;//const in inner loop quad. formula
+ final float precalc3 =-2 * centerX;//const in inner loop quad. formula
+
+ //const part of X,Y coord (shifted to bottom left corner of pixel.
+ final float constX = (a00*(x-.5f)) + (a01*(y+.5f)) + a02;
+ final float constY = (a10*(x-.5f)) + (a11*(y+.5f)) + a12;
+ float X; // User space point X coordinate
+ float Y; // User space point Y coordinate
+ int i, j; //indexing variables for FOR loops
+ int indexer = off-1; //index variable for pixels array
+
+ // Size of a pixel in user space.
+ double pixSzSq = (float)(a00*a00+a01*a01+a10*a10+a11*a11);
+ double [] prevGs = new double[w+1];
+ double deltaXSq, deltaYSq;
+ double solutionX, solutionY;
+ double slope, yintcpt, A, B, C, det;
+ double intersectToFocusSq, currentToFocusSq;
+ double g00, g01, g10, g11;
+
+ // Set X,Y to top left corner of first pixel of first row.
+ X = constX - a01;
+ Y = constY - a11;
+
+ // Calc top row of g's.
+ for (i=0; i <= w; i++) {
+ // special case to avoid divide by zero or very near zero
+ if (((X-focusX)>-0.000001) &&
+ ((X-focusX)< 0.000001)) {
+ solutionX = focusX;
+ solutionY = centerY;
+ solutionY += (Y > focusY)?trivial:-trivial;
+ }
+ else {
+ // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0
+ // Formula line: Y = Slope*x + Y0;
+ //
+ // So you substitue line into Circle and apply
+ // Quadradic formula.
+
+
+ //slope of the focus-current line
+ slope = (Y - focusY) / (X - focusX);
+
+ yintcpt = Y - (slope * X); //y-intercept of that same line
+
+ //use the quadratic formula to calculate the intersection
+ //point
+ A = (slope * slope) + 1;
+
+ B = precalc3 + (-2 * slope * (centerY - yintcpt));
+
+ C = constC + (yintcpt* (yintcpt - precalc2));
+
+ det = Math.sqrt((B * B) - ( 4 * A * C));
+
+ solutionX = -B;
+
+ //choose the positive or negative root depending
+ //on where the X coord lies with respect to the focus.
+ solutionX += (X < focusX)?-det:det;
+
+ solutionX = solutionX / (2 * A);//divisor
+
+ solutionY = (slope * solutionX) + yintcpt;
+ }
+
+ //calculate the square of the distance from the current point
+ //to the focus and the square of the distance from the
+ //intersection point to the focus. Want the squares so we can
+ //do 1 square root after division instead of 2 before.
+ deltaXSq = solutionX - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = solutionY - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ intersectToFocusSq = deltaXSq + deltaYSq;
+
+ deltaXSq = X - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = Y - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ currentToFocusSq = deltaXSq + deltaYSq;
+
+ //want the percentage (0-1) of the current point along the
+ //focus-circumference line
+ prevGs[i] = Math.sqrt(currentToFocusSq / intersectToFocusSq);
+
+ X += a00; //incremental change in X, Y
+ Y += a10;
+ }
+
+ for (j = 0; j < h; j++) { //for every row
+
+ // Set X,Y to bottom edge of pixel row.
+ X = (a01*j) + constX; //constants from row to row
+ Y = (a11*j) + constY;
+
+ g10 = prevGs[0];
+ // special case to avoid divide by zero or very near zero
+ if (((X-focusX)>-0.000001) &&
+ ((X-focusX)< 0.000001)) {
+ solutionX = focusX;
+ solutionY = centerY;
+ solutionY += (Y > focusY)?trivial:-trivial;
+ }
+ else {
+ // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0
+ // Formula line: Y = Slope*x + Y0;
+ //
+ // So you substitue line into Circle and apply
+ // Quadradic formula.
+
+
+ //slope of the focus-current line
+ slope = (Y - focusY) / (X - focusX);
+
+ yintcpt = Y - (slope * X); //y-intercept of that same line
+
+ //use the quadratic formula to calculate the intersection
+ //point
+ A = (slope * slope) + 1;
+
+ B = precalc3 + (-2 * slope * (centerY - yintcpt));
+
+ C = constC + (yintcpt* (yintcpt - precalc2));
+
+ det = Math.sqrt((B * B) - ( 4 * A * C));
+
+ solutionX = -B;
+
+ //choose the positive or negative root depending
+ //on where the X coord lies with respect to the focus.
+ solutionX += (X < focusX)?-det:det;
+
+ solutionX = solutionX / (2 * A);//divisor
+
+ solutionY = (slope * solutionX) + yintcpt;
+ }
+
+ //calculate the square of the distance from the current point
+ //to the focus and the square of the distance from the
+ //intersection point to the focus. Want the squares so we can
+ //do 1 square root after division instead of 2 before.
+ deltaXSq = solutionX - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = solutionY - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ intersectToFocusSq = deltaXSq + deltaYSq;
+
+ deltaXSq = X - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = Y - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ currentToFocusSq = deltaXSq + deltaYSq;
+ g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq);
+ prevGs[0] = g11;
+
+ X += a00; //incremental change in X, Y
+ Y += a10;
+
+ //for every column (inner loop begins here)
+ for (i=1; i <= w; i++) {
+ g00 = g10;
+ g01 = g11;
+ g10 = prevGs[i];
+
+ // special case to avoid divide by zero or very near zero
+ if (((X-focusX)>-0.000001) &&
+ ((X-focusX)< 0.000001)) {
+ solutionX = focusX;
+ solutionY = centerY;
+ solutionY += (Y > focusY)?trivial:-trivial;
+ }
+ else {
+ // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0
+ // Formula line: Y = Slope*x + Y0;
+ //
+ // So you substitue line into Circle and apply
+ // Quadradic formula.
+
+
+ //slope of the focus-current line
+ slope = (Y - focusY) / (X - focusX);
+
+ yintcpt = Y - (slope * X); //y-intercept of that same line
+
+ //use the quadratic formula to calculate the intersection
+ //point
+ A = (slope * slope) + 1;
+
+ B = precalc3 + (-2 * slope * (centerY - yintcpt));
+
+ C = constC + (yintcpt* (yintcpt - precalc2));
+
+ det = Math.sqrt((B * B) - ( 4 * A * C));
+
+ solutionX = -B;
+
+ //choose the positive or negative root depending
+ //on where the X coord lies with respect to the focus.
+ solutionX += (X < focusX)?-det:det;
+
+ solutionX = solutionX / (2 * A);//divisor
+
+ solutionY = (slope * solutionX) + yintcpt;
+ }
+
+ //calculate the square of the distance from the current point
+ //to the focus and the square of the distance from the
+ //intersection point to the focus. Want the squares so we can
+ //do 1 square root after division instead of 2 before.
+ deltaXSq = solutionX - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = solutionY - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ intersectToFocusSq = deltaXSq + deltaYSq;
+
+ deltaXSq = X - focusX;
+ deltaXSq = deltaXSq * deltaXSq;
+
+ deltaYSq = Y - focusY;
+ deltaYSq = deltaYSq * deltaYSq;
+
+ currentToFocusSq = deltaXSq + deltaYSq;
+ g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq);
+ prevGs[i] = g11;
+
+ //Get the color at this point
+ pixels[indexer+i] = indexGradientAntiAlias
+ ((float)((g00+g01+g10+g11)/4),
+ (float)Math.max(Math.abs(g11-g00),
+ Math.abs(g10-g01)));
+
+ X += a00; //incremental change in X, Y
+ Y += a10;
+ } //end inner loop
+ indexer += (w+adjust);
+ } //end outer loop
+ }
+}