/* 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.transform; import org.jwildfire.base.Property; import org.jwildfire.base.mathlib.MathLib; import org.jwildfire.base.mathparser.JEPWrapper; import org.jwildfire.image.WFImage; import org.nfunk.jep.Node; import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor; public class ParPlot3DTransformer extends Mesh3DTransformer { public enum Preset { NONE, PRESET01, PRESET02, PRESET03, PRESET04, PRESET05, PRESET06, PRESET07, PRESET08, PRESET09, PRESET10, PRESET11, PRESET12 } @Property(description = "Minimum of the U-range") private double uMin; @Property(description = "Maximum of the U-range") private double uMax; @Property(description = "Minimum of the V-range") private double vMin; @Property(description = "Maximum of the V-range") private double vMax; @Property(description = "Formula(u,v) for the X-coordinate") private String xFormula; @Property(description = "Formula(u,v) for the Y-coordinate") private String yFormula; @Property(description = "Formula(u,v) for the Z-coordinate") private String zFormula; @Property(description = "Built-in preset", editorClass = PresetEditor.class) private Preset preset; @Property(description = "Scale factor for source z amplitude") private double zScale; @Override protected void transformMesh(Mesh3D pMesh3D, int pImageWidth, int pImageHeight) { initPreset(); int pCount = pMesh3D.getPCount(); int width = pImageWidth; int height = pImageHeight; double x[] = pMesh3D.getX(); double y[] = pMesh3D.getY(); double z[] = pMesh3D.getZ(); JEPWrapper parser = new JEPWrapper(); parser.addVariable("u", 0.0); parser.addVariable("v", 0.0); Node xNode = parser.parse(xFormula); Node yNode = parser.parse(yFormula); Node zNode = parser.parse(zFormula); // Don't calculate the actual bounding box because this may cause unexpected results if the object was deformed by another tansformer before double objUMin = -(double) width / 2.0; // double objXMax = (double) width / 2.0; double objVMin = -(double) height / 2.0; // double objYMax = (double) height / 2.0; double objUSize = (double) width; double objVSize = (double) height; double du = this.uMax - this.uMin; double dv = this.vMax - this.vMin; double xMin = 0.0, yMin = 0.0, zMin = 0.0; double xMax = 0.0, yMax = 0.0, zMax = 0.0; double oriZMin = 0.0, oriZMax = 0.0; for (int i = 0; i < pCount; i++) { if (z[i] < oriZMin) oriZMin = z[i]; else if (z[i] > oriZMax) oriZMax = z[i]; } double oriZSize = oriZMax - oriZMin; double oriZScale = oriZSize / Math.sqrt(width * width + height * height); for (int i = 0; i < pCount; i++) { double zz = oriZSize > MathLib.EPSILON ? z[i] / oriZSize * oriZScale : 0.0; double uu = ((x[i] - objUMin) * du) / objUSize + uMin; double vv = ((y[i] - objVMin) * dv) / objVSize + vMin; parser.setVarValue("u", uu); parser.setVarValue("v", vv); x[i] = (Double) parser.evaluate(xNode) * (1 + zz * this.zScale); if (x[i] < xMin) xMin = x[i]; else if (x[i] > xMax) xMax = x[i]; y[i] = (Double) parser.evaluate(yNode) * (1 + zz * this.zScale); if (y[i] < yMin) yMin = y[i]; else if (y[i] > yMax) yMax = y[i]; z[i] = (Double) parser.evaluate(zNode) * (1 + zz * this.zScale); if (z[i] < zMin) zMin = z[i]; else if (z[i] > zMax) zMax = z[i]; } double xSize = xMax - xMin; if (xSize < MathLib.EPSILON) xSize = MathLib.EPSILON; double ySize = yMax - yMin; if (ySize < MathLib.EPSILON) ySize = MathLib.EPSILON; double zSize = zMax - zMin; if (zSize < MathLib.EPSILON) zSize = MathLib.EPSILON; double xScl = (double) width / xSize; double yScl = (double) height / ySize; double zScl = Math.sqrt(width * width + height * height) / zSize; for (int i = 0; i < pCount; i++) { x[i] *= xScl; y[i] *= yScl; z[i] *= zScl; } } private void initPreset() { switch (preset) { case PRESET01: uMin = 0.0; uMax = 2.0 * Math.PI; vMin = 0.0; vMax = 2.0 * Math.PI; xFormula = "cos(u)*(4+cos(v))"; yFormula = "sin(u)*(4+cos(v))"; zFormula = "4*sin(2*u)+sin(v)*(1.2-sin(v))"; break; case PRESET02: uMin = 0.0; uMax = Math.PI; vMin = 0.0; vMax = Math.PI; xFormula = "cos(v)*sin(2*u)"; yFormula = "sin(v)*sin(2*u)"; zFormula = "sin(2*v)*(cos(u))^2"; break; case PRESET03: uMin = 0.0; uMax = 5 * Math.PI; vMin = 0.0; vMax = 2 * Math.PI; xFormula = "cos(u)*(exp(u/10)-1)*(cos(v)+0.8)"; yFormula = "sin(u)*(exp(u/10)-1)*(cos(v)+0.8)"; zFormula = "(exp(u/10)-1)*sin(v)"; break; case PRESET04: uMin = 0.0; uMax = 2 * Math.PI; vMin = 0.0; vMax = 2 * Math.PI; xFormula = "cos(v)*(2+sin(u+v/3))"; yFormula = "sin(v)*(2+sin(u+v/3))"; zFormula = "cos(u+v/3)"; break; case PRESET05: uMin = 0.0; uMax = 2.0 * Math.PI; vMin = 0.0; vMax = 2.0 * Math.PI; xFormula = "cos(u)*(2+cos(v))"; yFormula = "sin(u)*(2+cos(v))"; zFormula = "sin(v)"; break; case PRESET06: uMin = 0.0; uMax = 4.0 * Math.PI; vMin = 0.0; vMax = 2.0 * Math.PI; xFormula = "cos(u)*(2+cos(v))"; yFormula = "sin(u)*(2+cos(v))"; zFormula = "(u-2*pi)+sin(v)"; break; case PRESET07: uMin = 0.0; uMax = Math.PI; vMin = 0.0; vMax = 2.0 * Math.PI; xFormula = "u*cos(v)"; yFormula = "u*sin(v)"; zFormula = "(cos(4*u))^2*exp(0-u)"; break; case PRESET08: uMin = 0.0 - Math.PI; uMax = Math.PI; vMin = 0.0 - Math.PI; vMax = 2.0 * Math.PI; xFormula = "cos(u)*(2+(cos(u/2))^2*sin(v))"; yFormula = "sin(u)*(2+(cos(u/2))^2*sin(v))"; zFormula = "(cos(u/2))^2*cos(v)"; break; case PRESET09: uMin = 0.0; uMax = 2.0 * Math.PI; vMin = 0.0; vMax = 2.0 * Math.PI; xFormula = "cos(u)*(4+cos(v))"; yFormula = "sin(u)*(4+cos(v))"; zFormula = "3*sin(u)+(sin(3*v)*(1.2+sin(3*v)))"; break; case PRESET10: uMin = 0.0 - Math.PI; uMax = Math.PI; vMin = 0.0 - Math.PI; vMax = Math.PI; xFormula = "u*cos(v)"; yFormula = "v*cos(u)"; zFormula = "u*v*sin(u)*sin(v)"; break; case PRESET11: uMin = 0.0; uMax = 2.0 * Math.PI; vMin = 0.0; vMax = Math.PI; xFormula = "cos(u)*sin(v^3/(3.1415926^2))"; yFormula = "sin(u)*sin(v)"; zFormula = "cos(v)"; break; case PRESET12: uMin = 0.0; uMax = 2.0 * Math.PI; vMin = 0.0; vMax = 2.0 * Math.PI; xFormula = "cos(u)*((cos(3*u)+2)*sin(v)+0.5)"; yFormula = "sin(u)*((cos(3*u)+2)*sin(v)+0.5)"; zFormula = "(cos(3*u)+2)*cos(v)"; break; default: // nothing to do break; } } @Override public void initDefaultParams(WFImage pImg) { super.initDefaultParams(pImg); alpha = 10; beta = 20.0; zoom = 0.5; faces = Faces.DOUBLE; preset = Preset.NONE; zScale = 1.0; uMin = 0.0; uMax = 2 * Math.PI; vMin = 0.0; vMax = 2 * Math.PI; xFormula = "cos(v)*(2+sin(u+v/3))"; yFormula = "sin(v)*(2+sin(u+v/3))"; zFormula = "cos(u+v/3)"; } public double getUMin() { return uMin; } public void setUMin(double uMin) { this.uMin = uMin; } public double getUMax() { return uMax; } public void setUMax(double uMax) { this.uMax = uMax; } public double getVMin() { return vMin; } public void setVMin(double vMin) { this.vMin = vMin; } public double getVMax() { return vMax; } public void setVMax(double vMax) { this.vMax = vMax; } public String getXFormula() { return xFormula; } public void setXFormula(String xFormula) { this.xFormula = xFormula; } public String getYFormula() { return yFormula; } public void setYFormula(String yFormula) { this.yFormula = yFormula; } public String getZFormula() { return zFormula; } public void setZFormula(String zFormula) { this.zFormula = zFormula; } public static class PresetEditor extends ComboBoxPropertyEditor { public PresetEditor() { super(); setAvailableValues(new Preset[] { Preset.NONE, Preset.PRESET01, Preset.PRESET02, Preset.PRESET03, Preset.PRESET04, Preset.PRESET05, Preset.PRESET06, Preset.PRESET07, Preset.PRESET08, Preset.PRESET09, Preset.PRESET10, Preset.PRESET11, Preset.PRESET12 }); } } public Preset getPreset() { return preset; } public void setPreset(Preset preset) { this.preset = preset; } public double getZScale() { return zScale; } public void setZScale(double zScale) { this.zScale = zScale; } }