/*
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.PropertyMax;
import org.jwildfire.base.PropertyMin;
import org.jwildfire.image.WFImage;
import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;
public class WrapTransformer extends Mesh3DTransformer {
public enum Axis {
X, Y, XY
}
public enum Method {
AMOUNT, RADIUS
}
@Property(description = "X-coordinate of the effect origin")
private double originX;
@Property(description = "Y-coordinate of the effect origin")
private double originY;
@Property(description = "Wrap amount (method=AMOUNT)")
@PropertyMin(0.0)
@PropertyMax(100.0)
private double amount;
@Property(description = "Wrap radius (method=RADIUS)")
@PropertyMin(0.0)
private double radius;
@Property(description = "Wrap axis", editorClass = AxisEditor.class)
private Axis axis;
@Property(description = "Wrap method", editorClass = MethodEditor.class)
private Method method;
public static class AxisEditor extends ComboBoxPropertyEditor {
public AxisEditor() {
super();
setAvailableValues(new Axis[] { Axis.X, Axis.Y, Axis.XY });
}
}
public static class MethodEditor extends ComboBoxPropertyEditor {
public MethodEditor() {
super();
setAvailableValues(new Method[] { Method.AMOUNT, Method.RADIUS });
}
}
@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 (this.method == Method.AMOUNT) {
double log100 = Math.log(100.0);
if (this.amount >= 0.001) {
if (this.axis == Axis.X) {
double twoPi = 2.0 * Math.PI;
double amount = this.amount;
double logAmount = Math.log(amount);
double centreY = this.originY - (double) height / 2;
double radiusi = (double) height / twoPi;
double radius0 = 50.0 * radiusi;
double radius = radius0 + (radiusi - radius0) / log100 * logAmount;
for (int i = 0; i < pCount; i++) {
double dr = y[i] - centreY;
double angle = dr / radius;
double sa = Math.sin(angle);
double ca = Math.cos(angle);
double zz = z[i];
y[i] = sa * (radius - zz) + centreY;
z[i] = radius - ca * (radius - zz);
}
}
else if (this.axis == Axis.Y) {
double twoPi = 2.0 * Math.PI;
double amount = this.amount;
double logAmount = Math.log(amount);
double centreX = this.originX - (double) width / 2;
double radiusi = (double) width / twoPi;
double radius0 = 50.0 * radiusi;
double radius = radius0 + (radiusi - radius0) / log100 * logAmount;
for (int i = 0; i < pCount; i++) {
double dr = x[i] - centreX;
double angle = dr / radius;
double sa = Math.sin(angle);
double ca = Math.cos(angle);
double zz = z[i];
x[i] = sa * (radius - zz) + centreX;
z[i] = radius - ca * (radius - zz);
}
}
else {
double twoPi = 2.0 * Math.PI;
double mPI2 = 0.0 - Math.PI / 2.0;
double pPI2 = Math.PI / 2.0;
double amount = this.amount;
double logAmount = Math.log(amount);
double dx = (double) width;
double dy = (double) height;
double centreX = this.originX - (double) width / 2;
double centreY = this.originY - (double) height / 2;
double radiusi = (double) Math.sqrt(dx * dx + dy * dy) / twoPi;
double radius0 = 50.0 * radiusi;
double radius = radius0 + (radiusi - radius0) / log100 * logAmount;
for (int i = 0; i < pCount; i++) {
dx = x[i] - centreX;
dy = y[i] - centreY;
double zz = z[i];
double dr = Math.sqrt(dx * dx + dy * dy);
/* inverse rotation */
double angle2;
if (dx != 0.0) {
angle2 = Math.atan(dy / dx);
}
else {
if (dy < 0.0)
angle2 = mPI2;
else
angle2 = pPI2;
}
/* wrapping */
double angle = dr / radius;
double sa = Math.sin(angle);
double ca = Math.cos(angle);
double rx;
if (dx < 0)
rx = 0.0 - (radius - zz) * sa;
else
rx = (radius - zz) * sa;
z[i] = radius - (radius - zz) * ca;
/* rotation */
x[i] = rx * Math.cos(angle2) + centreX;
y[i] = rx * Math.sin(angle2) + centreY;
}
}
}
}
else if (this.method == Method.RADIUS) {
if (this.radius >= 0.001) {
if (this.axis == Axis.X) {
double centreY = this.originY - (double) height / 2;
double radius = this.radius;
if (radius < 1.0)
radius = 1.0;
double ds = radius * Math.PI / 2.0;
double dsrad = radius - ds;
for (int i = 0; i < pCount; i++) {
double dr = y[i] - centreY;
if (Math.abs(dr) <= ds) {
double angle = dr / radius;
double sa = Math.sin(angle);
double ca = Math.cos(angle);
double zz = z[i];
y[i] = sa * (radius - zz) + centreY;
z[i] = 0.0 - (ca * radius - zz);
}
else {
if (dr >= 0.0) {
y[i] = dr + dsrad + centreY;
}
else {
y[i] = dr - dsrad + centreY;
}
}
}
}
else if (this.axis == Axis.Y) {
double centreX = this.originX - (double) width / 2;
double radius = this.radius;
if (radius < 1.0)
radius = 1.0;
double ds = radius * Math.PI / 2.0;
double dsrad = radius - ds;
for (int i = 0; i < pCount; i++) {
double dr = x[i] - centreX;
if (Math.abs(dr) <= ds) {
double angle = dr / radius;
double sa = Math.sin(angle);
double ca = Math.cos(angle);
double zz = z[i];
x[i] = sa * (radius - zz) + centreX;
z[i] = 0.0 - ca * (radius - zz);
}
else {
if (dr >= 0.0) {
x[i] = dr + dsrad + centreX;
}
else {
x[i] = dr - dsrad + centreX;
}
}
}
}
else {
double mPI2 = 0.0 - Math.PI / 2.0;
double pPI2 = Math.PI / 2.0;
double dx = (double) width;
double dy = (double) height;
double centreX = this.originX - (double) width / 2;
double centreY = this.originY - (double) height / 2;
double radius = this.radius;
if (radius < 1.0)
radius = 1.0;
double ds = radius * Math.PI / 2.0;
double dsrad = radius - ds;
for (int i = 0; i < pCount; i++) {
dx = x[i] - centreX;
dy = y[i] - centreY;
double zz = z[i];
double dr = Math.sqrt(dx * dx + dy * dy);
/* inverse rotation */
double angle2;
if (dx != 0.0) {
angle2 = Math.atan(dy / dx);
}
else {
if (dy < 0.0)
angle2 = mPI2;
else
angle2 = pPI2;
}
if (dr <= ds) {
/* wrapping */
double angle = dr / radius;
double sa = Math.sin(angle);
double ca = Math.cos(angle);
double rx;
if (dx < 0)
rx = 0.0 - (radius - zz) * sa;
else
rx = (radius - zz) * sa;
z[i] = 0.0 - (radius - zz) * ca;
/* rotation */
x[i] = rx * Math.cos(angle2) + centreX;
y[i] = rx * Math.sin(angle2) + centreY;
}
else {
if (dx >= 0.0) {
x[i] = dx + dsrad * Math.cos(angle2) + centreX;
y[i] = dy + dsrad * Math.sin(angle2) + centreY;
}
else {
x[i] = dx - dsrad * Math.cos(angle2) + centreX;
y[i] = dy - dsrad * Math.sin(angle2) + centreY;
}
}
}
}
}
}
}
@Override
public void initDefaultParams(WFImage pImg) {
super.initDefaultParams(pImg);
int width = pImg.getImageWidth();
int height = pImg.getImageHeight();
method = Method.RADIUS;
amount = 98.0;
originX = Math.round(width / 2.0);
originY = Math.round(height / 2.0);
radius = calcRad(originX, originY);
axis = Axis.XY;
faces = Faces.DOUBLE;
}
private double calcRad(double cx, double cy) {
return Math.sqrt(cx * cx + cy * cy) / 3.4;
}
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 getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public Axis getAxis() {
return axis;
}
public void setAxis(Axis axis) {
this.axis = axis;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}