/*
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.PropertyCategory;
import org.jwildfire.base.PropertyMin;
import org.jwildfire.image.WFImage;
import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;
public class WaterTransformer extends Mesh3DTransformer {
public enum Axis {
X, Y, XY
};
@Property(description = "Wavelength of the wave")
@PropertyMin(0.0)
private double wavelength = 150.0;
@Property(description = "Amplitude of the wave")
@PropertyMin(0.0)
private double amplitude = 30.0;
@Property(description = "Damping of the wave", category = PropertyCategory.SECONDARY)
private double damping = -0.5;
@Property(description = "Damping on/off", category = PropertyCategory.SECONDARY)
private boolean damp = true;
@Property(description = "Number of frames to describe a complete phase", category = PropertyCategory.SECONDARY)
@PropertyMin(1)
private int frames = 60;
@Property(description = "Current frames", category = PropertyCategory.SECONDARY)
@PropertyMin(1)
private int frame = 33;
@Property(description = "X-coordinate of the wave origin")
private double originX = 400.0;
@Property(description = "Y-coordinate of the wave origin")
private double originY = 400.0;
@Property(description = "Propagation axis of the wave", editorClass = AxisEditor.class)
private Axis axis = Axis.XY;
@Property(description = "Number of rings", category = PropertyCategory.SECONDARY)
@PropertyMin(1)
private int rings = 3;
@Property(description = "How many times to emit", category = PropertyCategory.SECONDARY)
@PropertyMin(1)
private int times = 6;
@Property(description = "Activate movement in x- and y-direction", category = PropertyCategory.SECONDARY)
private boolean moveXY = true;
@Override
protected void transformMesh(Mesh3D pMesh3D, int pImageWidth, int pImageHeight) {
int pCount = pMesh3D.getPCount();
int width = pImageWidth;
int height = pImageHeight;
double x[] = pMesh3D.getX();
double y[] = pMesh3D.getY();
double z[] = pMesh3D.getZ();
double twoPi = 2.0 * Math.PI;
double centreX = this.originX - (double) width / 2;
double centreY = this.originY - (double) height / 2;
double amplitude = this.amplitude;
double wavelength = this.wavelength;
if (wavelength < 2.0)
wavelength = 2.0;
double damping = this.damping;
double times = this.times;
if (times < 1.0)
times = 1.0;
double limit;
double rings = this.rings;
if (rings >= 1.0)
limit = twoPi * rings;
else
limit = twoPi;
double am2 = this.amplitude / 2.0;
double dt = 1.0 / (double) frames;
double a0 = twoPi * dt * (frame + 1) * times;
double div1 = wavelength / twoPi;
double div2 = twoPi / wavelength;
double number = a0 * div1 - 1.0;
if (axis == Axis.XY) {
if (!damp) {
for (int i = 0; i < pCount; i++) {
double dx = x[i] - centreX;
double dy = y[i] - centreY;
double dr = Math.sqrt(dx * dx + dy * dy);
double aa;
if (dr > 0.0) {
aa = (number - dr + 1.0) * div2;
}
else {
aa = a0;
dr = 0.0001;
}
if ((aa >= 0.0) && (aa < limit)) {
if (moveXY) {
double cx = dx;
double cy = dy;
dx = dx / dr;
dy = dy / dr;
cx = cx - dx * am2;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa);
x[i] = cx + centreX + dx * rr;
y[i] = cy + centreY + dy * rr;
}
z[i] += amplitude * Math.sin(aa);
}
else {
if (moveXY) {
double cx = dx;
double cy = dy;
dx = dx / dr;
dy = dy / dr;
cx = cx - dx * am2;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa);
x[i] = cx + centreX + dx * rr;
y[i] = cy + centreY + dy * rr;
}
z[i] += 0.0;
}
}
}
else {
for (int i = 0; i < pCount; i++) {
double dx = x[i] - centreX;
double dy = y[i] - centreY;
double dr = Math.sqrt(dx * dx + dy * dy);
double dl = dr / wavelength;
double dmp = Math.exp(damping * dl);
double aa;
if (dr > 0.0) {
aa = (number - dr + 1.0) * div2;
}
else {
aa = a0;
dr = 0.0001;
}
if ((aa >= 0.0) && (aa < limit)) {
if (moveXY) {
double cx = dx;
double cy = dy;
dx = dx / dr;
dy = dy / dr;
cx = cx - dx * am2;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa) * dmp;
x[i] = cx + centreX + dx * rr;
y[i] = cy + centreY + dy * rr;
}
z[i] += amplitude * Math.sin(aa) * dmp;
}
else {
if (moveXY) {
double cx = dx;
double cy = dy;
dx = dx / dr;
dy = dy / dr;
cx = cx - dx * am2;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa) * dmp;
x[i] = cx + centreX + dx * rr;
y[i] = cy + centreY + dy * rr;
}
z[i] += 0.0;
}
}
}
}
else if (axis == Axis.X) {
if (!damp) {
for (int i = 0; i < pCount; i++) {
double dx = x[i] - centreX;
double dr = dx;
if (dr < 0.0)
dr = 0.0 - dr;
double aa;
if (dr > 0.0) {
aa = (number - dr + 1.0) * div2;
}
else {
aa = a0;
dr = 0.0001;
}
if ((aa >= 0.0) && (aa < limit)) {
if (moveXY) {
double cx = dx;
dx = dx / dr;
cx = cx - dx * am2;
double rr = amplitude * Math.cos(aa);
x[i] = cx + centreX + dx * rr;
}
z[i] += amplitude * Math.sin(aa);
}
else {
if (moveXY) {
double cx = dx;
dx = dx / dr;
cx = cx - dx * am2;
double rr = amplitude * Math.cos(aa);
x[i] = cx + centreX + dx * rr;
}
z[i] += 0.0;
}
}
}
else {
for (int i = 0; i < pCount; i++) {
double dx = x[i] - centreX;
double dr = dx;
if (dr < 0.0)
dr = 0.0 - dr;
double dl = dr / wavelength;
double dmp = Math.exp(damping * dl);
double aa;
if (dr > 0.0) {
aa = (number - dr + 1.0) * div2;
}
else {
aa = a0;
dr = 0.0001;
}
if ((aa >= 0.0) && (aa < limit)) {
if (moveXY) {
double cx = dx;
dx = dx / dr;
cx = cx - dx * am2;
double rr = amplitude * Math.cos(aa) * dmp;
x[i] = cx + centreX + dx * rr;
}
z[i] += amplitude * Math.sin(aa) * dmp;
}
else {
if (moveXY) {
double cx = dx;
dx = dx / dr;
cx = cx - dx * am2;
double rr = amplitude * Math.cos(aa) * dmp;
x[i] = cx + centreX + dx * rr;
}
z[i] += 0.0;
}
}
}
}
else { // (axis == Axis.Y)
if (!damp) {
for (int i = 0; i < pCount; i++) {
double dy = y[i] - centreY;
double dr = dy;
if (dr < 0.0)
dr = 0.0 - dr;
double aa;
if (dr > 0.0) {
aa = (number - dr + 1.0) * div2;
}
else {
aa = a0;
dr = 0.0001;
}
if ((aa >= 0.0) && (aa < limit)) {
if (moveXY) {
double cy = dy;
dy = dy / dr;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa);
y[i] = cy + centreY + dy * rr;
}
z[i] += amplitude * Math.sin(aa);
}
else {
if (moveXY) {
double cy = dy;
dy = dy / dr;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa);
y[i] = cy + centreY + dy * rr;
}
z[i] += 0.0;
}
}
}
else {
for (int i = 0; i < pCount; i++) {
double dy = y[i] - centreY;
double dr = dy;
if (dr < 0.0)
dr = 0.0 - dr;
double dl = dr / wavelength;
double dmp = Math.exp(damping * dl);
double aa;
if (dr > 0.0) {
aa = (number - dr + 1.0) * div2;
}
else {
aa = a0;
dr = 0.0001;
}
if ((aa >= 0.0) && (aa < limit)) {
if (moveXY) {
double cy = dy;
dy = dy / dr;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa) * dmp;
y[i] = cy + centreY + dy * rr;
}
z[i] += amplitude * Math.sin(aa) * dmp;
}
else {
if (moveXY) {
double cy = dy;
dy = dy / dr;
cy = cy - dy * am2;
double rr = amplitude * Math.cos(aa) * dmp;
y[i] = cy + centreY + dy * rr;
}
z[i] += 0.0;
}
}
}
}
}
@Override
public void initDefaultParams(WFImage pImg) {
super.initDefaultParams(pImg);
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
double rr = Math.sqrt(width * width + height * height);
damp = true;
damping = -0.1;
amplitude = (rr) / 120.0;
wavelength = (rr) / 12.0;
rings = 5;
times = 10;
frame = 33;
frames = 60;
originX = width / 2;
originY = height / 2;
axis = Axis.XY;
moveXY = true;
}
public static class AxisEditor extends ComboBoxPropertyEditor {
public AxisEditor() {
super();
setAvailableValues(new Axis[] { Axis.X, Axis.Y, Axis.XY });
}
}
public double getWavelength() {
return wavelength;
}
public void setWavelength(double wavelength) {
this.wavelength = wavelength;
}
public double getAmplitude() {
return amplitude;
}
public void setAmplitude(double amplitude) {
this.amplitude = amplitude;
}
public double getDamping() {
return damping;
}
public void setDamping(double damping) {
this.damping = damping;
}
public boolean isDamp() {
return damp;
}
public void setDamp(boolean damp) {
this.damp = damp;
}
public int getFrames() {
return frames;
}
public void setFrames(int frames) {
this.frames = frames;
}
public int getFrame() {
return frame;
}
public void setFrame(int frame) {
this.frame = frame;
}
public double getOriginX() {
return originX;
}
public void setOriginX(double originX) {
this.originX = originX;
}
public double getOriginY() {
return originY;
}
public void setOriginY(double originY) {
this.originY = originY;
}
public Axis getAxis() {
return axis;
}
public void setAxis(Axis axis) {
this.axis = axis;
}
public int getRings() {
return rings;
}
public void setRings(int rings) {
this.rings = rings;
}
public int getTimes() {
return times;
}
public void setTimes(int times) {
this.times = times;
}
public boolean isMoveXY() {
return moveXY;
}
public void setMoveXY(boolean moveXY) {
this.moveXY = moveXY;
}
}