/*
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 java.awt.Color;
import org.jwildfire.base.Property;
import org.jwildfire.base.mathlib.MathLib;
import org.jwildfire.image.WFImage;
import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;
public class TwistTransformer extends Mesh3DTransformer {
public enum Axis {
X, Y, Z
}
@Property(description = "X-coordinate of the effect origin")
private double originX = 400.0;
@Property(description = "Y-coordinate of the effect origin")
private double originY = 400.0;
@Property(description = "Z-coordinate of the effect origin")
private double originZ = 0.0;
@Property(description = "Twist amount")
private double amount = 0.0;
@Property(description = "Twist distance")
private double dist = 0.0;
@Property(description = "Twist axis", editorClass = AxisEditor.class)
private Axis axis = Axis.X;
@Override
protected void transformMesh(Mesh3D pMesh3D, int pImageWidth, int pImageHeight) {
int width = pImageWidth;
int height = pImageHeight;
int pCount = pMesh3D.getPCount();
double x[] = pMesh3D.getX();
double y[] = pMesh3D.getY();
double z[] = pMesh3D.getZ();
if ((Math.abs(amount) <= MathLib.EPSILON) || (Math.abs(dist) <= MathLib.EPSILON))
return;
double originX = this.originX - (double) width / 2.0;
double originY = this.originY - (double) height / 2.0;
double originZ = 0.0 - this.originZ;
double dist = this.dist;
double angle0 = this.amount * Math.PI / 180.0;
double sa0 = Math.sin(angle0);
double ca0 = Math.cos(angle0);
if (this.axis == Axis.X) {
if (dist > 0.0) {
double ascale = angle0 / dist;
for (int i = 0; i < pCount; i++) {
double dx = x[i] - originX;
if (dx >= 0.0) {
double dy = y[i] - originY;
double dz = z[i] - originZ;
double sa, ca;
if (dx <= dist) {
double angle = dx * ascale;
sa = Math.sin(angle);
ca = Math.cos(angle);
}
else {
sa = sa0;
ca = ca0;
}
y[i] = originY + dy * ca + dz * sa;
z[i] = originZ + dz * ca - dy * sa;
}
}
}
else {
dist = 0.0 - dist;
double ascale = angle0 / dist;
for (int i = 0; i < pCount; i++) {
double dx = originX - x[i];
if (dx >= 0.0) {
double dy = y[i] - originY;
double dz = z[i] - originZ;
double sa, ca;
if (dx <= dist) {
double angle = dx * ascale;
sa = Math.sin(angle);
ca = Math.cos(angle);
}
else {
sa = sa0;
ca = ca0;
}
y[i] = originY + dy * ca + dz * sa;
z[i] = originZ + dz * ca - dy * sa;
}
}
}
}
else if (this.axis == Axis.Y) {
if (dist > 0.0) {
double ascale = angle0 / dist;
for (int i = 0; i < pCount; i++) {
double dy = y[i] - originY;
if (dy >= 0.0) {
double dx = x[i] - originX;
double dz = z[i] - originZ;
double sa, ca;
if (dy <= dist) {
double angle = dy * ascale;
sa = Math.sin(angle);
ca = Math.cos(angle);
}
else {
sa = sa0;
ca = ca0;
}
x[i] = originX + dx * ca + dz * sa;
z[i] = originZ + dz * ca - dx * sa;
}
}
}
else {
dist = 0.0 - dist;
double ascale = angle0 / dist;
for (int i = 0; i < pCount; i++) {
double dy = originY - y[i];
if (dy >= 0.0) {
double dx = x[i] - originX;
double dz = z[i] - originZ;
double sa, ca;
if (dy <= dist) {
double angle = dy * ascale;
sa = Math.sin(angle);
ca = Math.cos(angle);
}
else {
sa = sa0;
ca = ca0;
}
x[i] = originX + dx * ca + dz * sa;
z[i] = originZ + dz * ca - dx * sa;
}
}
}
}
else if (this.axis == Axis.Z) {
if (dist > 0.0) {
double ascale = angle0 / dist;
for (int i = 0; i < pCount; i++) {
double dz = z[i] - originZ;
if (dz >= 0.0) {
double dx = x[i] - originX;
double dy = y[i] - originY;
double sa, ca;
if (dz <= dist) {
double angle = dz * ascale;
sa = Math.sin(angle);
ca = Math.cos(angle);
}
else {
sa = sa0;
ca = ca0;
}
x[i] = originX + dx * ca + dy * sa;
y[i] = originY + dy * ca - dx * sa;
}
}
}
else {
dist = 0.0 - dist;
double ascale = angle0 / dist;
for (int i = 0; i < pCount; i++) {
double dz = originZ - z[i];
if (dz >= 0.0) {
double dx = x[i] - originX;
double dy = y[i] - originY;
double sa, ca;
if (dz <= dist) {
double angle = dz * ascale;
sa = Math.sin(angle);
ca = Math.cos(angle);
}
else {
sa = sa0;
ca = ca0;
}
x[i] = originX + dx * ca + dy * sa;
y[i] = originY + dy * ca - dx * sa;
}
}
}
}
}
@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);
axis = Axis.X;
originX = Math.round((double) width / 4.0);
originY = Math.round((double) height / 2.0);
originZ = 0.0;
dist = Math.round(rr - originX);
amount = Math.round(rr / 2.0);
setFaces(Faces.DOUBLE);
setZoom(0.8);
setLight2Color(new Color(255, 255, 220));
}
public static class AxisEditor extends ComboBoxPropertyEditor {
public AxisEditor() {
super();
setAvailableValues(new Axis[] { Axis.X, Axis.Y, Axis.Z });
}
}
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 double getOriginZ() {
return originZ;
}
public void setOriginZ(double originZ) {
this.originZ = originZ;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public double getDist() {
return dist;
}
public void setDist(double dist) {
this.dist = dist;
}
public Axis getAxis() {
return axis;
}
public void setAxis(Axis axis) {
this.axis = axis;
}
}