/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2013 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.create.tina.meshgen.marchingcubes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jwildfire.create.tina.meshgen.RawFaces;
public class FacesMerger {
private static final float DLFT_OBJSIZE = 10.0f;
private static class AvgNormal extends Point3f {
public int count;
public AvgNormal(Point3f pPoint) {
x = pPoint.x;
y = pPoint.y;
z = pPoint.z;
count = 1;
}
public void addPoint(Point3f pPoint) {
x += pPoint.x;
y += pPoint.y;
z += pPoint.z;
count++;
}
public float getAvgX() {
return count > 0 ? x / (float) count : 0.0f;
}
public float getAvgY() {
return count > 0 ? y / (float) count : 0.0f;
}
public float getAvgZ() {
return count > 0 ? z / (float) count : 0.0f;
}
}
public static Mesh generateMesh(RawFaces pRawFaces, float zScale) {
List<Point3f> vertices = pRawFaces.getVertices();
List<Point3f> faceNormals = pRawFaces.getNormals();
Map<Point3f, Integer> index = new HashMap<Point3f, Integer>();
List<Point3f> points = new ArrayList<Point3f>();
Point3f first = vertices.size() > 0 ? vertices.get(0) : new Point3f();
float xmin = first.x, xmax = first.x;
float ymin = first.y, ymax = first.y;
float zmin = first.z, zmax = first.z;
long t0, t1;
t0 = System.currentTimeMillis();
for (Point3f point : vertices) {
if (index.get(point) == null) {
index.put(point, points.size());
points.add(point);
if (point.x < xmin)
xmin = point.x;
else if (point.x > xmax)
xmax = point.x;
if (point.y < ymin)
ymin = point.y;
else if (point.y > ymax)
ymax = point.y;
if (point.z < zmin)
zmin = point.z;
else if (point.z > zmax)
zmax = point.z;
}
}
t1 = System.currentTimeMillis();
System.out.println("CREATE UNIQUE POINTS: " + (t1 - t0) / 1000.0 + "s");
t0 = System.currentTimeMillis();
Set<Face> facesSet = new HashSet<Face>();
List<Face> faces = new ArrayList<Face>();
Map<Integer, AvgNormal> normalMap = new HashMap<Integer, AvgNormal>();
for (int i = 0; i < vertices.size(); i += 3) {
int a = index.get(vertices.get(i));
int b = index.get(vertices.get(i + 1));
int c = index.get(vertices.get(i + 2));
if (a != b && b != c && a != c) {
Face face = new Face(a, c, b);
if (!facesSet.contains(face)) {
facesSet.add(face);
faces.add(face);
if (faceNormals != null) {
Point3f faceNormal = faceNormals.get(i / 3);
addFaceNormalToNormalMap(normalMap, a, faceNormal);
addFaceNormalToNormalMap(normalMap, b, faceNormal);
addFaceNormalToNormalMap(normalMap, c, faceNormal);
}
}
}
}
t1 = System.currentTimeMillis();
System.out.println("CREATE FACES: " + (t1 - t0) / 1000.0 + "s");
t0 = System.currentTimeMillis();
float xsize = xmax - xmin;
float ysize = ymax - ymin;
float zsize = zmax - zmin;
float size = (xsize + ysize + zsize) / 3.0f;
float dx = -xmin - (xmax - xmin) / 2.0f;
float dy = -ymin - (ymax - ymin) / 2.0f;
float dz = -zmin - (zmax - zmin) / 2.0f;
float scale = DLFT_OBJSIZE / size;
if (faceNormals != null) {
List<Point3f> vertexNormals = new ArrayList<Point3f>();
for (int i = 0; i < points.size(); i++) {
Point3f point = points.get(i);
AvgNormal avgNormal = normalMap.get(i);
if (avgNormal != null) {
vertexNormals.add(new Point3f(avgNormal.getAvgX(), avgNormal.getAvgY(), avgNormal.getAvgZ()));
}
else {
vertexNormals.add(new Point3f());
}
point.x = (point.x + dx) * scale;
point.y = (point.y + dy) * scale;
point.z = (point.z + dz) * scale * zScale;
}
t1 = System.currentTimeMillis();
System.out.println("SCALING POINTS: " + (t1 - t0) / 1000.0 + "s");
return new Mesh(points, vertexNormals, faces);
}
else {
for (Point3f point : points) {
point.x = (point.x + dx) * scale;
point.y = (point.y + dy) * scale;
point.z = (point.z + dz) * scale * zScale;
}
t1 = System.currentTimeMillis();
System.out.println("SCALING POINTS: " + (t1 - t0) / 1000.0 + "s");
return new Mesh(points, faces);
}
}
private static void addFaceNormalToNormalMap(Map<Integer, AvgNormal> pNormalMap, int pPointIndex, Point3f pFaceNormal) {
Integer key = Integer.valueOf(pPointIndex);
AvgNormal avg = pNormalMap.get(key);
if (avg == null) {
avg = new AvgNormal(pFaceNormal);
pNormalMap.put(key, avg);
}
else {
avg.addPoint(pFaceNormal);
}
}
}