Select Git revision
Camera.java
Forked from
YAGOUBI Rim / Game of life Template
Source project has a limited visibility.
-
LABOUREL Arnaud authoredLABOUREL Arnaud authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Mandelbrot.java 3.93 KiB
package mandelbrot;
import java.util.function.Function;
/**
* A class to compute how fast a parameterized polynomial sequence diverges.
* This is used to compute the colors of point in the Mandelbrot fractal.
*/
public class Mandelbrot {
/**
* If a complex has modulus above <code>RADIUS</code>, we know that
* the sequence diverges. <code>RADIUS</code> should be at least 2 for
* the usual Mandelbrot sequence.
*/
private static final double RADIUS = 10;
/**
* The square of <code>RADIUS</code>, used in computations.
*/
private static final double RADIUS2 = RADIUS * RADIUS;
/**
* How many iterations of the sequence do we compute before concluding
* that it probably converges. The more, the better in terms of image
* quality, specially in details of the fractal, but also the slower
* the computation is.
*/
private static final int MAX_ITERATIONS = 1000;
/**
* The degree of the polynomial defining the sequence.
*/
private static final int DEGREE = 2;
/**
* Compute how divergent is the sequence generated by <code>z -> z ** 2 + c</code>
*
* @param c A complex parameter, defining the polynomial to use.
* @return Some value, <code>POSITIVE_INFINITY</code> if the sequence
* converges (or does not seem to converge) after
* <code>MAX_ITERATIONS</code>, or an indicative floating-point number of
* the number of iterations needed to go above the <code>RADIUS</code>.
*/
public double divergence(Complex c) {
if (isConvergent(c)) return Double.POSITIVE_INFINITY;
Function<Complex, Complex> f = z -> z.pow(DEGREE).add(c);
Sequence seq = new Sequence(c, f);
int countIterations = 0;
for (Complex z : seq) {
if (isDiverging(z))
return smoothIterationCount(countIterations, z);
if (countIterations >= MAX_ITERATIONS)
return Double.POSITIVE_INFINITY;
countIterations++;
}
return 0.;
}
/**
* This method is used to smooth the number of iterations until
* getting out of the <code>RADIUS</code>, so that we get a
* floating-point value and thus smooth coloring.
*
* @param countIterations the iteration on which <code>RADIUS</code> is beaten.
* @param z the first complex of the sequence whose modulus is above <code>RADIUS</code>
* @return a double close to <code>countIterations</code>.
*/
private double smoothIterationCount(int countIterations, Complex z) {
double x = Math.log(z.modulus()) / Math.log(RADIUS);
return (double) countIterations - Math.log(x) / Math.log(DEGREE);
}
/**
* Checks whether a term of the sequence is out of the given
* <code>RADIUS</code>, which guarantees that the sequence diverges.
*
* @param z a term of the sequence
* @return <code>true</code> if we are sure that the sequence diverges.
*/
private boolean isDiverging(Complex z) {
return z.squaredModulus() > RADIUS2;
}
/**
* Checks whether the parameter of the sequence is in some region
* that guarantees that the sequence is convergent. This does not
* capture all convergent parameters.
*
* @param c the parameter for the polynomial
* @return <code>true</code> if we are sure that the sequence converges.
*/
private boolean isConvergent(Complex c) {
return isIn2Bulb(c) || isInCardioid(c);
}
/* The cardioid black shape of the fractal */
private boolean isInCardioid(Complex z) {
double m = z.squaredModulus();
return Helpers.doubleCompare(m * (8 * m - 3), 3. / 32. - z.getReal()) <= 0;
}
/* The main black disc of the fractal */
private boolean isIn2Bulb(Complex z) {
Complex zMinusOne = z.subtract(new Complex(-1, 0));
return Helpers.doubleCompare(zMinusOne.squaredModulus(), 1. / 16.) < 0;
}
}