/* 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.fabs; import static org.jwildfire.base.mathlib.MathLib.pow; 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; public class CrobFunc extends VariationFunc { private static final long serialVersionUID = 1L; private static final String PARAM_TOP = "top"; private static final String PARAM_BOTTOM = "bottom"; private static final String PARAM_LEFT = "left"; private static final String PARAM_RIGHT = "right"; private static final String PARAM_BLUR = "blur"; private static final String PARAM_RATIOBLUR = "ratioBlur"; private static final String PARAM_DIRECTBLUR = "directBlur"; private static final String[] paramNames = { PARAM_TOP, PARAM_BOTTOM, PARAM_LEFT, PARAM_RIGHT, PARAM_BLUR, PARAM_RATIOBLUR, PARAM_DIRECTBLUR }; private double left = -1.0; private double top = -1.0; private double right = 1.0; private double bottom = 1.0; private int blur = 1; private double ratioblur = 0.05; private double directblur = 2.0; @Override public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) { // crob by FractalDesire, https://fractaldesire.deviantart.com/art/crob-plugin-260173724 double gradTmp, secTmp; double xTmp = pAffineTP.x; double yTmp = pAffineTP.y; if ((pAffineTP.x < left_border) || (pAffineTP.x > right_border) || (pAffineTP.y < top_border) || (pAffineTP.y > bottom_border)) { //***** Case: no edge ***** if (blur == 0) { xTmp = 0; yTmp = 0; } //***** Case: with edge ***** else { secTmp = pContext.random(); // ***** Drawing top and bottom ***** if (secTmp < setProb) { do { yTmp = top + pContext.random()*yInt_2; xTmp = right - pow(pContext.random(), directblur)*ratioblur*minInt_2; gradTmp = (yTmp - y0c)/(xTmp - x0c); } while (gradTmp < -1.0); if (secTmp < setProbH) xTmp = left + right - xTmp; if ((secTmp > setProbQ) && (secTmp < setProbTQ)) yTmp = bottom + top - yTmp; } // ***** Drawing left and right ***** else { do { xTmp = right - pContext.random()*xInt_2; yTmp = top + pow(pContext.random(), directblur)*ratioblur*minInt_2; gradTmp = (yTmp - y0c)/(xTmp - x0c); } while ((gradTmp <= 0.0) && (gradTmp > -1.0)); if (secTmp > setCompProbH) yTmp = bottom + top - yTmp; if ((secTmp > setCompProbQ) && (secTmp < setCompProbTQ)) xTmp = left + right - xTmp; } } } pVarTP.x += xTmp; pVarTP.y += yTmp; if (pContext.isPreserveZCoordinate()) { pVarTP.z += pAmount * pAffineTP.z; } } @Override public String[] getParameterNames() { return paramNames; } @Override public Object[] getParameterValues() { return new Object[] { top, bottom, left, right, blur, ratioblur, directblur }; } @Override public void setParameter(String pName, double pValue) { if (PARAM_LEFT.equalsIgnoreCase(pName)) left = pValue; else if (PARAM_RIGHT.equalsIgnoreCase(pName)) right = pValue; else if (PARAM_TOP.equalsIgnoreCase(pName)) top = pValue; else if (PARAM_BOTTOM.equalsIgnoreCase(pName)) bottom = pValue; else if (PARAM_BLUR.equalsIgnoreCase(pName)) blur = Tools.FTOI(pValue); else if (PARAM_RATIOBLUR.equalsIgnoreCase(pName)) ratioblur = pValue; else if (PARAM_DIRECTBLUR.equalsIgnoreCase(pName)) directblur = pValue; else throw new IllegalArgumentException(pName); } @Override public String getName() { return "crob"; } private double top_border, bottom_border, left_border, right_border; private double xInterval, yInterval, xInt_2, yInt_2, minInt_2; private double x0, y0, x0c, y0c; private double setProb, setProbH, setProbQ, setProbTQ, setCompProb, setCompProbH, setCompProbQ, setCompProbTQ; @Override public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) { double tmp; // ***** Preventing bad inputs ***** if (top > bottom) { tmp = top; top = bottom; bottom = tmp; } if (top == bottom) { top = -1.0; bottom = 1.0; } if (left > right) { tmp = left; left = right; right = tmp; } if (left == right) { left = -1.0; right = 1.0; } if (directblur < 0.0) directblur = 0.0; // ***** Initializing intervals ***** if (blur != 0) blur = 1; xInterval = fabs(right - left); yInterval = fabs(bottom - top); xInt_2 = xInterval/2.0; yInt_2 = yInterval/2.0; minInt_2 = (xInt_2 > yInt_2) ? yInt_2 : xInt_2; x0 = right - xInt_2; y0 = top + yInt_2; // ***** Initializing reference point ***** if (xInt_2 > yInt_2) { x0c = right - minInt_2; y0c = y0; } else if (xInt_2 < yInt_2) { x0c = x0; y0c = top + minInt_2; } else { x0c = x0; y0c = y0; } // ***** Initializing probabilities ***** setProb = yInterval / (xInterval + yInterval); setProbQ = 0.25 * setProb; setProbH = 0.50 * setProb; setProbTQ = 0.75 * setProb; setCompProb = 1.0 - setProb; setCompProbQ = setProb + 0.25 * setCompProb; setCompProbH = setProb + 0.50 * setCompProb; setCompProbTQ = setProb + 0.75 * setCompProb; // ***** Defining inner area ***** if (blur == 0) { top_border = top; bottom_border = bottom; left_border = left; right_border = right; } else { top_border = top + minInt_2 * ratioblur; bottom_border = bottom - minInt_2 * ratioblur; left_border = left + minInt_2 * ratioblur; right_border = right - minInt_2 * ratioblur; } } }