/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2014 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.
*/
/*
* Implementation of the marching cubes algorithm based on the
* "Marching Cubes Tutorial Applet Copyright (C) 2002 - GERVAISE Raphael & RICHARD Karen"
* http://users.polytech.unice.fr/~lingrand/MarchingCubes/applet.html
*/
package org.jwildfire.create.tina.meshgen.marchingcubes;
import static org.jwildfire.base.mathlib.MathLib.sqrt;
import java.util.List;
public class FacesCalculator {
public static void getFaces(Cube pCube, List<Point3f> pVertices, List<Point3f> pNormals, ImageStackSampler pSampler, int pSeekValue) {
int cn = caseNumber(pCube, pSampler, pSeekValue);
boolean directTable = !(isAmbigous(cn));
// address in the table
int offset = directTable ? cn * 15 : (255 - cn) * 15;
InvalidatablePoint[] edges = pCube.getEdges();
Point3f v1 = new Point3f();
Point3f v2 = new Point3f();
for (int index = 0; index < 5; index++) {
// if there's a triangle
if (PredefinedCases.faces[offset] != -1) {
// pick up vertexes of the current triangle
InvalidatablePoint edge1 = edges[PredefinedCases.faces[offset + 0]];
InvalidatablePoint edge2 = edges[PredefinedCases.faces[offset + 1]];
InvalidatablePoint edge3 = edges[PredefinedCases.faces[offset + 2]];
if (edge1.invalid || edge2.invalid || edge3.invalid) {
}
else {
pVertices.add(new Point3f(edge1));
pVertices.add(new Point3f(edge2));
pVertices.add(new Point3f(edge3));
if (pNormals != null) {
Point3f normal = new Point3f();
v1.x = edge2.x - edge1.x;
v1.y = edge2.y - edge1.y;
v1.z = edge2.z - edge1.z;
v2.x = edge3.x - edge1.x;
v2.y = edge3.y - edge1.y;
v2.z = edge3.z - edge1.z;
if (directTable) {
crossProduct(v1, v2, normal);
}
else {
crossProduct(v2, v1, normal);
}
normalize(normal);
pNormals.add(normal);
}
}
}
offset += 3;
}
}
private static void normalize(Point3f pPoint) {
double r = sqrt(pPoint.x * pPoint.x + pPoint.y * pPoint.y + pPoint.z * pPoint.z);
if (r != 0) {
pPoint.x /= r;
pPoint.y /= r;
pPoint.z /= r;
}
}
private static void crossProduct(Point3f pA, Point3f pB, Point3f pTarget) {
pTarget.x = pA.y * pB.z - pA.z * pB.y;
pTarget.y = pA.z * pB.x - pA.x * pB.z;
pTarget.z = pA.x * pB.y - pA.y * pB.x;
}
/**
* indicates if a number corresponds to an ambigous case
* @param n number of the case to test
* @return true if the case if ambigous
*/
private static boolean isAmbigous(int n) {
boolean result = false;
for (int index = 0; index < PredefinedCases.ambigous.length; index++) {
result |= PredefinedCases.ambigous[index] == n;
}
return result;
}
/**
* computes the case number of the cube
* @return the number of the case corresponding to the cube
*/
private static int caseNumber(Cube pCube, ImageStackSampler pSampler, int pSeekValue) {
int caseNumber = 0;
for (int index = -1; ++index < pCube.getVertices().length; caseNumber += (pSampler.getIntensity(pCube.getVertices()[index]) - pSeekValue > 0) ? 1 << index : 0)
;
return caseNumber;
}
}