rsidwell icon

FiveFoldFunc.java

rsidwell | PRO | 10/05/17 02:15:59 AM UTC | 0 ⭐ | 754 👁️ | Never ⏰ | []
Java |

12.97 KB

|

None

|

0 👍

/

0 👎

/*
  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