/*
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.
*/
package org.jwildfire.create.tina.variation;
import static org.jwildfire.base.mathlib.MathLib.sin;
import static org.jwildfire.base.mathlib.MathLib.cos;
import static org.jwildfire.base.mathlib.MathLib.fmod;
import static org.jwildfire.base.mathlib.MathLib.M_PI;
import static org.jwildfire.base.mathlib.MathLib.M_2PI;
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;
public class FiveFoldFunc extends VariationFunc {
private static final long serialVersionUID = 1L;
private static final String PARAM_T = "t";
private static final String PARAM_COL1 = "col1";
private static final String PARAM_COL2 = "col2";
private static final String PARAM_ON = "on";
private static final String PARAM_ITT = "itt";
private static final String PARAM_EQ = "eq";
private static final String PARAM_DEPTH = "depth";
private static final String PARAM_ON1 = "on1";
private static final String PARAM_ITT1 = "itt1";
private static final String PARAM_EQ1 = "eq1";
private static final String PARAM_DEPTH1 = "depth1";
private static final String PARAM_ON2 = "on2";
private static final String PARAM_ITT2 = "itt2";
private static final String PARAM_EQ2 = "eq2";
private static final String PARAM_DEPTH2 = "depth2";
private static final String[] paramNames = { PARAM_T, PARAM_COL1, PARAM_COL2, PARAM_ON, PARAM_ITT, PARAM_EQ, PARAM_DEPTH,
PARAM_ON1, PARAM_ITT1, PARAM_EQ1, PARAM_DEPTH1, PARAM_ON2, PARAM_ITT2, PARAM_EQ2, PARAM_DEPTH2 };
private int t = 2;
private double col1 = Math.round(Math.random() * 35 + 10) / 100.0, col2 = Math.round(Math.random() * 35 + 55) / 100.0;
private double on = Math.round(Math.random()), on1 = Math.round(Math.random()), on2 = Math.round(Math.random());
private int itt = (int) (Math.random() * 5 + 1), itt1 = (int) (Math.random() * 5), itt2 = (int) (Math.random() * 5);
private int eq = (int) (Math.random() * 2 + 1), eq1 = (int) (Math.random() * 2 + 1), eq2 = (int) (Math.random() * 2 + 1);
private int depth = (int) (Math.random() * 4), depth1 = (int) (Math.random() * 4), depth2 = (int) (Math.random() * 4);
private class triangle {
int type;
double x1, y1, x2, y2, x3, y3;
double col;
public void assign(triangle t) {
type = t.type; col = t.col;
x1 = t.x1; y1 = t.y1;
x2 = t.x2; y2 = t.y2;
x3 = t.x3; y3 = t.y3;
}
private void triBlur(XYZPoint p) {
double u, v, v1, v2, w, x, x0, x1, x2, x3, x4, x5, x6, y, y0, y1, y2, y3, y4, y5, y6;
if (this.x1 <= this.x2 && this.x1 <= this.x3) {
if (this.x2 <= this.x3) {
x1 = this.x1; y1 = this.y1;
x2 = this.x2; y2 = this.y2;
x3 = this.x3; y3 = this.y3;
}
else {
x1 = this.x1; y1 = this.y1;
x2 = this.x3; y2 = this.y3;
x3 = this.x2; y3 = this.y2;
}
}
else if (this.x2 <= this.x1 && this.x2 <= this.x3){
if (this.x1 <= this.x3) {
x1 = this.x2; y1 = this.y2;
x2 = this.x1; y2 = this.y1;
x3 = this.x3; y3 = this.y3;
}
else {
x1 = this.x2; y1 = this.y2;
x2 = this.x3; y2 = this.y3;
x3 = this.x1; y3 = this.y1;
}
}
else {
if (this.x1 <= this.x2) {
x1 = this.x3; y1 = this.y3;
x2 = this.x1; y2 = this.y1;
x3 = this.x2; y3 = this.y2;
}
else {
x1 = this.x3; y1 = this.y3;
x2 = this.x2; y2 = this.y2;
x3 = this.x1; y3 = this.y1;
}
}
double r1 = genRand.random(), r2 = genRand.random();
if (x1 == x2 && x2 == x3) {
u = x1;
if (y1 <= y2 && y1 <= y3) {
v1 = y1;
v2 = (y3 > y2) ? y2 : y3;
}
else if (y2 <= y1 && y2 <= y3) {
v1 = y2;
v2 = (y3 > y1) ? y1 : y3;
}
else {
v1 = y3;
v2 = (y2 > y1) ? y1 : y2;
}
v = v1 + r1 * (v2 - v1);
}
else if (x1 == x2) {
x4 = (x1 + x3) / 2; y4 = (y1 + y3) / 2;
x5 = x3 + x2 - x4; y5 = y3 + y2 - y4;
x6 = x1 + x2 - x4; y6 = y1 + y2 - y4;
x = x3 + r1 * (x4 - x3); y = y3 + r1 * (y4 - y3);
x0 = x5 + r1 * (x2 - x5); y0 = y5 + r1 * (y2 - y5);
u = x + r2 * (x0 - x); v = y + r2 * (y0 - y);
w = y3 + (y2 - y3) / (x2 - x3) * (u - x3);
if (y2 > y3 + (y3 - y1) / (x3 - x1) * (x2 - x3)) {
if (v > w) {
x = x4 + r1 * (x1 - x4); y = y4 + r1 * (y1 - y4);
x0 = x2 + r1 * (x6 - x2); y0 = y2 + r1 * (y6 - y2);
u = x0 + r2 * (x - x0); v = y0 + r2 * (y - y0);
}
}
else {
if (v < w) {
x = x4 + r1 * (x1 - x4); y = y4 + r1 * (y1 - y4);
x0 = x2 + r1 * (x6 - x2); y0 = y2 + r1 * (y6 - y2);
u = x0 + r2 * (x - x0); v = y0 + r2 * (y - y0);
}
}
}
else {
x4 = (x1 + x3) / 2; y4 = (y1 + y3) / 2;
x5 = x1 + x2 - x4; y5 = y1 + y2 - y4;
x6 = x3 + x2 - x4; y6 = y3 + y2 - y4;
x = x1 + r1 * (x4 - x1); y = y1 + r1 * (y4 - y1);
x0 = x5 + r1 * (x2 - x5); y0 = y5 + r1 * (y2 - y5);
u = x + r2 * (x0 - x); v = y + r2 * (y0 - y);
w = y1 + (y2 - y1) / (x2 - x1) * (u - x1);
if (y2 > y1 + (y3 - y1) / (x3 - x1) * (x2 - x1)) {
if (v > w) {
x = x4 + r1 * (x3 - x4); y = y4 + r1 * (y3 - y4);
x0 = x2 + r1 * (x6 - x2); y0 = y2 + r1 * (y6 - y2);
u = x0 + r2 * (x - x0); v = y0 + r2 * (y - y0);
}
}
else {
if (v < w) {
x = x4 + r1 * (x3 - x4); y = y4 + r1 * (y3 - y4);
x0 = x2 + r1 * (x6 - x2); y0 = y2 + r1 * (y6 - y2);
u = x0 + r2 * (x - x0); v = y0 + r2 * (y - y0);
}
}
}
if (x1 == x2 && y1 == y2) {
u = x1 + r1 * (x3 - x1); v = y1 + r1 * (y3 - y1);
}
if (x1 == x3 && y1 == y3) {
u = x1 + r1 * (x2 - x1); v = y1 + r1 * (y2 - y1);
}
if (x2 == x3 && y2 == y3) {
u = x1 + r1 * (x2 - x1); v = y1 + r1 * (y2 - y1);
}
p.x = u;
p.y = v;
p.z = 0;
}
}
private triangle orig, t1, t2;
private XYZPoint p;
private double alfa;
AbstractRandomGenerator genRand;
private double discretNoise(int x) {
int n = x;
n = (n << 13) ^ n;
return ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / (double) 0x7fffffff;
}
private void fiveFoldDevis(triangle in, triangle out) {
double x4, y4, x5, y5;
double w;
switch (in.type) {
case 1:
x4 = in.x2 + alfa * (in.x3 - in.x2); y4 = in.y2 + alfa * (in.y3 - in.y2);
w = genRand.random();
if (w < alfa*alfa) {
out.type = 1; out.col = col1;
out.x1 = in.x3; out.y1 = in.y3;
out.x2 = in.x1; out.y2 = in.y1;
out.x3 = x4; out.y3 = y4;
}
else {
out.type = 2; out.col = col2;
out.x1 = in.x2; out.y1 = in.y2;
out.x2 = x4; out.y2 = y4;
out.x3 = in.x1; out.y3 = in.y1;
}
break;
case 2:
x4 = in.x3 + alfa * (in.x1 - in.x3); y4 = in.y3 + alfa * (in.y1 - in.y3);
x5 = in.x3 + alfa * (in.x2 - in.x3); y5 = in.y3 + alfa * (in.y2 - in.y3);
w = genRand.random();
if (w < alfa*alfa) {
out.type = 2; out.col = col2;
out.x1 = in.x2; out.y1 = in.y2;
out.x2 = x4; out.y2 = y4;
out.x3 = in.x1; out.y3 = in.y1;
}
else if (w < 2*alfa*alfa) {
out.type = 2; out.col = col2;
out.x1 = in.x3; out.y1 = in.y3;
out.x2 = x5; out.y2 = y5;
out.x3 = x4; out.y3 = y4;
}
else {
out.type = 1; out.col = col1;
out.x1 = in.x2; out.y1 = in.y2;
out.x2 = x4; out.y2 = y4;
out.x3 = x5; out.y3 = y5;
}
break;
}
}
@Override
public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) {
orig = new triangle();
switch (t) {
case 1:
orig.type = 1; orig.col = col1;
orig.x1 = 0.0; orig.y1 = 0.0;
orig.x2 = cos(M_2PI/5); orig.y2 = sin(M_2PI/5);
orig.x3 = 2 * orig.x2; orig.y3 = 0.0;
break;
case 2:
orig.type = 2; orig.col = col2;
orig.x1 = 0.0; orig.y1 = 0.0;
orig.x2 = cos(M_PI/5); orig.y2 = sin(M_PI/5);
orig.x3 = 2 * orig.x2; orig.y3 = 0.0;
break;
}
alfa = 2*cos(M_2PI/5);
genRand = pContext.getRandGen();
t1 = new triangle();
t2 = new triangle();
p = new XYZPoint();
}
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
/* FiveFold by eralex61, https://eralex61.deviantart.com/art/Five-fold-example-of-finite-recurent-system-in-Apo-705813367 */
t1.assign(orig);
t2.assign(orig);
int n = itt;
int k = 1;
while (n > 0) {
fiveFoldDevis(t1, t2);
t1.assign(t2);
if (on < 0.5) {
if ((k == itt) && (t1.type != eq)) n = n + depth;
}
else {
if ((k >= itt) && (k < itt + depth) && (t1.type != eq)) n = n + 1;
}
n = n - 1;
k = k + 1;
}
int m = 0;
switch (t1.type) {
case 1:
n = itt1;
k = 1;
while (n > 0) {
fiveFoldDevis(t1, t2);
t1.assign(t2);
m = 2 * m + t2.type - 1;
if (on1 < 0.5) {
if ((k == itt1) && (t1.type != eq1)) n = n + depth1;
}
else {
if ((k >= itt1) && (k < itt1 + depth1) && (t1.type != eq1)) n = n + 1;
}
n = n - 1;
k = k + 1;
}
t1.col = discretNoise(m+43);
break;
case 2:
n = itt2;
k = 1;
while (n > 0) {
fiveFoldDevis(t1, t2);
t1.assign(t2);
m = 2 * m + t2.type - 1;
if (on2 < 0.5) {
if ((k == itt2) && (t1.type != eq2)) n = n + depth2;
}
else {
if ((k >= itt2) && (k < itt2 + depth2) && (t1.type != eq2)) n = n + 1;
}
n = n - 1;
k = k + 1;
}
t1.col = discretNoise(m+31);
break;
}
t2.triBlur(p);
pVarTP.x += pAmount * p.x;
pVarTP.y += pAmount * p.y;
pVarTP.z += pAmount * p.z;
pVarTP.color = fmod(t1.col + t2.col, 1.0);
if (pVarTP.color < 0.0) pVarTP.color += 1.0;
}
@Override
public String[] getParameterNames() {
return paramNames;
}
@Override
public Object[] getParameterValues() {
return new Object[] { t, col1, col2, on, itt, eq, depth, on1, itt1, eq1, depth1, on2, itt2, eq2, depth2 };
}
@Override
public String[] getParameterAlternativeNames() {
return new String[] { "FiveFold_T", "FiveFold_Col1", "FiveFold_Col2", "FiveFold_On", "FiveFold_Itt", "FiveFold_Eq", "FiveFold_Depth", "FiveFold_On1", "FiveFold_Itt1", "FiveFold_Eq1", "FiveFold_Depth1", "FiveFold_On2", "FiveFold_Itt2", "FiveFold_Eq2", "FiveFold_Depth2" };
}
@Override
public void setParameter(String pName, double pValue) {
if (PARAM_ON.equalsIgnoreCase(pName))
on = pValue;
else if (PARAM_COL1.equalsIgnoreCase(pName))
col1 = pValue;
else if (PARAM_COL2.equalsIgnoreCase(pName))
col2 = pValue;
else if (PARAM_T.equalsIgnoreCase(pName))
t = Tools.FTOI(pValue);
else if (PARAM_ITT.equalsIgnoreCase(pName))
itt = Tools.FTOI(pValue);
else if (PARAM_EQ.equalsIgnoreCase(pName))
eq = Tools.FTOI(pValue);
else if (PARAM_DEPTH.equalsIgnoreCase(pName))
depth = Tools.FTOI(pValue);
else if (PARAM_ON1.equalsIgnoreCase(pName))
on1 = pValue;
else if (PARAM_ITT1.equalsIgnoreCase(pName))
itt1 = Tools.FTOI(pValue);
else if (PARAM_EQ1.equalsIgnoreCase(pName))
eq1 = Tools.FTOI(pValue);
else if (PARAM_DEPTH1.equalsIgnoreCase(pName))
depth1 = Tools.FTOI(pValue);
else if (PARAM_ON2.equalsIgnoreCase(pName))
on2 = pValue;
else if (PARAM_ITT2.equalsIgnoreCase(pName))
itt2 = Tools.FTOI(pValue);
else if (PARAM_EQ2.equalsIgnoreCase(pName))
eq2 = Tools.FTOI(pValue);
else if (PARAM_DEPTH2.equalsIgnoreCase(pName))
depth2 = Tools.FTOI(pValue);
else
throw new IllegalArgumentException(pName);
}
@Override
public String getName() {
return "fiveFold";
}
}
Comments