Package org.jwildfire.create.tina.variation

Source Code of org.jwildfire.create.tina.variation.Onion2Func

/*
  JWildfire - an image and animation processor written in Java
  Copyright (C) 1995-2011 Andreas Maschke

  Variation created by Nicolaus Anderson, 2013
  Under the same license.
 
  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.M_PI;
import static org.jwildfire.base.mathlib.MathLib.cos;
import static org.jwildfire.base.mathlib.MathLib.exp;
import static org.jwildfire.base.mathlib.MathLib.sin;
import static org.jwildfire.base.mathlib.MathLib.tan;

import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.base.XYZPoint;

/**
* @author Nicolaus Anderson
*/
public class Onion2Func extends VariationFunc {
  private static final long serialVersionUID = 1L;

  private static final String PN_MEETING_PT = "meeting_pt";
  private static final String PN_CIRCLE_A = "circle_a";
  private static final String PN_CIRCLE_B = "circle_b";
  private static final String PN_SHIFT_X = "shift_x";
  private static final String PN_SHIFT_Y = "shift_y";
  private static final String PN_SHIFT_Z = "shift_z";
  private static final String PN_TOP_CROP = "top_crop";
  private static final String PN_STRETCH = "stretch";

  private static final String[] params = {
      PN_MEETING_PT,
      PN_CIRCLE_A, PN_CIRCLE_B,
      PN_SHIFT_X, PN_SHIFT_Y, PN_SHIFT_Z,
      PN_TOP_CROP,
      PN_STRETCH
  };

  private double meetingPt = 0.5;
  private double circle_a = 1.0;
  private double circle_b = 1.0;
  private double shift_x = 0.0;
  private double shift_y = 0.0;
  private double shift_z = 0.0;
  private double top_crop = 0.0;
  private double stretch = 1.0;

  @Override
  public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
    /* Description:
     The transform creates a shape similar to an onion by starting with a circle
     and smoothly transitioning to a (negative) exponential function. In this case,
     they meet where exp(x) has a slope of 1.
     To make the function spherical, the point's x and y values are treated as a
     radius and become "t". The circle and exponential function are then formed
     from parametric equations, where "t" is the same "t" from the original point's
     x and y values.
     These equations are as follows:
     circle: xp=cos(t), yp=sin(t) (or r=cos(t), z=sin(t))
     exponential: xp=cos(t), yp=exp(s) (or r=cos(t), z=exp(s))
     where "s" represents a shifted "t" value so as to aline the exponential
     function with the circle.
    
     The slope of the circle:
     dyp/dxp = cos(t)dt/-sin(t)dt = -cot(t)
     Thus, cot(t) becomes the coefficient on exp(x) so as to make the slopes the
     same. However, this requires a y-axis realignment of cot(t) instead of 1
     in addition to a shift in the y-axis to bring exp(t) to meet with the circle.
     y-axis-shift = sin(t) - cot(t)
    
     This value of "t" - where the circle and exponential function meet - is
     called "m", and it is a user-set variable.
     Thus, the shifts for exp(s) are:
     x-axis shift = cos(m)
     y-axis shift = sin(m) - cot(m)
    
     Final exponential equation:
     xp = cos(t)
     yp = cot(t)*exp( -xp + cos(m) ) + sin(m) - cot(m)

     NOTE: xp is made negative instead of cot(t) so as to perform the desired
     mirror in parametric space.
    */

    // Initial coordinates
    XYZPoint ini = new XYZPoint();
    ini.x = pAffineTP.x;
    ini.y = pAffineTP.y;
    ini.z = pAffineTP.z;
    ini.x -= shift_x;
    ini.y -= shift_y;
    //ini.z -= shift_z;
    ini.invalidate();

    // Final coordinates in parametric space
    double r;
    double z;

    /* Convert x and y of point to parametric space,
     noting they are the radius outward in real space. */
    double t = ini.getPrecalcSqrt() / stretch - M_PI / 2;

    /* NOTE: "t" and "meetingPt" are in radians */

    if (t > meetingPt) {
      // exponential curve
      r = cos(t);
      if (tan(meetingPt) != 0.0) {
        z = exp(cos(meetingPt) - r) / tan(meetingPt)
            + sin(meetingPt)
            - 1 / tan(meetingPt);

        if (z > top_crop && top_crop > 0) { /* FIX ADDED. top_crop could start at -1 for cropping below middle. */
          z = top_crop;
          r = 0;
        }
      }
      else {
        z = top_crop;
      }
    }
    else {
      // circular curve
      r = cos(t);
      z = sin(t);
    }
    // Expand radius of onion
    r *= circle_a * pAmount;
    z *= circle_b * pAmount;

    // Convert parametric space (2D) back to real space (3D)
    /* A new coordinate equals the new factor times a unit vector in the
     direction of the coordinate of interest. */
    pVarTP.x += r * (ini.x / ini.getPrecalcSqrt());
    pVarTP.y += r * (ini.y / ini.getPrecalcSqrt());
    pVarTP.z += z;

    if (pContext.isPreserveZCoordinate()) {
      // (this should cause positive z values to curl inside the onion)

      /* Treating z as a vector that is split into two components, one being
       an x-component of parametric space which becomes a new radius for
       real space, taking into account conversion through unit vectors */
      pVarTP.x += r * ini.z * (ini.x / ini.getPrecalcSqrt());
      pVarTP.y += r * ini.z * (ini.y / ini.getPrecalcSqrt());

      /* The z-component is a normalized value from the parametric space y
       (which is real space z), taking into account the amount that went into
       the x component. */
      pVarTP.z += ini.z * z / (r * r + z * z);
    }

    pVarTP.x += shift_x;
    pVarTP.y += shift_y;
    //pVarTP.z += shift_z;
  }

  @Override
  public String getName() {
    return "onion2";
  }

  @Override
  public String[] getParameterNames() {
    return params;
  }

  @Override
  public Object[] getParameterValues() {
    return new Object[] {
        meetingPt,
        circle_a,
        circle_b,
        shift_x,
        shift_y,
        shift_z,
        top_crop,
        stretch
    };
  }

  @Override
  public void setParameter(String pName, double pValue) {

    if (PN_MEETING_PT.equalsIgnoreCase(pName)) {
      meetingPt = pValue;
    }
    else if (PN_CIRCLE_A.equalsIgnoreCase(pName)) {
      circle_a = pValue;
    }
    else if (PN_CIRCLE_B.equalsIgnoreCase(pName)) {
      circle_b = pValue;
    }
    else if (PN_SHIFT_X.equalsIgnoreCase(pName)) {
      shift_x = pValue;
    }
    else if (PN_SHIFT_Y.equalsIgnoreCase(pName)) {
      shift_y = pValue;
    }
    else if (PN_SHIFT_Z.equalsIgnoreCase(pName)) {
      shift_z = pValue;
    }
    else if (PN_TOP_CROP.equalsIgnoreCase(pName)) {
      top_crop = pValue;
    }
    else if (PN_STRETCH.equalsIgnoreCase(pName)) {
      if (pValue > 0.0)
        stretch = pValue;
    }
    else
      throw new IllegalArgumentException(pName);
  }
}
TOP

Related Classes of org.jwildfire.create.tina.variation.Onion2Func

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.