/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2011 Andreas Maschke
This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This software 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this software;
if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
// Variation Plugin DLL for Apophysis
// Jed Kelsey, 20 June 2007
package org.jwildfire.create.tina.variation;
import java.util.ArrayList;
import java.util.List;
import org.jwildfire.base.Tools;
import org.jwildfire.create.tina.base.Layer;
import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.base.XYZPoint;
import org.jwildfire.create.tina.random.AbstractRandomGenerator;
import org.jwildfire.create.tina.random.MarsagliaRandomGenerator;
public class MandelbrotFunc extends VariationFunc {
private static final long serialVersionUID = 1L;
private static final String PARAM_ITER = "iter";
private static final String PARAM_XMIN = "xmin";
private static final String PARAM_XMAX = "xmax";
private static final String PARAM_YMIN = "ymin";
private static final String PARAM_YMAX = "ymax";
private static final String PARAM_INVERT = "invert";
private static final String PARAM_SKIN = "skin";
private static final String PARAM_CX = "cx";
private static final String PARAM_CY = "cy";
private static final String PARAM_MAX_POINTS = "max_points";
private static final String PARAM_SEED = "seed";
private static final String PARAM_RND_Z_RANGE = "rnd_z_range";
private static final String[] paramNames = { PARAM_ITER, PARAM_XMIN, PARAM_XMAX, PARAM_YMIN, PARAM_YMAX, PARAM_INVERT, PARAM_SKIN, PARAM_CX, PARAM_CY, PARAM_MAX_POINTS, PARAM_SEED, PARAM_RND_Z_RANGE };
private int iter = 100;
private double xmin = -1.6;
private double xmax = 1.6;
private double ymin = -1.2;
private double ymax = 1.2;
private int invert = 0;
private double skin = 0;
private double cx = 0.0;
private double cy = 0.0;
private int max_points = -1;
private int seed = 1234;
private double rnd_z_range = 0.0;
private AbstractRandomGenerator randGen;
private int _pIdx = 0;
private List<Double> xP = new ArrayList<Double>();
private List<Double> yP = new ArrayList<Double>();
private List<Double> zP = new ArrayList<Double>();
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
double x1 = _x0;
double x = _x0;
double y1 = _y0;
double y = _y0;
int currIter;
boolean inverted = randGen.random() < this.invert;
if (inverted) {
currIter = 0;
}
else {
currIter = iter;
}
while ((inverted && (currIter < iter)) ||
((!inverted) && ((currIter >= iter) ||
((skin < 1) && (currIter < 0.1 * iter * (1 - skin)))))) {
if ((_x0 == 0) && (_y0 == 0)) {
// Choose a point at random
if (max_points > 0) {
if (xP.size() >= max_points) {
_x0 = xP.get(_pIdx);
_y0 = yP.get(_pIdx++);
_z0 = zP.get(_pIdx++);
if (_pIdx >= max_points) {
_pIdx = 0;
}
}
else {
_x0 = (xmax - xmin) * randGen.random() + xmin;
_y0 = (ymax - ymin) * randGen.random() + ymin;
_z0 = randGen.random() * rnd_z_range;
xP.add(_x0);
yP.add(_y0);
zP.add(_z0);
}
}
else {
_x0 = (xmax - xmin) * randGen.random() + xmin;
_y0 = (ymax - ymin) * randGen.random() + ymin;
_z0 = randGen.random() * rnd_z_range;
}
}
else {
// Choose a point close to previous point
_x0 = (skin + 0.001) * (randGen.random() - 0.5) + _x0;
_y0 = (skin + 0.001) * (randGen.random() - 0.5) + _y0;
// _z0 = (skin + 0.001) * (randGen.random() - 0.5) + _z0;
}
x1 = _x0;
y1 = _y0;
x = _x0;
y = _y0;
currIter = 0;
while (((x * x + y * y < 2 * 2) && (currIter < iter))) {
double xtemp = x * x - y * y + _x0;
y = 2.0 * x * y + _y0;
x = xtemp;
currIter++;
}
if ((currIter >= iter) || (skin == 1) || (currIter < 0.1 * (iter * (1 - skin)))) {
// Random point next time
_x0 = 0;
_y0 = 0;
}
}
pVarTP.x += pAmount * (x1 + cx * x); // + FTx^;
pVarTP.y += pAmount * (y1 + cy * y); // + FTy^;
pVarTP.z += _z0;
}
@Override
public String[] getParameterNames() {
return paramNames;
}
@Override
public Object[] getParameterValues() {
return new Object[] { iter, xmin, xmax, ymin, ymax, invert, skin, cx, cy, max_points, seed, rnd_z_range };
}
@Override
public void setParameter(String pName, double pValue) {
if (PARAM_ITER.equalsIgnoreCase(pName))
iter = Tools.FTOI(pValue);
else if (PARAM_XMIN.equalsIgnoreCase(pName))
xmin = pValue;
else if (PARAM_XMAX.equalsIgnoreCase(pName))
xmax = pValue;
else if (PARAM_YMIN.equalsIgnoreCase(pName))
ymin = pValue;
else if (PARAM_YMAX.equalsIgnoreCase(pName))
ymax = pValue;
else if (PARAM_INVERT.equalsIgnoreCase(pName))
invert = Tools.FTOI(pValue);
else if (PARAM_SKIN.equalsIgnoreCase(pName))
skin = pValue;
else if (PARAM_CX.equalsIgnoreCase(pName))
cx = pValue;
else if (PARAM_CY.equalsIgnoreCase(pName))
cy = pValue;
else if (PARAM_MAX_POINTS.equalsIgnoreCase(pName)) {
max_points = Tools.FTOI(pValue);
if (max_points > 0 && max_points < 100) {
max_points = 100;
}
}
else if (PARAM_SEED.equalsIgnoreCase(pName))
seed = Tools.FTOI(pValue);
else if (PARAM_RND_Z_RANGE.equalsIgnoreCase(pName))
rnd_z_range = pValue;
else
throw new IllegalArgumentException(pName);
}
@Override
public String getName() {
return "mandelbrot";
}
private double _x0, _y0, _z0;
@Override
public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) {
_x0 = _y0 = _z0 = 0.0;
xP.clear();
yP.clear();
zP.clear();
_pIdx = 0;
randGen = new MarsagliaRandomGenerator();
randGen.randomize(seed);
}
}