/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package org.andork.math3d;
import static org.andork.math3d.Vecmath.calcClippingPlanes;
import static org.andork.math3d.Vecmath.getColumn3;
import static org.andork.math3d.Vecmath.invAffine;
import static org.andork.math3d.Vecmath.mmulAffine;
import static org.andork.math3d.Vecmath.mpmulAffine;
import static org.andork.math3d.Vecmath.mvmulAffine;
import static org.andork.math3d.Vecmath.newMat4f;
import static org.andork.math3d.Vecmath.normalize3;
import static org.andork.math3d.Vecmath.scaleAdd3;
import static org.andork.math3d.Vecmath.setf;
import static org.andork.math3d.Vecmath.threePointNormal;
import java.awt.Component;
import java.awt.event.MouseEvent;
import org.andork.util.Reparam;
public class PickXform {
boolean perspective = false;
final float[] vipi = newMat4f();
final float[] vi = newMat4f();
final float[] btlrnf = new float[6];
public void calculate(float[] p, float[] v) {
perspective = p[15] == 0;
if (p[15] == 0) {
calcClippingPlanes(p, btlrnf);
invAffine(v, vi);
} else {
mmulAffine(p, v, vipi);
invAffine(vipi);
invAffine(v, vi);
}
}
public void exportViewVolume(PlanarHull3f hull, float viewWidth, float viewHeight) {
exportViewVolume(hull, 0, 0, viewWidth, viewHeight, viewWidth, viewHeight);
}
public void exportViewVolume(PlanarHull3f hull, float minX, float minY, float maxX, float maxY, float viewWidth,
float viewHeight) {
if (hull.origins.length != 6) {
throw new IllegalArgumentException("hull must have exactly 6 sides");
}
if (hull.vertices.length != 8) {
throw new IllegalArgumentException("hull must have exactly 8 vertices");
}
xform(minX, minY, -1, viewWidth, viewHeight, hull.vertices[0]);
xform(maxX, minY, -1, viewWidth, viewHeight, hull.vertices[1]);
xform(minX, maxY, -1, viewWidth, viewHeight, hull.vertices[2]);
xform(maxX, maxY, -1, viewWidth, viewHeight, hull.vertices[3]);
xform(minX, minY, 1, viewWidth, viewHeight, hull.vertices[4]);
xform(maxX, minY, 1, viewWidth, viewHeight, hull.vertices[5]);
xform(minX, maxY, 1, viewWidth, viewHeight, hull.vertices[6]);
xform(maxX, maxY, 1, viewWidth, viewHeight, hull.vertices[7]);
setf(hull.origins[0], hull.vertices[0]);
setf(hull.origins[1], hull.vertices[3]);
setf(hull.origins[2], hull.vertices[0]);
setf(hull.origins[3], hull.vertices[3]);
xform((minX + maxX) * 0.5f, (minY + maxY) * 0.5f, -1, viewWidth, viewHeight, hull.origins[4]);
xform((minX + maxX) * 0.5f, (minY + maxY) * 0.5f, 1, viewWidth, viewHeight, hull.origins[5]);
threePointNormal(hull.vertices[0], hull.vertices[4], hull.vertices[2], hull.normals[0]);
threePointNormal(hull.vertices[1], hull.vertices[3], hull.vertices[5], hull.normals[1]);
threePointNormal(hull.vertices[0], hull.vertices[1], hull.vertices[4], hull.normals[2]);
threePointNormal(hull.vertices[2], hull.vertices[6], hull.vertices[3], hull.normals[3]);
threePointNormal(hull.vertices[0], hull.vertices[2], hull.vertices[1], hull.normals[4]);
threePointNormal(hull.vertices[4], hull.vertices[5], hull.vertices[6], hull.normals[5]);
normalize3(hull.normals[0]);
normalize3(hull.normals[1]);
normalize3(hull.normals[2]);
normalize3(hull.normals[3]);
normalize3(hull.normals[4]);
normalize3(hull.normals[5]);
}
public void exportViewVolume(PlanarHull3f hull, float[] viewBounds, float viewWidth, float viewHeight) {
exportViewVolume(hull, viewBounds[0], viewBounds[1], viewBounds[2], viewBounds[3], viewWidth, viewHeight);
}
public void exportViewVolume(PlanarHull3f hull, MouseEvent e, float radius) {
Component c = e.getComponent();
int y = c.getHeight() - e.getY();
exportViewVolume(hull, e.getX() - radius, y - radius, e.getX() + radius, y + radius,
c.getWidth(), c.getHeight());
}
public void xform(float x, float y, float z, float canvasWidth, float canvasHeight, float[] out) {
if (perspective) {
x = Reparam.linear(x, 0, canvasWidth, btlrnf[2], btlrnf[3]);
y = Reparam.linear(y, 0, canvasHeight, btlrnf[0], btlrnf[1]);
mvmulAffine(vi, x, y, -btlrnf[4], out);
z = Reparam.linear(z, -1, 1, -btlrnf[4], -btlrnf[5]);
scaleAdd3(z / -btlrnf[4], out, 0, vi, 12, out, 0);
} else {
x = Reparam.linear(x, 0, canvasWidth, -1, 1);
y = Reparam.linear(y, 0, canvasHeight, -1, 1);
mpmulAffine(vipi, x, y, z, out);
}
}
public void xform(float x, float y, float canvasWidth, float canvasHeight, float[] originOut,
float[] directionOut) {
if (perspective) {
getColumn3(vi, 3, originOut);
x = btlrnf[2] + x / canvasWidth * (btlrnf[3] - btlrnf[2]);
y = btlrnf[0] + y / canvasHeight * (btlrnf[1] - btlrnf[0]);
mvmulAffine(vi, x, y, -btlrnf[4], directionOut);
} else {
x = Reparam.linear(x, 0, canvasWidth, -1, 1);
y = Reparam.linear(y, 0, canvasHeight, -1, 1);
mpmulAffine(vipi, x, y, -1, originOut);
mvmulAffine(vi, 0, 0, 1, directionOut);
}
}
public void xform(float x, float y, float canvasWidth, float canvasHeight, float[] originOut, int originOuti,
float[] directionOut, int directionOuti) {
if (perspective) {
getColumn3(vi, 3, originOut, originOuti);
x = btlrnf[2] + x / canvasWidth * (btlrnf[3] - btlrnf[2]);
y = btlrnf[0] + y / canvasHeight * (btlrnf[1] - btlrnf[0]);
mvmulAffine(vi, x, y, -btlrnf[4], directionOut, directionOuti);
} else {
x = Reparam.linear(x, 0, canvasWidth, -1, 1);
y = Reparam.linear(y, 0, canvasHeight, -1, 1);
mpmulAffine(vipi, x, y, -1, originOut, originOuti);
mvmulAffine(vi, 0, 0, 1, directionOut, directionOuti);
}
}
public void xform(float x, float y, float z, float[] out) {
if (perspective) {
x = Reparam.linear(x, -1, 1, btlrnf[2], btlrnf[3]);
y = Reparam.linear(y, -1, 1, btlrnf[0], btlrnf[1]);
mvmulAffine(vi, x, y, -btlrnf[4], out);
z = Reparam.linear(z, -1, 1, -btlrnf[4], -btlrnf[5]);
scaleAdd3(z / -btlrnf[4], out, 0, vi, 12, out, 0);
} else {
mpmulAffine(vipi, x, y, z, out);
}
}
public void xform(MouseEvent e, float z, float[] out) {
Component canvas = e.getComponent();
xform(e.getX(), canvas.getHeight() - e.getY(), z, canvas.getWidth(), canvas.getHeight(), out);
}
public void xform(MouseEvent e, float[] origin, float[] direction) {
Component canvas = e.getComponent();
xform(e.getX(), canvas.getHeight() - e.getY(), canvas.getWidth(), canvas.getHeight(), origin, direction);
}
}