Previously I presented some Newton Fractal ruby-processing sketches. Here is an example using vanilla processing:-
int imgx = 512;
int imgy = 512;
JComplex z;
JComplex COMPLEX = new JComplex(1.0E-6, 1.0E-6);
PImage img;
//Drawing area
float xa = -4.0;
float xb = 4.0;
float ya = -4.0;
float yb = 4.0;
int maxIt = 20; // max iterations allowed
float EPS = 1.0E-3; // max error allowed
JComplex func(JComplex z) {
return z.mul(z.pow(3.0).div(6.0).sub(1.0));
}
void settings() {
size(imgx, imgy);
}
void setup() {
img = createImage(imgx, imgy, RGB);
img.loadPixels();
for (int y = 0; y < imgy; y++) {
float zy = y*(yb - ya)/(imgy - 1) + ya;
for (int x = 0; x < imgx; x++) {
float zx = x*(xb - xa)/(imgx - 1) + xa;
z = new JComplex(zx, zy);
for (int i = 0; i < maxIt; i++) {
// Complex numerical derivative
JComplex dz = func(z.add(COMPLEX)).sub(func(z)).div(COMPLEX);
JComplex z0 = z.sub(func(z).div(dz));
if (z0.sub(z).abs2() < EPS * EPS) {
break;
}
z = z0;
img.pixels[x + y * img.width] = color(i%5*64, i%17*16, i%9*32);
}
}
}
noLoop();
}
void draw() {
image(img, 0, 0, img.width, img.height);
}
Here is the java class (just put it the processing ide)
import java.util.Objects;
// Code includes some ideas from
// commons.apache.org/proper/commons-math/userguide/complex.html
public final class JComplex {
private final double re; // the real part
private final double im; // the imaginary part
private final static JComplex ZERO = new JComplex(0, 0);
private final static JComplex NAN = new JComplex(Double.NaN, Double.NaN);
/**
* create a new object with the given real and imaginary parts
*
* @param real
* @param imag
*/
public JComplex(double real, double imag) {
re = real;
im = imag;
}
/**
* @return a string representation of the invoking Complex object
*/
@Override
public String toString() {
return "JComplex(" + re + ", " + im + "i)";
}
/**
*
* @return abs/modulus/magnitude
*/
public final double abs() {
return Math.hypot(re, im);
}
/**
*
* @return square of abs/modulus/magnitude
*/
public final double abs2() {
return re * re + im * im;
}
/**
*
* @return angle/phase/argument, normalized to be between -pi and pi
*/
public final double phase() {
return Math.atan2(im, re);
}
/**
*
* @param b
* @return a new Complex object whose value is (this + b)
*/
public final JComplex add(JComplex b) {
JComplex a = this; // invoking object
double real = a.re + b.re;
double imag = a.im + b.im;
return new JComplex(real, imag);
}
/**
*
* @param scalar
* @return a new Complex object whose value is (this + scalar)
*/
public final JComplex add(double scalar) {
return new JComplex(re + scalar, im);
}
public final boolean zero() {
return this.equals(ZERO);
}
/**
*
* @param b
* @return a new Complex object whose value is (this - b)
*/
public final JComplex sub(JComplex b) {
JComplex a = this;
double real = a.re - b.re;
double imag = a.im - b.im;
return new JComplex(real, imag);
}
/**
*
* @param scalar
* @return a new Complex object whose value is (this - scalar)
*/
public final JComplex sub(double scalar) {
return new JComplex(re - scalar, im);
}
/**
*
* @param b
* @return a new Complex object whose value is (this * b)
*/
public final JComplex mul(JComplex b) {
JComplex a = this;
double real = a.re * b.re - a.im * b.im;
double imag = a.re * b.im + a.im * b.re;
return new JComplex(real, imag);
}
/**
* Also known as scale
*
* @param b
* @return a new Complex object whose value is (this * b)
*/
public final JComplex mul(double b) {
return new JComplex(re * b, im * b);
}
/**
*
* @return a new Complex object whose value is the conjugate of this
*/
public final JComplex conjugate() {
return new JComplex(re, -im);
}
/**
*
* @return a new Complex object whose value is the reciprocal of this
*/
private JComplex reciprocal() {
double scale = re * re + im * im; // self dot product
return new JComplex(re / scale, -im / scale);
}
/**
*
* @param other
* @return this^other
*/
public final JComplex pow(JComplex other) {
if (this.zero()) {
if (other.zero()) {
return ZERO;
}
return NAN;
}
return (this).log().mul(other).exp();
}
/**
*
* @param scalar
* @return this^scalar
*/
public final JComplex pow(double scalar) {
if (this.zero()) {
if (scalar == 0) {
return ZERO;
}
return NAN;
}
return (this).log().mul(scalar).exp();
}
/**
*
* @return log
*/
private JComplex log() {
return new JComplex(Math.log(abs()), Math.atan2(im, re));
}
/**
*
* @return real part
*/
public final double re() {
return re;
}
/**
*
* @return imaginary part
*/
public final double im() {
return im;
}
/**
*
* @param b
* @return a / b
*/
public final JComplex div(JComplex b) {
JComplex a = this;
return a.mul(b.reciprocal());
}
/**
*
* @param b
* @return a / b
*/
public final JComplex div(double b) {
if (b == 0) {
return NAN;
}
return new JComplex(re / b, im / b);
}
/**
*
* @return a new Complex object whose value is the complex exponential of
* this
*/
public final JComplex exp() {
return new JComplex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im));
}
@Override
public final int hashCode() {
return Objects.hash(re, im);
}
@Override
public final boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final JComplex other = (JComplex) obj;
if (Double.doubleToLongBits(this.re) != Double.doubleToLongBits(other.re)) {
return false;
}
return Double.doubleToLongBits(this.im) == Double.doubleToLongBits(other.im);
}
}