/*
* JAME 6.2.1
* http://jame.sourceforge.net
*
* Copyright 2001, 2016 Andrea Medeghini
*
* This file is part of JAME.
*
* JAME is an application for creating fractals and other graphics artifacts.
*
* JAME is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JAME is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JAME. If not, see <http://www.gnu.org/licenses/>.
*
*/
package net.sf.jame.mandelbrot.extensions.renderingFormula;
import java.util.ArrayList;
import java.util.List;
import net.sf.jame.core.math.Complex;
import net.sf.jame.mandelbrot.orbitTrap.extension.OrbitTrapExtensionRuntime;
import net.sf.jame.mandelbrot.processingFormula.extension.ProcessingFormulaExtensionRuntime;
import net.sf.jame.mandelbrot.renderer.RenderedPoint;
/**
* @author Andrea Medeghini
*/
public class ZNRuntime extends AbstractRenderingFormulaRuntime<ZNConfig> {
private static final int GUARD_VALUE = 1000;
private final Complex p2 = new Complex(0, 0);
private final Complex p4 = new Complex(0, 0);
private final Complex p8 = new Complex(0, 0);
private final Complex p16 = new Complex(0, 0);
private final Complex t = new Complex(0, 0);
private final Complex z = new Complex(0, 0);
private final Complex x = new Complex(0, 0);
private final Complex w = new Complex(0, 0);
private int exponent;
/**
* @see net.sf.jame.mandelbrot.extensions.renderingFormula.AbstractRenderingFormulaRuntime#prepareForRendering(net.sf.jame.mandelbrot.processingFormula.extension.ProcessingFormulaExtensionRuntime, net.sf.jame.mandelbrot.orbitTrap.extension.OrbitTrapExtensionRuntime)
*/
@Override
public void prepareForRendering(final ProcessingFormulaExtensionRuntime formulaRuntime, final OrbitTrapExtensionRuntime<?> orbitTrapRuntime) {
super.prepareForRendering(formulaRuntime, orbitTrapRuntime);
exponent = Math.abs(getExponent());
}
/**
* @return the exponent.
*/
public int getExponent() {
return getConfig().getExponent();
}
/**
* @see net.sf.jame.mandelbrot.extensions.renderingFormula.AbstractRenderingFormulaRuntime#isHorizontalSymetryAllowed()
*/
@Override
public boolean isHorizontalSymetryAllowed() {
return (exponent % 2 != 0);
}
/**
* @see net.sf.jame.mandelbrot.extensions.renderingFormula.AbstractRenderingFormulaRuntime#isVerticalSymetryAllowed()
*/
@Override
public boolean isVerticalSymetryAllowed() {
if (formulaRuntime != null) {
return false;
}
if (orbitTrapRuntime != null) {
return false;
}
return true;
}
/**
* @see net.sf.jame.mandelbrot.renderingFormula.extension.RenderingFormulaExtensionRuntime#renderPoint(net.sf.jame.mandelbrot.renderer.RenderedPoint)
*/
@Override
public int renderPoint(final RenderedPoint cp) {
if (formulaRuntime != null) {
formulaRuntime.prepareForProcessing();
}
x.r = cp.xr;
x.i = cp.xi;
w.r = cp.wr;
w.i = cp.wi;
cp.time = 0;
for (int k = 1; k <= iterations; k++) {
Complex.mul(p2, x, x);
int e = exponent;
z.r = 1;
z.i = 0;
if (e > 3) {
Complex.mul(p4, p2, p2);
if (e > 7) {
Complex.mul(p8, p4, p4);
if (e > 15) {
Complex.mul(p16, p8, p8);
final int d16 = e / 16;
for (int i = 0; i < d16; i++) {
Complex.mul(t, z, p16);
z.r = t.r;
z.i = t.i;
}
e = e % 16;
}
final int d8 = e / 8;
for (int i = 0; i < d8; i++) {
Complex.mul(t, z, p8);
z.r = t.r;
z.i = t.i;
}
e = e % 8;
}
final int d4 = e / 4;
for (int i = 0; i < d4; i++) {
Complex.mul(t, z, p4);
z.r = t.r;
z.i = t.i;
}
e = e % 4;
}
final int d2 = e / 2;
for (int i = 0; i < d2; i++) {
Complex.mul(t, z, p2);
z.r = t.r;
z.i = t.i;
}
e = e % 2;
for (int i = 0; i < e; i++) {
Complex.mul(t, z, x);
z.r = t.r;
z.i = t.i;
}
Complex.add(z, z, w);
cp.zr = z.r;
cp.zi = z.i;
if (formulaRuntime != null) {
formulaRuntime.processPoint(cp);
}
if (orbitTrapRuntime != null) {
if (orbitTrapRuntime.processPoint(cp)) {
cp.time = k;
break;
}
}
else {
if (Complex.mod(z) > threshold) {
cp.time = k;
break;
}
}
x.r = cp.zr;
x.i = cp.zi;
if ((x.r > GUARD_VALUE) || (x.i > GUARD_VALUE)) {
cp.time = k;
break;
}
}
if (formulaRuntime != null) {
formulaRuntime.renderPoint(cp);
}
else {
if (orbitTrapRuntime != null) {
orbitTrapRuntime.renderPoint(cp);
}
}
return cp.time;
}
/**
* @see net.sf.jame.mandelbrot.renderingFormula.extension.RenderingFormulaExtensionRuntime#renderOrbit(net.sf.jame.mandelbrot.renderer.RenderedPoint)
*/
@Override
public List<Complex> renderOrbit(final RenderedPoint cp) {
final ArrayList<Complex> orbit = new ArrayList<Complex>();
final Complex p2 = new Complex(0, 0);
final Complex p4 = new Complex(0, 0);
final Complex p8 = new Complex(0, 0);
final Complex p16 = new Complex(0, 0);
final Complex t = new Complex(0, 0);
final Complex z = new Complex(0, 0);
final Complex x = new Complex(cp.xr, cp.xi);
final Complex w = new Complex(cp.wr, cp.wi);
cp.time = 0;
for (int k = 1; k <= iterations; k++) {
Complex.mul(p2, x, x);
int e = exponent;
z.r = 1;
z.i = 0;
if (e > 3) {
Complex.mul(p4, p2, p2);
if (e > 7) {
Complex.mul(p8, p4, p4);
if (e > 15) {
Complex.mul(p16, p8, p8);
final int d16 = e / 16;
for (int i = 0; i < d16; i++) {
Complex.mul(t, z, p16);
z.r = t.r;
z.i = t.i;
}
e = e % 16;
}
final int d8 = e / 8;
for (int i = 0; i < d8; i++) {
Complex.mul(t, z, p8);
z.r = t.r;
z.i = t.i;
}
e = e % 8;
}
final int d4 = e / 4;
for (int i = 0; i < d4; i++) {
Complex.mul(t, z, p4);
z.r = t.r;
z.i = t.i;
}
e = e % 4;
}
final int d2 = e / 2;
for (int i = 0; i < d2; i++) {
Complex.mul(t, z, p2);
z.r = t.r;
z.i = t.i;
}
e = e % 2;
for (int i = 0; i < e; i++) {
Complex.mul(t, z, x);
z.r = t.r;
z.i = t.i;
}
Complex.add(z, z, w);
cp.zr = z.r;
cp.zi = z.i;
orbit.add(new Complex(z.r, z.i));
if (orbitTrapRuntime != null) {
if (orbitTrapRuntime.processPoint(cp)) {
cp.time = k;
break;
}
}
else {
if (Complex.mod(z) > threshold) {
cp.time = k;
break;
}
}
x.r = z.r;
x.i = z.i;
if ((x.r > GUARD_VALUE) || (x.i > GUARD_VALUE)) {
cp.time = k;
break;
}
}
return orbit;
}
/**
* @see net.sf.jame.mandelbrot.renderingFormula.extension.RenderingFormulaExtensionRuntime#getNormalizedIterationCount(net.sf.jame.mandelbrot.renderer.RenderedPoint)
*/
@Override
public double getNormalizedIterationCount(final RenderedPoint cp) {
final double modulus = Math.sqrt((cp.zr * cp.zr) + (cp.zi * cp.zi));
// return cp.time + 1d - Math.log(Math.log(modulus)) / Math.log(exponent);
return cp.time + (Math.log(Math.log(threshold)) - Math.log(Math.log(modulus))) / Math.log(exponent);
}
}