|
import java.util.Vector;
|
import java.util.Hashtable;
|
|
import com.sun.j3d.utils.geometry.*;
|
import javax.media.j3d.*;
|
|
class BoundaryRep implements java.io.Serializable
|
{
|
static final long serialVersionUID = // VERY old 2008 -5762968998168738314L;
|
-4852664309425035321L;
|
|
transient int displaylist = 0;
|
|
BoundaryRep()
|
{
|
this(0, 0);
|
}
|
|
void SaveSupports()
|
{
|
transientsupport = support;
|
support = null;
|
}
|
|
void RestoreSupports()
|
{
|
support = transientsupport;
|
transientsupport = null;
|
}
|
|
void Init(int nVerts, int nFaces, boolean setsize)
|
{
|
positions = null;
|
normals = null;
|
colors = null;
|
uvmap = null;
|
triangles = null;
|
|
//System.out.println("Vertices = " + nVerts);
|
//System.out.println("Faces = " + nFaces);
|
vertices = new Vector(nVerts);
|
faces = new Vector(nFaces);
|
if (setsize)
|
{
|
vertices.setSize(nVerts);
|
faces.setSize(nFaces);
|
}
|
vertextable = new Hashtable();
|
|
bufV = nVerts;
|
bufF = nFaces;
|
|
maxIndexV = 0;
|
|
countV = 0;
|
countF = 0;
|
|
//new Exception().printStackTrace();
|
|
trimmed = false;
|
|
links = null;
|
}
|
|
BoundaryRep(int nVerts, int nFaces)
|
{
|
Init(nVerts, nFaces, false);
|
}
|
|
BoundaryRep(int nVerts, int nFaces, boolean setsize)
|
{
|
Init(nVerts, nFaces, setsize);
|
}
|
|
BoundaryRep(BoundaryRep other, double mat[][])
|
{
|
/*
|
if (other.trimmed)
|
{
|
trimmed = true;
|
//positions = new float[other.positions.length];
|
//System.arraycopy(other.positions,0, positions,0, positions.length);
|
//normals = new float[other.normals.length];
|
//System.arraycopy(other.normals,0, normals,0, normals.length);
|
//triangles = new int[other.triangles.length];
|
//System.arraycopy(other.triangles,0, triangles,0, triangles.length);
|
// Shared
|
positions = other.positions;
|
normals = other.normals;
|
colors = other.colors;
|
uvmap = other.uvmap;
|
triangles = other.triangles;
|
}
|
else
|
{
|
//vertices = (Vector)other.vertices.clone();
|
//vertextable = (Hashtable)other.vertextable.clone();
|
//faces = (Vector)other.faces.clone();
|
vertices = other.vertices;
|
vertextable = other.vertextable;
|
faces = other.faces;
|
}
|
*/
|
|
Set(other);
|
}
|
|
void Set(BoundaryRep other)
|
{
|
trimmed = other.trimmed;
|
stripified = other.stripified;
|
|
positions = other.positions;
|
normals = other.normals;
|
colors = other.colors;
|
uvmap = other.uvmap;
|
triangles = other.triangles;
|
|
vertices = other.vertices;
|
vertextable = other.vertextable;
|
faces = other.faces;
|
|
countV = other.countV;
|
countF = other.countF;
|
maxIndexV = other.maxIndexV;
|
|
bufV = other.bufV;
|
bufF = other.bufF;
|
|
vertextable = new Hashtable();
|
verticesCopy = null;
|
}
|
|
void Average(cVector av)
|
{
|
av.x = 0;
|
av.y = 0;
|
av.z = 0;
|
|
for (int i=VertexCount(); --i>=0;)
|
{
|
Vertex v = GetVertex(i);
|
|
av.x += v.x;
|
av.y += v.y;
|
av.z += v.z;
|
}
|
|
av.x /= VertexCount();
|
av.y /= VertexCount();
|
av.z /= VertexCount();
|
}
|
|
void overwriteThis(BoundaryRep other)
|
{
|
if (other == null) // june 2014
|
return;
|
|
//assert(VertexCount() == other.VertexCount());
|
if (VertexCount() != other.VertexCount() // jan 2014
|
|| FaceCount() != other.FaceCount()
|
|| !(indices == null ^ other.indices != null)) // july 2014
|
{
|
// The meshes have different structures.
|
//new Exception().printStackTrace();
|
trimmed = other.trimmed;
|
stripified = other.stripified;
|
|
AOdone = AOdone;
|
maxIndexV = other.maxIndexV;
|
countV = other.countV;
|
countF = other.countF;
|
bufV = other.bufV;
|
bufF = other.bufF;
|
|
positions = (float[]) Grafreed.clone(other.positions);
|
normals = (float[]) Grafreed.clone(other.normals);
|
colors = (float[]) Grafreed.clone(other.colors);
|
uvmap = (float[]) Grafreed.clone(other.uvmap);
|
triangles = (int[]) Grafreed.clone(other.triangles);
|
|
indices = (int[]) Grafreed.clone(other.indices);
|
|
vertices = (Vector<Vertex>) Grafreed.clone(other.vertices);
|
faces = (Vector<Face>) Grafreed.clone(other.faces);
|
}
|
else
|
{
|
// we assume a perfect match...
|
|
int min = VertexCount();
|
|
// STRIPIFY mismatch??
|
//if (min > other.VertexCount())
|
// min = other.VertexCount();
|
|
for (int i = 0; i < min; i++)
|
{
|
Vertex v = other.GetVertex(i);
|
|
SetVertex(v, i);
|
}
|
}
|
}
|
|
static class Support implements java.io.Serializable
|
{
|
static final long serialVersionUID = 2700906041984136489L;
|
|
int[] links = new int[100]; // connected supports
|
|
int Length()
|
{
|
int n = 0;
|
|
while (links[n] != -1)
|
{
|
n++;
|
// if (n == links.length)
|
// break;
|
}
|
|
return n;
|
}
|
|
boolean Contains(int link)
|
{
|
return IndexOf(link) != -1;
|
}
|
|
int IndexOf(int link)
|
{
|
for (int i=links.length; --i>=0;)
|
{
|
if (links[i] == link)
|
return i;
|
}
|
|
return -1;
|
}
|
}
|
|
transient Support[] cachesupports = null;
|
|
Support[] InitConnections()
|
{
|
if (cachesupports != null)
|
{
|
return cachesupports;
|
}
|
|
int n = this.startvertices.length-1;
|
|
Support[] supports = new Support[n];
|
|
for (int i=n; --i>=0;)
|
{
|
supports[i] = new Support();
|
supports[i].links[0] = -1;
|
}
|
|
for (int object=1; object<=n; object++)
|
{
|
int start = this.startvertices[object-1];
|
int end = this.startvertices[object];
|
|
if (start == end)
|
continue; // ??
|
|
/**
|
Vertex v2 = vertextemp;
|
v2.x = averagepoints[object*3];
|
v2.y = averagepoints[object*3+1];
|
v2.z = averagepoints[object*3+2];
|
|
//v2.set(GetVertex(this.startvertices[subsupport]));
|
|
// projected point
|
Vertex v3 = vertextemp2;
|
//GetVertex(this.startvertices[subsupport]);
|
v3.x = extremepoints[object*3];
|
v3.y = extremepoints[object*3+1];
|
v3.z = extremepoints[object*3+2];
|
|
vect3.set(v3); // "X" axis apex
|
vect3.sub(v2); // origin (center)
|
vect3.normalize();
|
/**/
|
|
int linkcount = 0;
|
|
int objectinlist = -1;
|
|
Support subsupport = supports[object-1];
|
|
for (int object2=1; object2<=n; object2++)
|
{
|
for (int i = start; i < end; i++)
|
{
|
Vertex v = this.GetVertex(i);
|
|
// Check if v is close enough from any vertex of the given subobject.
|
if (this.Contains(v, object2))
|
{
|
if (linkcount == subsupport.links.length)
|
break;
|
|
if (object2 == object)
|
objectinlist = linkcount;
|
|
subsupport.links[linkcount++] = object2;
|
break;
|
}
|
}
|
}
|
|
subsupport.links[linkcount] = -1;
|
|
if (objectinlist == -1)
|
assert(objectinlist != -1);
|
|
// if (linkcount <= 1)
|
// assert(linkcount > 1);
|
|
// show main support as blue
|
int first = subsupport.links[0];
|
subsupport.links[0] = subsupport.links[objectinlist];
|
subsupport.links[objectinlist] = first;
|
}
|
|
for (int loop = 0; --loop>=0;)
|
{
|
Support[] supports2 = new Support[n];
|
|
for (int i=n; --i>=0;)
|
{
|
supports2[i] = new Support();
|
supports2[i].links[0] = -1;
|
}
|
|
|
// Allows another link depth
|
for (int i=n; --i>=0;)
|
{
|
if (i == 55)
|
i = 55;
|
|
Support newsup = supports2[i];
|
int linkcount = 0;
|
|
Support oldsup = supports[i];
|
|
for (int j=oldsup.Length(); --j>=0;)
|
{
|
newsup.links[linkcount++] = oldsup.links[j];
|
|
if (oldsup.links[j] == 0)
|
break;
|
|
Support indirect = supports[oldsup.links[j]-1];
|
|
for (int k=indirect.Length(); --k>=0;)
|
{
|
if (newsup.Contains(indirect.links[k]))
|
continue;
|
|
try
|
{
|
newsup.links[linkcount++] = indirect.links[k];
|
}
|
catch(Exception e)
|
{
|
e.printStackTrace();
|
}
|
|
break;
|
}
|
}
|
|
newsup.links[linkcount] = -1;
|
}
|
|
supports = supports2;
|
}
|
|
return cachesupports = supports;
|
}
|
|
double Distance2(Vertex v, Vertex v2, double dist2beat, double[][] toRoot, int k)
|
{
|
// Vertex v2 = GetVertex(v.vertexlinks[k]);
|
|
vect2.set(v2);
|
LA.xformPos(vect2,toRoot,vect2);
|
vect2.sub(v);
|
|
// int j3 = k*3;
|
//
|
// float tx = v.tplane[j3];
|
// float ty = v.tplane[j3+1];
|
// float tz = v.tplane[j3+2];
|
|
double dist2 = vect2.dot(vect2); // tx*tx + ty*ty + tz*tz;
|
|
// DOESN'T WORK BECAUSE OF EDGE DISTANCE
|
// look for all triangles
|
if (false) // dist2 < dist2beat) // if it is useful...
|
for (int i = FaceCount(); --i>=0;)
|
{
|
Face f = GetFace(i);
|
|
Vertex p = GetVertex(f.p);
|
Vertex q = GetVertex(f.q);
|
Vertex r = GetVertex(f.r);
|
|
if (v2 != p && v2 != q && v2 != r)
|
continue; // vertex is not in the face
|
|
// // rotate for p to be v2
|
// while (p != v2)
|
// {
|
// Vertex t = p;
|
// p = q;
|
// q = r;
|
// r = t;
|
// }
|
|
// normal to the plane
|
vect2.set(q);
|
LA.xformPos(vect2,toRoot,vect2);
|
vect4.set(p);
|
LA.xformPos(vect4,toRoot,vect4);
|
vect2.sub(vect4);
|
|
// vect3.set(vect2);
|
vect3.set(r);
|
LA.xformPos(vect3,toRoot,vect3);
|
vect4.set(q);
|
LA.xformPos(vect4,toRoot,vect4);
|
vect3.sub(vect4);
|
|
normal.cross(vect2, vect3);
|
|
if (normal.dot(v.norm) < 0)
|
continue;
|
|
normal.normalize();
|
|
vect4.set(p); // v2 or doesn't matter
|
LA.xformPos(vect4,toRoot,vect4);
|
|
// closest point in the plane
|
vect4.sub(v);
|
vect4.mul(-1);
|
|
// double dot = -vect4.dot(normal);
|
//
|
// normal.mul(dot);
|
// vect4.set(v);
|
// vect4.sub(normal);
|
|
// System.err.println("ortho = " + vect4.dot(normal));
|
|
// 3 planes
|
vect.cross(normal,vect2);
|
vect.normalize(); //
|
double distpq = vect4.dot(vect);
|
|
vect.cross(normal,vect3);
|
vect.normalize(); //
|
double distqr = vect4.dot(vect) - vect2.dot(vect);
|
|
// rp...
|
// (r - q) + (q - p)
|
vect.set(vect2);
|
vect.add(vect3);
|
// vect3.set(p);
|
// LA.xformPos(vect3,toRoot,vect3);
|
// vect2.set(r);
|
// LA.xformPos(vect2,toRoot,vect2);
|
// vect3.sub(vect2);
|
//
|
// vect.cross(normal,vect3);
|
vect.cross(normal, vect);
|
vect.normalize(); //
|
double distrp = -vect4.dot(vect);
|
|
if (distpq < 0 && distrp < 0 && distqr < 0 ||
|
distpq > 0 && distrp > 0 && distqr > 0)
|
{
|
// point is inside triangle
|
double dot = vect4.dot(normal);
|
|
if (dist2 > dot*dot)
|
{
|
dist2 = dot*dot;
|
|
if (debug)
|
{
|
debugcount++;
|
Object3D debugObject = new Object3D();
|
debugObject.CreateMaterial();
|
debugObject.material.color = 0.25f * debugcount;
|
debugObject.material.modulation = 1;
|
debugObject.bRep = new BoundaryRep(3, 1, true);
|
|
debugObject.bRep.setFace(0, 0,1,2);
|
|
Vertex dv = debugObject.bRep.GetVertex(0);
|
dv.set(p);
|
LA.xformPos(dv,toRoot,dv);
|
dv = debugObject.bRep.GetVertex(1);
|
dv.set(q);
|
LA.xformPos(dv,toRoot,dv);
|
dv = debugObject.bRep.GetVertex(2);
|
dv.set(r);
|
LA.xformPos(dv,toRoot,dv);
|
|
CameraPane.debugstuff.add(debugObject);
|
}
|
}
|
// dist2 = tz*tz;
|
break;
|
}
|
}
|
|
return dist2;
|
}
|
|
static Vertex vertextemp = new Vertex(true);
|
static Vertex vertextemp2 = new Vertex(true);
|
|
static double SEUIL = 0.025f; // 0.1 for rag doll; 0.07;
|
|
// Compute weight of point w/r to this
|
float ComputeWeight(Vertex v, double[][] toRoot, int k)
|
{
|
// assert(LA.isIdentity(toRoot));
|
Vertex v2 = GetVertex(v.vertexlinks[k]);
|
|
vect2.set(v2);
|
LA.xformPos(vect2,toRoot,vect2);
|
|
Vertex v3;
|
|
// v3 = GetVertex(v.vertexlinks2[k]);
|
//
|
// vect3.set(v3);
|
// LA.xformPos(vect3,toRoot,vect3);
|
//
|
// vect3.sub(vect2);
|
//
|
// // heuristic
|
float supportsize = 1;
|
|
// supportsize = Math.sqrt(
|
// vect3.dot(vect3)
|
// )
|
// ;
|
|
// use subsupport center
|
v2 = vertextemp;
|
|
int subsupport = supports[v.closestsupport].links[k] - 1;
|
|
v2.x = averagepoints[subsupport*3];
|
v2.y = averagepoints[subsupport*3+1];
|
v2.z = averagepoints[subsupport*3+2];
|
|
//v2.set(GetVertex(this.startvertices[subsupport]));
|
|
if (true)
|
{
|
// projected point
|
v3 = vertextemp2;
|
//GetVertex(this.startvertices[subsupport]);
|
v3.x = extremepoints[subsupport*3];
|
v3.y = extremepoints[subsupport*3+1];
|
v3.z = extremepoints[subsupport*3+2];
|
|
vect3.set(v3); // "X" axis apex
|
vect3.sub(v2); // origin (center)
|
|
double distmax = vect3.length();
|
|
if (distmax == 0)
|
{
|
System.err.println("DISTMAX == 0");
|
//System.exit(0);
|
distmax = 1;
|
}
|
|
vect3.normalize();
|
|
vect4.set(vect2); // keep original
|
vect2.set(v); // TEST
|
vect2.sub(v2); // original - origin
|
|
double dot = vect2.dot(vect3);
|
|
if (dot > distmax)
|
dot = distmax;
|
//return 0; // patch for strange behavior
|
if (dot < -distmax)
|
dot = -distmax;
|
//return 0; // patch for strange behavior
|
|
// v3 = GetVertex(this.startvertices[subsupport] + 16);
|
//
|
// vect4.set(v3); // "Y" axis apex
|
// vect4.sub(v2); // origin (center)
|
//
|
// double dot2 = vect4.dot(vect3);
|
//
|
// v2.add(vect3, dot2); // projected point
|
//
|
// vect4.set(v3); // "Y" axis apex
|
// vect4.sub(v2); // projected
|
//
|
// v2.add(vect3, -dot2);
|
//
|
// //vect4.sub(v3); // vect2); // distance to projected point
|
//
|
// supportsize = Math.pow
|
// (
|
// vect4.dot(vect4), 1 // .5
|
// )
|
// ;
|
//
|
|
supportsize = supportminsize[subsupport];
|
|
double K = supportsize / distmax;
|
|
assert(K <= 1);
|
|
dot *= (1 - K);
|
|
v2.add(vect3, dot); // projected point
|
}
|
|
float dist2 = (float)Distance2(v, v2, 1E10, toRoot, k);
|
|
double seuil = SEUIL * 2;
|
|
if (dist2 >= 2 * seuil*seuil) // && !CameraPane.CROWD) // weightmode
|
return 0;
|
|
dist2 /= 2 * seuil*seuil; // multiplied by two because center of support
|
// could be far from closest point
|
|
// dist2 = Math.pow(dist2, 2);
|
//
|
// dist2 = Math.tan(dist2*Math.PI/2);
|
//
|
// return (float)(supportsize / Math.pow(dist2, 2)); // 2));
|
|
dist2 = (float)Math.pow(dist2, 2); // 2);
|
|
float fadefactor = 1/dist2 - 1;
|
|
// if (fadefactor < 0.5)
|
// {
|
// fadefactor *= fadefactor;
|
// fadefactor *= 2;
|
// }
|
// else
|
// {
|
// fadefactor = 1 - fadefactor;
|
// fadefactor *= fadefactor;
|
// fadefactor *= 2;
|
// fadefactor = 1 - fadefactor;
|
// }
|
|
// fadefactor = (float)Math.pow(fadefactor, 4);
|
// fadefactor = (float)Math.exp(-1/fadefactor);
|
|
// fadefactor *= Math.E;
|
|
// if (supportsize * fadefactor > 1)
|
// return 1;
|
|
return //supportsize *
|
supportsize * fadefactor;
|
}
|
|
void RecomputeBasis(BoundaryRep other, double[][] toRoot, Vertex v)
|
{
|
CameraPane.CreateSelectedPoint();
|
CameraPane.selectedpoint.
|
getAverage(cStatic.point1, true);
|
|
cStatic.point1.sub(v);
|
|
debug = false;
|
if (cStatic.point1.dot(cStatic.point1) < 0.00001)
|
{
|
// debug = true;
|
CameraPane.debugstuff.clear();
|
v = v;
|
}
|
|
if (vect == null)
|
{
|
// serial
|
vect = new cVector();
|
normal = new cVector();
|
vect2 = new cVector();
|
vect3 = new cVector();
|
vect4 = new cVector();
|
}
|
|
v.totalweight = 0;
|
|
int subsupports = v.vertexlinks.length;
|
|
for (int k = 0/*-1*/; k < subsupports; k++)
|
{
|
if (v.vertexlinks[k] == -1)
|
{
|
//assert(false); // assert?
|
continue;
|
}
|
|
Vertex v2 = other.GetVertex(v.vertexlinks[k]);
|
|
vect2.set(v2);
|
LA.xformPos(vect2,toRoot,vect2);
|
|
if (v.vertexlinks2[k] == -1)
|
{
|
//assert(false); // assert?
|
continue;
|
}
|
|
Vertex v3 = other.GetVertex(v.vertexlinks2[k]);
|
|
vect3.set(v3);
|
LA.xformPos(vect3,toRoot,vect3);
|
|
vect3.sub(vect2);
|
|
// heuristic
|
double supportsize = Math.sqrt(vect3.dot(vect3));
|
|
// normal.set(v2); // v2.norm);
|
// normal.add(v2.norm);
|
// LA.xformPos(normal,toRoot,normal);
|
// normal.sub(vect2);
|
normal.set(v2.norm);
|
LA.xformDir(normal,toRoot,normal);
|
|
normal.normalize();
|
|
double dot = vect3.dot(normal);
|
|
vect.set(normal);
|
vect.mul(dot);
|
vect3.sub(vect);
|
vect3.normalize();
|
|
// assert(vect3.dot(normal) == 0);
|
|
vect4.cross(normal, vect3);
|
|
// assert(vect4.length() == 1);
|
|
// axis.set(0,0,1);
|
// quat.setRotation(normal, axis);
|
// rotation.setRotation(quat);
|
//
|
//// vect.set(v);
|
//// vect.sub(v2);
|
// vect.sub(v);
|
// vect.mul(-1);
|
//
|
// rotation.Transform(vect);
|
vect.set(v);
|
vect.sub(vect2);
|
|
int j3 = k*3;
|
|
float tx = v.tplane[j3] = (float)vect.dot(vect4);
|
float ty = v.tplane[j3+1] = (float)vect.dot(vect3);
|
float tz = v.tplane[j3+2] = (float)vect.dot(normal);
|
|
double normalweight = 1; // v.norm.dot(normal); // tz/Math.sqrt(tx*tx+ty*ty+tz*tz);
|
|
// vect.set(v.norm);
|
// //vect.sub(v2.norm);
|
|
// rotation.Transform(vect);
|
|
v.nplane[j3] = (float)v.norm.dot(vect4);
|
v.nplane[j3+1] = (float)v.norm.dot(vect3);
|
float nz = v.nplane[j3+2] = (float)v.norm.dot(normal);
|
|
vect.normalize();
|
|
// //if (nz < 0)
|
// //if (v.norm.dot(vect) < 0.9)
|
// if (tx*tx+ty*ty+tz*tz > 0.0025
|
// //|| nz < 0
|
// )
|
// normalweight = 0;
|
|
nz = nz+1;
|
|
//if (subsupports == 1)
|
nz = 1;
|
|
int j = supports[v.closestsupport].links[k];
|
|
if (j-1 == v.closestsupport)
|
{
|
tx = ty = 0;
|
}
|
// if (nz < 1)
|
// nz = 0;
|
|
// v.weights[j-1] *= v.nplane[j3+2];
|
v.weights[k] = other.ComputeWeight(v, toRoot, k); // (float)(supportsize * normalweight * nz / Math.pow(tx*tx+ty*ty+tz*tz, 1));
|
v.totalweight += v.weights[k];
|
|
if (Globals.CROWD)
|
{
|
// System.out.print("weight = " + v.weights[k]);
|
// System.out.println("; totalweight = " + v.totalweight);
|
}
|
}
|
|
// float max = -1;
|
// int maxj = 0;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (max < v.weights[j])
|
// {
|
// max = v.weights[j];
|
// maxj = j;
|
// }
|
// }
|
//
|
// // only three subsupports
|
// float max2 = -1;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] == max)
|
// continue;
|
//
|
// if (max2 < v.weights[j])
|
// max2 = v.weights[j];
|
// }
|
//
|
// float max3 = -1;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] == max)
|
// continue;
|
//
|
// if (v.weights[j] == max2)
|
// continue;
|
//
|
// if (max3 < v.weights[j])
|
// max3 = v.weights[j];
|
// }
|
//
|
// v.totalweight = 0;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] != max && v.weights[j] != max2) // && v.weights[j] != max3)
|
// {
|
// v.weights[j] = 0;
|
// }
|
//
|
// v.totalweight += v.weights[j];
|
// }
|
}
|
|
Vertex vert = new Vertex(true);
|
|
static // april 2014
|
cVector vect = new cVector();
|
static // april 2014
|
cVector normal = new cVector();
|
static // april 2014
|
cVector vect2 = new cVector();
|
static // april 2014
|
cVector vect3 = new cVector();
|
static // april 2014
|
cVector vect4 = new cVector();
|
static // june 2014
|
cVector vect5 = new cVector();
|
|
Support[] supports;
|
|
static boolean debug = false;
|
int debugcount = 0;
|
|
transient BoundaryRep transientsupport; // for cloning
|
|
transient boolean reduced; // for morph reduction
|
|
//transient
|
BoundaryRep support; // hmmmm..
|
|
static boolean patchKDTree;
|
|
// Set the T coordinates in the basis of the closest point (tangent plane)
|
// Performs search for only the two closest supports. The supports have to be connected.
|
void linkVerticesThis(BoundaryRep other, double[][] toRoot)
|
{
|
if (trimmed && other != null) // user warning?
|
{
|
Untrim(); // sept 2013
|
//return;
|
}
|
if (trimmed && other != null)
|
{
|
Untrim(); // sept 2013
|
assert(!trimmed);
|
}
|
|
if (other == support)
|
return; // already done... no relinkage. do reset first.
|
|
if (support != null)
|
{
|
setMasterThis(support, null, false, false); // june 2014
|
|
// nov 2013
|
// support = other;
|
// return;
|
}
|
|
support = other;
|
|
if (support == null)
|
{
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
v.closestsupport = -1;
|
|
v.vertexlinks = null;
|
v.vertexlinks2 = null;
|
v.weights = null;
|
v.tplane = null;
|
v.nplane = null;
|
}
|
return;
|
}
|
|
if (other.trimmed) // user warning
|
return;
|
|
if (vect == null || normal == null)
|
{
|
// serial
|
vect = new cVector();
|
normal = new cVector();
|
vect2 = new cVector();
|
vect3 = new cVector();
|
vect4 = new cVector();
|
}
|
|
if (LA.isIdentity(toRoot))
|
toRoot = null;
|
|
// july 2014
|
kdtrees = null;
|
|
if (other.startvertices == null)
|
{
|
linkVerticesThis0(other, toRoot); // who cares...
|
return;
|
}
|
|
int nbsupports;
|
|
// sept 2017 SEUIL = 0.1; // aout 2013
|
|
supports = other.InitConnections();
|
|
other.supports = supports; // should be the other way around...
|
|
assert(supports.length == other.startvertices.length-1);
|
|
nbsupports = supports.length;
|
|
double maxtotalweight = 0;
|
|
//
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
if (i == 2719)
|
i = 2719;
|
|
v.closestsupport = -1;
|
|
CameraPane.CreateSelectedPoint();
|
CameraPane.selectedpoint.
|
getAverage(cStatic.point1, true);
|
|
cStatic.point1.sub(v);
|
|
if (cStatic.point1.dot(cStatic.point1) < 0.00001)
|
{
|
v = v;
|
}
|
|
double mindistance = 1E10;
|
|
int subsupports = 0;
|
|
// sept 2017 SEUIL = 0.1; // aout 2013
|
|
while (subsupports == 0)
|
{
|
// find closest support
|
for (int j = 1; j <= nbsupports; j++)
|
{
|
if (j == 56)
|
j = 56;
|
|
patchKDTree = true;
|
int c = other.GetClosestIndex(v, false, toRoot, mindistance, j, true);
|
patchKDTree = false;
|
|
if (c == -1)
|
continue;
|
|
Vertex v2 = other.GetVertex(c);
|
|
vect2.set(v2);
|
LA.xformPos(vect2,toRoot,vect2);
|
|
vect.set(v);
|
vect.sub(vect2);
|
|
// vertextemp.x = other.averagepoints[c*3];
|
// vertextemp.y = other.averagepoints[c*3+1];
|
// vertextemp.z = other.averagepoints[c*3+2];
|
//
|
// Vertex v3 = vertextemp2;
|
// v3.x = other.extremepoints[c*3];
|
// v3.y = other.extremepoints[c*3+1];
|
// v3.z = other.extremepoints[c*3+2];
|
//
|
// vect3.set(v3); // "X" axis apex
|
// vect3.sub(vertextemp); // origin (center)
|
//
|
// double distmax = vect3.length();
|
//
|
// vect3.set(v2); // "X" axis apex
|
// vect3.sub(vertextemp); // origin (center)
|
//
|
// if (vect3.length() >= distmax)
|
// continue;
|
|
if (mindistance > vect.dot(vect))
|
{
|
// assert(mindistance == 1E10);
|
mindistance = vect.dot(vect);
|
v.closestsupport = j-1;
|
}
|
}
|
|
subsupports = v.closestsupport==-1 ? 0 : supports[v.closestsupport].Length();
|
|
// previously for "contains", now for weights.
|
assert(subsupports > 0);
|
//SEUIL *= 2;
|
}
|
|
assert(subsupports > 0);
|
|
v.vertexlinks = new int[subsupports];
|
v.vertexlinks2 = new int[subsupports];
|
v.weights = new float[subsupports];
|
v.tplane = new float[subsupports*3];
|
v.nplane = new float[subsupports*3];
|
|
// int numweights = 0;
|
|
for (int k = 0/*-1*/; k < subsupports; k++)
|
{
|
int j = 0;
|
|
try
|
{
|
if (k == -1)
|
j = v.closestsupport; // already in the list
|
else
|
j = supports[v.closestsupport].links[k];
|
|
if (j == 0)
|
continue;
|
|
patchKDTree = true;
|
v.vertexlinks[k] = other.GetClosestIndex(v, false, toRoot, 1E10, j, j-1 == v.closestsupport);
|
patchKDTree = false;
|
}
|
catch(Exception e)
|
{
|
e.printStackTrace();
|
break;
|
}
|
|
if (v.vertexlinks[k] == -1)
|
{
|
//assert(false); // assert?
|
continue;
|
}
|
|
Vertex v2 = other.GetVertex(v.vertexlinks[k]);
|
|
v.vertexlinks2[k] = other.GetClosestIndex(v2, true, null, 1E10, j, true);
|
|
//numweights += 1;
|
}
|
|
RecomputeBasis(other, toRoot, v);
|
|
if (maxtotalweight < v.totalweight)
|
maxtotalweight = v.totalweight;
|
|
v = v;
|
if (v.totalweight == 0)
|
{
|
// assert(false);
|
// new Exception().printStackTrace();
|
// System.err.println("Total weight = 0!");
|
// v.totalweight = 1; // empty support ?!?
|
}
|
else
|
{
|
// assert(subsupports >= 2);
|
|
// float max = -1;
|
// int maxj = 0;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (max < v.weights[j])
|
// {
|
// max = v.weights[j];
|
// maxj = j;
|
// }
|
// }
|
//
|
// // only three subsupports
|
// float max2 = -1;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] == max)
|
// continue;
|
//
|
// if (max2 < v.weights[j])
|
// max2 = v.weights[j];
|
// }
|
//
|
//// float max3 = -1;
|
////
|
//// for (int j = 0; j < subsupports; j++)
|
//// {
|
//// if (v.weights[j] == max)
|
//// continue;
|
////
|
//// if (v.weights[j] == max2)
|
//// continue;
|
////
|
//// if (max3 < v.weights[j])
|
//// max3 = v.weights[j];
|
//// }
|
//
|
// v.totalweight = 0;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] != max && v.weights[j] != max2)
|
// {
|
// v.weights[j] = 0;
|
// }
|
//
|
// v.totalweight += v.weights[j];
|
// }
|
|
//// v.totalweight = max + max2;
|
|
// group of subsupports
|
// while (numweights > 2)
|
// {
|
// int numw = 0;
|
//
|
// for (int j = 1; j < subsupports + 1; j++)
|
// {
|
// if (v.weights[j-1]/v.totalweight < 0.2)
|
// {
|
// continue;
|
// }
|
//
|
// numw += 1;
|
// }
|
//
|
// if (numw <= 2)
|
// break;
|
//
|
// float newtotal = 0;
|
//
|
// numweights = 0;
|
//
|
// for (int j = 1; j < subsupports + 1; j++)
|
// {
|
// if (v.weights[j-1]/v.totalweight < 0.2)
|
// {
|
// v.weights[j-1] = 0;
|
// }
|
//
|
// newtotal += v.weights[j-1];
|
// numweights += 1;
|
// }
|
//
|
// if (newtotal == v.totalweight)
|
// break;
|
//
|
// v.totalweight = newtotal;
|
// }
|
|
// if (v.totalweight == 0)
|
// {
|
// assert(false);
|
// v.totalweight = v.weights[maxj] = 1;
|
// }
|
}
|
|
// if (v.totalweight == 0)
|
// new Exception().printStackTrace();
|
}
|
|
if (true) // ????? june 2013 nbsupports > 2)
|
SmoothWeights();
|
else
|
{
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
v.totalweight /= maxtotalweight;
|
}
|
}
|
}
|
|
void SmoothVertexWeight(float[] v, Vertex v0)
|
{
|
for (int wi = v0.weights.length; --wi>=0;)
|
v[wi] = 0;
|
|
CameraPane.CreateSelectedPoint();
|
CameraPane.selectedpoint.
|
getAverage(cStatic.point1, true);
|
|
cStatic.point1.sub(v0);
|
|
if (cStatic.point1.dot(cStatic.point1) < 0.00001)
|
v0 = v0;
|
|
|
//int facecount = 0;
|
double angle = 0;
|
|
// for (int fi = FaceCount(); --fi>=0;)
|
for (int fii = 0; fii < v0.faceindices.length; fii++)
|
{
|
int fi = v0.faceindices[fii];
|
|
if (fi == -1)
|
break;
|
|
Face f = GetFace(fi);
|
|
Vertex p = GetVertex(f.p);
|
Vertex q = GetVertex(f.q);
|
Vertex r = GetVertex(f.r);
|
|
// if (v0 != p && v0 != q && v0 != r)
|
// continue; // vertex is not in the face
|
|
//facecount += 1;
|
|
// rotate for p to be v2
|
while (p != v0)
|
{
|
Vertex t = p;
|
p = q;
|
q = r;
|
r = t;
|
}
|
|
// normal to the plane
|
vect2.set(q);
|
vect2.sub(p);
|
|
double dot = vect2.dot(p.norm);
|
vect2.add(p.norm, -dot);
|
|
// vect3.set(vect2);
|
vect3.set(r);
|
vect3.sub(p);
|
|
dot = vect3.dot(p.norm);
|
vect3.add(p.norm, -dot);
|
|
vect2.normalize();
|
vect3.normalize();
|
|
//normal.cross(vect2, vect3);
|
angle += Math.acos(vect2.dot(vect3));
|
|
for (int wi = 0; wi < v0.weights.length; wi++)
|
{
|
if (p == v0 || v0.closestsupport == p.closestsupport)
|
v[wi] += p.weights[wi];
|
else
|
{
|
int support = supports[v0.closestsupport].links[wi];
|
|
int index = supports[p.closestsupport].IndexOf(support);
|
|
if (index != -1)
|
v[wi] += p.weights[index];
|
}
|
|
if (q == v0 || v0.closestsupport == q.closestsupport)
|
v[wi] += q.weights[wi];
|
else
|
{
|
int support = supports[v0.closestsupport].links[wi];
|
|
int index = supports[q.closestsupport].IndexOf(support);
|
|
if (index != -1)
|
v[wi] += q.weights[index];
|
}
|
|
if (r == v0 || v0.closestsupport == r.closestsupport)
|
v[wi] += r.weights[wi];
|
else
|
{
|
int support = supports[v0.closestsupport].links[wi];
|
|
int index = supports[r.closestsupport].IndexOf(support);
|
|
if (index != -1)
|
v[wi] += r.weights[index];
|
}
|
}
|
}
|
|
v0.totalweight = 0;
|
for (int wi = 0; wi < v0.weights.length; wi++)
|
{
|
if (Math.abs(angle - 2*Math.PI) < Math.PI/16) // && facecount > 4)
|
{
|
// v[wi] /= facecount*3;
|
angle = angle;
|
}
|
else
|
// border vertex. keep original weights.
|
v[wi] = v0.weights[wi];
|
v0.totalweight += v[wi];
|
}
|
|
if (v0.totalweight == 0)
|
v0.totalweight = 1;
|
|
for (int wi = 0; wi < v0.weights.length; wi++)
|
{
|
v[wi] /= v0.totalweight;
|
}
|
|
v0.totalweight = 1;
|
}
|
|
void SmoothVertex(Vertex v0, Vertex v2)
|
{
|
double keepx = v0.x;
|
double keepy = v0.y;
|
double keepz = v0.z;
|
double keepnx = v0.norm.x;
|
double keepny = v0.norm.y;
|
double keepnz = v0.norm.z;
|
|
v0.x = v0.y = v0.z = 0;
|
v0.norm.x = v0.norm.y = v0.norm.z = 0;
|
|
CameraPane.CreateSelectedPoint();
|
CameraPane.selectedpoint.
|
getAverage(cStatic.point1, true);
|
|
cStatic.point1.sub(v0);
|
|
if (cStatic.point1.dot(cStatic.point1) < 0.00001)
|
v0 = v0;
|
|
double weight = 0;
|
|
//int facecount = 0;
|
double angle = 0;
|
|
// for (int fi = FaceCount(); --fi>=0;)
|
for (int fii = 0; fii < v0.faceindices.length; fii++)
|
{
|
int fi = v0.faceindices[fii];
|
|
if (fi == -1)
|
break;
|
|
Face f = GetFace(fi);
|
|
Vertex p = GetVertex(f.p);
|
Vertex q = GetVertex(f.q);
|
Vertex r = GetVertex(f.r);
|
|
// if (v0 != p && v0 != q && v0 != r)
|
// continue; // vertex is not in the face
|
|
//facecount += 1;
|
|
// rotate for p to be v2
|
while (p != v2)
|
{
|
Vertex t = p;
|
p = q;
|
q = r;
|
r = t;
|
}
|
|
// normal to the plane
|
vect2.set(q);
|
vect2.sub(p);
|
|
// vect3.set(vect2);
|
vect3.set(r);
|
vect3.sub(p);
|
|
double dot = vect2.dot(p.norm);
|
vect2.add(p.norm, -dot);
|
dot = vect3.dot(p.norm);
|
vect3.add(p.norm, -dot);
|
|
vect2.normalize();
|
vect3.normalize();
|
|
//normal.cross(vect2, vect3);
|
angle += Math.acos(vect2.dot(vect3));
|
|
v0.x += p.x;
|
v0.y += p.y;
|
v0.z += p.z;
|
v0.norm.x += p.norm.x;
|
v0.norm.y += p.norm.y;
|
v0.norm.z += p.norm.z;
|
v0.x += q.x;
|
v0.y += q.y;
|
v0.z += q.z;
|
v0.norm.x += q.norm.x;
|
v0.norm.y += q.norm.y;
|
v0.norm.z += q.norm.z;
|
v0.x += r.x;
|
v0.y += r.y;
|
v0.z += r.z;
|
v0.norm.x += r.norm.x;
|
v0.norm.y += r.norm.y;
|
v0.norm.z += r.norm.z;
|
|
weight += 3;
|
}
|
|
// for (int wi = 0; wi < v0.weights.length; wi++)
|
{
|
if (Math.abs(angle - 2*Math.PI) < Math.PI/32) // && facecount > 4)
|
{
|
// v[wi] /= facecount*3;
|
v0.x /= weight;
|
v0.y /= weight;
|
v0.z /= weight;
|
v0.norm.normalize();
|
}
|
else
|
{
|
// border vertex. keep original.
|
v0.x = keepx;
|
v0.y = keepy;
|
v0.z = keepz;
|
v0.norm.x = keepnx;
|
v0.norm.y = keepny;
|
v0.norm.z = keepnz;
|
}
|
}
|
}
|
|
void InitFaceIndices()
|
{
|
for (int vi = 0; vi < VertexCount(); vi++)
|
{
|
GetVertex(vi).faceindices = new int[16];
|
|
for (int i=GetVertex(vi).faceindices.length; --i>=0;)
|
{
|
GetVertex(vi).faceindices[i] = -1;
|
}
|
}
|
|
for (int fi = FaceCount(); --fi>=0;)
|
{
|
Face f = GetFace(fi);
|
|
Vertex p = GetVertex(f.p);
|
|
if (!p.ContainsFace(fi))
|
{
|
p.AddFace(fi);
|
}
|
|
p = GetVertex(f.q);
|
|
if (!p.ContainsFace(fi))
|
{
|
p.AddFace(fi);
|
}
|
|
p = GetVertex(f.r);
|
|
if (!p.ContainsFace(fi))
|
{
|
p.AddFace(fi);
|
}
|
}
|
}
|
|
void SmoothWeights()
|
{
|
if (GetVertex(0).faceindices == null)
|
{
|
InitFaceIndices();
|
}
|
|
BoundaryRep rep = (BoundaryRep) Grafreed.clone(this);
|
//float[] v = new float[100];
|
|
for (int loops=1; --loops>=0;)
|
{
|
System.err.println("Smooth pass #" + loops);
|
for (int vi = 0; vi < VertexCount(); vi++)
|
{
|
Vertex v = rep.GetVertex(vi);
|
|
SmoothVertexWeight(v.weights, GetVertex(vi));
|
}
|
|
for (int vi = 0; vi < VertexCount(); vi++)
|
{
|
Vertex v0 = GetVertex(vi);
|
Vertex v = rep.GetVertex(vi);
|
|
System.arraycopy(v.weights, 0, v0.weights, 0, v0.weights.length);
|
}
|
}
|
}
|
|
void SmoothMesh()
|
{
|
if (GetVertex(0).faceindices == null)
|
{
|
InitFaceIndices();
|
}
|
|
BoundaryRep rep = (BoundaryRep) Grafreed.clone(this);
|
//float[] v = new float[100];
|
|
for (int loops=10; --loops>=0;)
|
{
|
for (int vi = 0; vi < VertexCount(); vi++)
|
{
|
Vertex v = rep.GetVertex(vi);
|
|
SmoothVertex(v, GetVertex(vi));
|
}
|
|
for (int vi = 0; vi < VertexCount(); vi++)
|
{
|
Vertex v0 = GetVertex(vi);
|
Vertex v = rep.GetVertex(vi);
|
|
//System.arraycopy(v.weights, 0, v0.weights, 0, v0.weights.length);
|
v0.set(v);
|
}
|
}
|
}
|
|
|
// Set the T coordinates in the base of the closest point (tangent plane)
|
// performs full search with multiple supports, artifact problems
|
void linkVerticesThis0(BoundaryRep other, double[][] toRoot)
|
{
|
if (trimmed)
|
return;
|
// assert(!trimmed);
|
|
// cVector vect = new cVector();
|
// cVector normal = new cVector();
|
// cVector vect2 = new cVector();
|
// cVector vect3 = new cVector();
|
// cVector vect4 = new cVector();
|
|
if (vect == null || normal == null)
|
{
|
// serial
|
vect = new cVector();
|
normal = new cVector();
|
vect2 = new cVector();
|
vect3 = new cVector();
|
vect4 = new cVector();
|
}
|
|
// cQuat quat = new cQuat();
|
// cVector axis = new cVector();
|
// cMatrix3x3 rotation = new cMatrix3x3();
|
|
int subsupports = 1;
|
|
if (other.startvertices != null)
|
subsupports = other.startvertices.length-1;
|
|
assert(subsupports == 1);
|
|
other.InitVertexTable();
|
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
if (i == 5180) // NaN issue due to Trim!!
|
i = 5180;
|
|
Vertex v = GetVertex(i);
|
|
v.vertexlinks = null; // new int[subsupports]; // very memory consuming...
|
v.vertexlinks2 = null; // new int[subsupports];
|
v.weights = null; // new float[subsupports];
|
v.tplane = null; // new float[subsupports*3];
|
v.nplane = null; // new float[subsupports*3];
|
|
v.totalweight = 0;
|
|
int numweights = 0;
|
|
for (int j = 1; j < subsupports+1; j++)
|
{
|
Vertex cache = other.GetCache(v);
|
|
if (cache != null && toRoot == null)
|
{
|
// special case
|
v.vertexlink/*s[j-1]*/ = cache.index;
|
|
int j3 = (j-1)*3;
|
|
v.tx = 0; // plane[j3] = 0;
|
v.ty = 0; // plane[j3+1] = 0;
|
v.tz = 0; // plane[j3+2] = 0;
|
|
// v.weights[j-1] = 1;
|
v.totalweight = 1;
|
|
continue;
|
}
|
//else
|
// System.exit(0);
|
|
// assert(false);
|
|
// do full search
|
v.vertexlink /*s[j-1]*/ = other.GetClosestIndex(v, false, toRoot, 1E10, j, false);
|
|
if (v.vertexlink /*s[j-1]*/ == -1)
|
{
|
//assert(false); // assert?
|
continue;
|
}
|
|
Vertex v2 = other.GetVertex(v.vertexlink/*s[j-1]*/);
|
|
v.vertexlink2/*s2[j-1]*/ = other.GetClosestIndex(v2, true, null, 1E10, j, true);
|
// (v.vertexlink+1) % VertexCount(); // june 2014
|
|
if (v.vertexlink2/*s2[j-1]*/ == -1)
|
continue; // ??? v.vertexlinks2[j-1] = -1;
|
|
Vertex v3 = other.GetVertex(v.vertexlink2/*s2[j-1]*/);
|
|
vect2.set(v2);
|
|
LA.xformPos(vect2,toRoot,vect2);
|
|
vect3.set(v3);
|
LA.xformPos(vect3,toRoot,vect3);
|
|
vect3.sub(vect2);
|
|
normal.set(v2.norm); // v2
|
// normal.add(v2.norm);
|
LA.xformDir(normal,toRoot,normal);
|
// normal.sub(vect2);
|
|
normal.normalize();
|
|
double dot = vect3.dot(normal);
|
|
vect.set(normal);
|
vect.mul(dot);
|
vect3.sub(vect);
|
vect3.normalize();
|
|
// assert(vect3.dot(normal) == 0);
|
|
vect4.cross(normal, vect3);
|
|
// assert(vect4.length() == 1);
|
|
// axis.set(0,0,1);
|
// quat.setRotation(normal, axis);
|
// rotation.setRotation(quat);
|
//
|
//// vect.set(v);
|
//// vect.sub(v2);
|
// vect.sub(v);
|
// vect.mul(-1);
|
//
|
// rotation.Transform(vect);
|
vect.set(v);
|
vect.sub(vect2);
|
|
int j3 = (j-1)*3;
|
|
float tx = v.tx/*plane[j3]*/ = (float)vect.dot(vect4);
|
float ty = v.ty/*plane[j3+1]*/ = (float)vect.dot(vect3);
|
float tz = v.tz/*plane[j3+2]*/ = (float)vect.dot(normal);
|
|
double normalweight = 1; // v.norm.dot(normal); // tz/Math.sqrt(tx*tx+ty*ty+tz*tz);
|
|
// vect.set(v.norm);
|
// //vect.sub(v2.norm);
|
|
// rotation.Transform(vect);
|
|
v.nx/*plane[j3]*/ = (float)v.norm.dot(vect4);
|
v.ny/*plane[j3+1]*/ = (float)v.norm.dot(vect3);
|
float nz = v.nz/*plane[j3+2]*/ = (float)v.norm.dot(normal);
|
|
vect.normalize();
|
|
// //if (nz < 0)
|
// //if (v.norm.dot(vect) < 0.9)
|
// if (tx*tx+ty*ty+tz*tz > 0.0025
|
// //|| nz < 0
|
// )
|
// normalweight = 0;
|
|
nz = nz+1;
|
|
if (subsupports == 1)
|
nz = 1;
|
|
// if (nz < 1)
|
// nz = 0;
|
|
// v.weights[j-1] *= v.nplane[j3+2];
|
// v.weights[j-1] = 1; // nov 2012 (float)(normalweight * nz / Math.pow(tx*tx+ty*ty+tz*tz, 1.5));
|
// v.totalweight += v.weights[j-1];
|
v.totalweight = 1;
|
|
numweights += 1;
|
}
|
|
v = v;
|
if (v.totalweight == 0)
|
{
|
// assert(false);
|
// new Exception().printStackTrace();
|
System.err.println("Total weight = 0!");
|
// v.totalweight = 1;
|
}
|
else
|
{
|
// System.err.println("Total weight != 0!");
|
// float max = -1;
|
// int maxj = 0;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (max < v.weights[j])
|
// {
|
// max = v.weights[j];
|
// maxj = j;
|
// }
|
// }
|
//
|
// // only two subsupports
|
// float max2 = -1;
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] == max)
|
// continue;
|
//
|
// if (max2 < v.weights[j])
|
// max2 = v.weights[j];
|
// }
|
//
|
// for (int j = 0; j < subsupports; j++)
|
// {
|
// if (v.weights[j] == max)
|
// continue;
|
// if (v.weights[j] == max2)
|
// continue;
|
//
|
// v.weights[j] = 0;
|
// }
|
//
|
// v.totalweight = max + max2;
|
//
|
// // group of subsupports
|
//// while (numweights > 2)
|
//// {
|
//// int numw = 0;
|
////
|
//// for (int j = 1; j < subsupports + 1; j++)
|
//// {
|
//// if (v.weights[j-1]/v.totalweight < 0.2)
|
//// {
|
//// continue;
|
//// }
|
////
|
//// numw += 1;
|
//// }
|
////
|
//// if (numw <= 2)
|
//// break;
|
////
|
//// float newtotal = 0;
|
////
|
//// numweights = 0;
|
////
|
//// for (int j = 1; j < subsupports + 1; j++)
|
//// {
|
//// if (v.weights[j-1]/v.totalweight < 0.2)
|
//// {
|
//// v.weights[j-1] = 0;
|
//// }
|
////
|
//// newtotal += v.weights[j-1];
|
//// numweights += 1;
|
//// }
|
////
|
//// if (newtotal == v.totalweight)
|
//// break;
|
////
|
//// v.totalweight = newtotal;
|
//// }
|
//
|
// if (v.totalweight == 0)
|
// {
|
// assert(false);
|
// v.totalweight = v.weights[maxj] = 1;
|
// }
|
}
|
|
// if (v.totalweight == 0)
|
// new Exception().printStackTrace();
|
}
|
|
//SmoothWeights();
|
}
|
|
void Print(Vertex v)
|
{
|
System.err.print("(" + v.x + ", " + v.y + ", " + v.z + "); ");
|
}
|
|
void Println(String s)
|
{
|
System.err.println(s);
|
}
|
|
// int tickcount = 0; // slow pose issue
|
|
static boolean exceptionstack;
|
|
// Update the current positions according to new support mesh (closest point tangent plane)
|
|
void setMasterThis(BoundaryRep other, double[][] toRoot, boolean smooth, boolean marked)
|
{
|
if (other == this)
|
{
|
System.err.println("Cannot link object " + this + " to itself.");
|
return;
|
}
|
|
if (LA.isIdentity(toRoot))
|
toRoot = null;
|
|
if (trimmed)
|
return;
|
// assert(!trimmed);
|
|
int subsupports = 1;
|
|
if (other.startvertices != null)
|
subsupports = other.startvertices.length-1;
|
else
|
{
|
setMasterThis0(other, toRoot, smooth, marked);
|
return;
|
}
|
|
// System.exit(0);
|
|
cVector vect = new cVector();
|
cVector normal = new cVector();
|
cVector vect2 = new cVector();
|
cVector vect3 = new cVector();
|
cVector vect4 = new cVector();
|
cVector tmp = new cVector();
|
cVector v0 = new cVector();
|
cVector n0 = new cVector();
|
// cQuat quat = new cQuat();
|
// cVector axis = new cVector();
|
// cMatrix3x3 rotation = new cMatrix3x3();
|
|
cVector vtotal = new cVector();
|
cVector ntotal = new cVector();
|
|
// toRoot = null;
|
|
// aout 2013 float height = 0;
|
//
|
// for (int i = 0; i < VertexCount(); i++)
|
// {
|
// height += GetVertex(i).y;
|
// }
|
// height /= VertexCount();
|
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
// if (i == 5180)
|
// i = 5180;
|
|
Vertex v = GetVertex(i);
|
|
// aout 2013 if (v.totalweight == 0)
|
// continue;
|
|
// aout 2013 if (CameraPane.CROWD) // && Math.abs(v.y - height) < 0.01) // weightmode)
|
//{
|
//// RecomputeBasis(other, toRoot, v);
|
//}
|
|
// aout 2013 if (i == 0)
|
// {
|
// // System.err.println("setMasterThis " + this + " : " + other);
|
// // System.err.println(" vertex(0) = " + v.x + ", " + v.y + ", " + v.z);
|
// }
|
|
// Print(v);
|
|
if (v.vertexlinks != null)
|
subsupports = v.vertexlinks.length; // ???
|
|
// aout 2-13 vtotal.set(v); // 0,0,0);
|
// ntotal.set(v.norm); // 0,0,0);
|
|
vtotal.mul(0); // 1 - v.totalweight);
|
ntotal.mul(0); // 1 - v.totalweight);
|
|
// float normalweight = 0;
|
|
int count = 0;
|
|
// double testweight = 0;
|
|
//for (int j = 1; j <= subsupports; j++)
|
for (int j = 0; j < subsupports; j++)
|
{
|
if (v.vertexlinks == null)
|
continue;
|
|
// Warning: faster but dangerous
|
if (v.weights != null && v.weights[j]
|
== 0)
|
// < 0.001 * v.totalweight)
|
{
|
//testweight += v.weights[j-1];
|
continue;
|
}
|
|
int vlink = v.vertexlinks[j];
|
|
if (vlink == -1)
|
continue; // no support
|
|
int vlink2 = v.vertexlinks2[j];
|
|
assert(vlink2 != -1);
|
// if (vlink2 == -1)
|
// continue; // strange...
|
|
// if (v.totalweight == 0)
|
// continue;
|
|
count++;
|
|
int j3 = j*3;
|
|
float tx = v.tplane[j3];
|
float ty = v.tplane[j3+1];
|
float tz = v.tplane[j3+2];
|
|
if (tx == 0 && ty == 0 && tz == 0)
|
{
|
// special case
|
Vertex v2 = other.GetVertex(vlink);
|
|
v0.set(v2);
|
LA.xformPos(v0,toRoot,v0);
|
// v.norm.set(v2.norm);
|
// LA.xformDir(v.norm,toRoot,v.norm);
|
// normal.set(v.norm);
|
n0.set(v2.norm);
|
LA.xformDir(n0,toRoot,n0);
|
normal.set(n0);
|
}
|
else
|
{
|
Vertex v2 = other.GetVertex(vlink);
|
Vertex v3 = other.GetVertex(vlink2);
|
|
vect3.set(v3);
|
|
normal.set(v2.norm);
|
// //normal.add(v2.norm);
|
|
if (toRoot != null)
|
{
|
vect2.set(v2);
|
LA.xformDir(normal,toRoot,normal);
|
// //normal.sub(vect2);
|
normal.normalize();
|
|
LA.xformPos(vect2,toRoot,vect2);
|
LA.xformPos(vect3,toRoot,vect3);
|
vect3.sub(vect2);
|
}
|
else
|
vect3.sub(v2);
|
|
// vect3.sub(vect2);
|
|
// normal.normalize();
|
|
double dot = vect3.dot(normal);
|
|
//vect.set(normal);
|
//vect.mul(dot);
|
vect.set(normal,dot);
|
vect3.sub(vect);
|
vect3.normalize();
|
|
// if (vect3.dot(normal) != 0)
|
// assert(vect3.dot(normal) == 0);
|
|
vect4.cross(normal, vect3);
|
|
// assert(vect4.length() == 1);
|
|
//tmp.set(vect4);
|
//tmp.mul(v.tplane[j3]);
|
//v0.set(tmp);
|
v0.set(vect4, tx); // v.tplane[j3]);
|
|
//tmp.set(vect3);
|
//tmp.mul(v.tplane[j3+1]);
|
v0.add(vect3, ty); // v.tplane[j3+1]);
|
//v0.add(tmp);
|
|
//tmp.set(normal);
|
//tmp.mul(v.tplane[j3+2]);
|
v0.add(normal, tz); // v.tplane[j3+2]);
|
//v0.add(tmp);
|
|
if (toRoot != null)
|
v0.add(vect2);
|
else
|
v0.add(v2);
|
|
// if (v.weights != null)
|
// {
|
//// testweight += v.weights[j];
|
// v0.mul(v.weights[j]/v.totalweight); // ?? tentative de non-normalisation (modeling)
|
// }
|
|
// vect4.mul(v.nplane[j3]);
|
// vect3.mul(v.nplane[j3+1]);
|
// normal.mul(v.nplane[j3+2]);
|
|
// normalweight += Math.abs(v.nplane[j3+2]);
|
|
normal.set(normal, v.nplane[j3+2]);
|
normal.add(vect4, v.nplane[j3]);
|
normal.add(vect3, v.nplane[j3+1]);
|
|
// assert norm == 1?
|
|
if (v.weights != null)
|
{
|
v0.mul(v.weights[j]/v.totalweight); // ?? tentative de non-normalisation (modeling)
|
normal.mul(v.weights[j]); // /v.totalweight);
|
}
|
}
|
//else
|
{
|
// Vertex v2 = other.GetVertex(v.vertexlink);
|
//
|
// vect.set(v2);
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// v.set(vect);
|
//
|
// axis.set(0,0,1);
|
//
|
// vect.set(v2.norm);
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// quat.setRotation(axis, vect);
|
// rotation.setRotation(quat);
|
//
|
// vect.set(v.tx,v.ty,v.tz);
|
// rotation.Transform(vect);
|
// v.add(vect);
|
//
|
// // support normals
|
// vect.set(v2.norm);
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// v.norm.set(vect);
|
// // }
|
// // else
|
// if (true)
|
// {
|
// vect.set(v.nx,v.ny,v.nz);
|
// rotation.Transform(vect);
|
// v.norm.set(vect);
|
// }
|
}
|
// v.set(v2);
|
// v.norm.set(v2.norm);
|
|
// douteux...
|
// double len2 = vect.length2();
|
// vect.normalize();
|
//
|
// double dot = v.norm.dot(vect);
|
// vect.mul(Math.exp(-0.001/len2)*dot);
|
// v.norm.sub(vect);
|
// v.norm.normalize();
|
|
vtotal.add(v0);
|
ntotal.add(normal);
|
}
|
|
if (count == 0)
|
{
|
if (!exceptionstack)
|
new Exception().printStackTrace();
|
exceptionstack = true;
|
continue;
|
}
|
|
// vtotal.mul(1.0/(other.startvertices.length-1));
|
// ntotal.mul(1.0/(other.startvertices.length-1));
|
|
//v.set(vtotal);
|
|
if (/*!CameraPane.INERTIA ||*/ CameraPane.FAST || /*subsupports == 1 ||*/!smooth || CameraPane.fullreset) // jump to target
|
{
|
// aout 2013 // not mid point
|
// v0.set(vtotal);
|
//
|
// if (vtotal.dot(vtotal) == 0)
|
// vtotal = vtotal;
|
//
|
// v0.sub(v);
|
// // double weight = Math.exp(-normalweight/10);
|
//
|
// // if (weight > 0.5)
|
// // weight = 0;
|
//
|
// // v0.mul(weight);
|
// v.add(v0);
|
|
// ???????????
|
v.set(vtotal); //
|
v.norm.set(ntotal);
|
}
|
else // halfway through
|
{
|
// System.exit(-1);
|
// PROBLEM with CROWD!!
|
float W = 8; // 10;
|
|
// if (slow)
|
// aout 2013
|
// sept 2013 merde...
|
W = 13; // 13;
|
|
// POSERATE
|
if (CameraPane.tickcount > 0 || CameraPane.SLOWPOSE)
|
{
|
// if (CameraPane.tickcount > 0)
|
// CameraPane.tickcount--;
|
// W = 150;
|
W = 40;
|
|
if (CameraPane.SLOWPOSE)
|
W = 150;
|
}
|
// W = 30;
|
|
if (!CameraPane.INERTIA)
|
{
|
W = 1;
|
if (CameraPane.SLOWPOSE)
|
W = 8;
|
}
|
|
v.mul(W - 1);
|
v.add(vtotal);
|
v.mul(1/W);
|
|
ntotal.normalize();
|
v.norm.mul(W - 1);
|
v.norm.add(ntotal);
|
// v.norm.mul(1/W);
|
}
|
|
v.norm.normalize();
|
|
// aout 2013 if (other.startvertices != null)
|
// if (Math.abs(testweight - v.totalweight)/testweight > 1E-2)
|
// {
|
//// System.err.println("WEIGHT problem");
|
// //new Exception().printStackTrace(); // assert(Math.abs(testweight - v.totalweight)/testweight < 1E-2);
|
// }
|
|
// Recompute weights
|
if (supports != null) // backward compatibility: only for newly linked
|
{
|
// if (other.supports != null)
|
// RecomputeBasis(other, toRoot, v);
|
}
|
|
// Print(v);
|
// Println("");
|
}
|
}
|
|
//boolean stepin;
|
transient boolean stepout;
|
|
transient int lastsoundtime;
|
|
transient boolean once = false;
|
|
void setMasterThis0(BoundaryRep other, double[][] toRoot, boolean smooth, boolean marked)
|
{
|
if (LA.isIdentity(toRoot))
|
toRoot = null;
|
|
if (trimmed)
|
return;
|
// assert(!trimmed);
|
|
cVector vect = new cVector();
|
cVector normal = new cVector();
|
cVector vect2 = new cVector();
|
cVector vect3 = new cVector();
|
cVector vect4 = new cVector();
|
cVector tmp = new cVector();
|
cVector v0 = new cVector();
|
cVector n0 = new cVector();
|
// cQuat quat = new cQuat();
|
// cVector axis = new cVector();
|
// cMatrix3x3 rotation = new cMatrix3x3();
|
|
int subsupports = 1;
|
|
assert (other.startvertices == null);
|
|
double height = Double.MAX_VALUE;
|
|
if (marked)
|
for (int i = 0; i < other.VertexCount(); i++)
|
{
|
Vertex v = other.GetVertex(i);
|
|
if (height > v.y)
|
height = v.y;
|
}
|
|
cVector vtotal = new cVector();
|
cVector ntotal = new cVector();
|
|
// toRoot = null;
|
|
boolean onein = false;
|
boolean allout = true;
|
|
// boolean slowposed = false;
|
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
if (i == 5180)
|
i = 5180;
|
|
Vertex v = GetVertex(i);
|
|
if (v.totalweight == 0)
|
{
|
if (!once)
|
{
|
System.err.println("v.totalweight == 0! --> " + this + " : " + other);
|
once = true;
|
}
|
continue;
|
}
|
|
if (i == 0)
|
{
|
// System.err.println("setMasterThis " + this + " : " + other);
|
// System.err.println(" vertex(0) = " + v.x + ", " + v.y + ", " + v.z);
|
}
|
|
// Print(v);
|
|
vtotal.set(0,0,0);
|
ntotal.set(0,0,0);
|
|
int count = 0;
|
|
for (int j = 1; j <= subsupports; j++)
|
{
|
int vlink = v.vertexlink; // s[j-1];
|
if (vlink == -1)
|
continue; // no support
|
|
int vlink2 = v.vertexlink2; // s2[j-1];
|
// if (vlink2 == -1)
|
// continue; // strange...
|
|
// if (v.totalweight == 0)
|
// continue;
|
|
if (v.weights != null && v.weights[j-1] == 0) // < 0.01 * v.totalweight) // == 0)
|
{
|
//testweight += v.weights[j-1];
|
continue;
|
}
|
|
count++;
|
|
//int j3 = (j-1)*3;
|
|
if (v.tx == 0 && v.ty == 0 && v.tz == 0) // plane[j3] == 0 && v.tplane[j3+1] == 0 && v.tplane[j3+2] == 0)
|
{
|
// special case
|
Vertex v2 = other.GetVertex(vlink);
|
|
v0.set(v2);
|
n0.set(v2.norm);
|
if (toRoot != null)
|
{
|
LA.xformPos(v0,toRoot,v0);
|
LA.xformDir(n0,toRoot,n0);
|
}
|
normal.set(n0);
|
}
|
else
|
{
|
Vertex v2 = other.GetVertex(vlink);
|
Vertex v3 = other.GetVertex(vlink2);
|
|
vect2.set(v2);
|
vect3.set(v3);
|
|
normal.set(v2.norm);
|
|
if (toRoot != null)
|
{
|
LA.xformPos(vect2,toRoot,vect2);
|
LA.xformPos(vect3,toRoot,vect3);
|
|
LA.xformDir(normal,toRoot,normal);
|
// //normal.sub(vect2);
|
|
normal.normalize();
|
}
|
|
vect3.sub(vect2);
|
|
// //normal.add(v2.norm);
|
|
double dot = vect3.dot(normal);
|
|
//vect.set(normal);
|
//vect.mul(dot);
|
vect.set(normal,dot);
|
vect3.sub(vect);
|
vect3.normalize();
|
|
// if (vect3.dot(normal) != 0)
|
// assert(vect3.dot(normal) == 0);
|
|
vect4.cross(normal, vect3);
|
|
// assert(vect4.length() == 1);
|
|
//tmp.set(vect4);
|
//tmp.mul(v.tplane[j3]);
|
//v0.set(tmp);
|
v0.set(vect4, v.tx); // plane[j3]);
|
|
//tmp.set(vect3);
|
//tmp.mul(v.tplane[j3+1]);
|
v0.add(vect3, v.ty); // plane[j3+1]);
|
//v0.add(tmp);
|
|
//tmp.set(normal);
|
//tmp.mul(v.tplane[j3+2]);
|
v0.add(normal, v.tz); // plane[j3+2]);
|
//v0.add(tmp);
|
|
v0.add(vect2);
|
|
// if (v.weights != null)
|
// {
|
// testweight += v.weights[j-1];
|
// v0.mul(v.weights[j-1]/v.totalweight);
|
// }
|
|
// vect4.mul(v.nplane[j3]);
|
// vect3.mul(v.nplane[j3+1]);
|
// normal.mul(v.nplane[j3+2]);
|
|
// normalweight += Math.abs(v.nplane[j3+2]);
|
|
normal.set(normal, v.nz); // plane[j3+2]);
|
normal.add(vect4, v.nx); // plane[j3]);
|
normal.add(vect3, v.ny); // plane[j3+1]);
|
|
// assert norm == 1?
|
|
// if (v.weights != null)
|
// {
|
// normal.mul(v.weights[j-1]); // /v.totalweight);
|
// }
|
}
|
//else
|
{
|
// Vertex v2 = other.GetVertex(v.vertexlink);
|
//
|
// vect.set(v2);
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// v.set(vect);
|
//
|
// axis.set(0,0,1);
|
//
|
// vect.set(v2.norm);
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// quat.setRotation(axis, vect);
|
// rotation.setRotation(quat);
|
//
|
// vect.set(v.tx,v.ty,v.tz);
|
// rotation.Transform(vect);
|
// v.add(vect);
|
//
|
// // support normals
|
// vect.set(v2.norm);
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// v.norm.set(vect);
|
// // }
|
// // else
|
// if (true)
|
// {
|
// vect.set(v.nx,v.ny,v.nz);
|
// rotation.Transform(vect);
|
// v.norm.set(vect);
|
// }
|
}
|
// v.set(v2);
|
// v.norm.set(v2.norm);
|
|
// douteux...
|
// double len2 = vect.length2();
|
// vect.normalize();
|
//
|
// double dot = v.norm.dot(vect);
|
// vect.mul(Math.exp(-0.001/len2)*dot);
|
// v.norm.sub(vect);
|
// v.norm.normalize();
|
|
vtotal.add(v0);
|
ntotal.add(normal);
|
}
|
|
if (count == 0)
|
continue;
|
|
// vtotal.mul(1.0/(other.startvertices.length-1));
|
// ntotal.mul(1.0/(other.startvertices.length-1));
|
|
//v.set(vtotal);
|
|
//double height = v.y;
|
|
if (/*!CameraPane.INERTIA ||*/ CameraPane.FAST || /*subsupports == 1 ||*/!smooth || CameraPane.fullreset) // jump to target
|
{
|
// not mid point
|
v.set(vtotal);
|
// v0.set(vtotal);
|
//
|
// if (vtotal.dot(vtotal) == 0)
|
// vtotal = vtotal;
|
//
|
// v0.sub(v);
|
// // double weight = Math.exp(-normalweight/10);
|
//
|
// // if (weight > 0.5)
|
// // weight = 0;
|
//
|
// // v0.mul(weight);
|
// v.add(v0);
|
|
// ??????????? v.set(vtotal); //
|
|
//ntotal.normalize();
|
v.norm.set(ntotal);
|
}
|
else // halfway through
|
{
|
// PROBLEM with CROWD!!
|
|
if (true) // POSEMODE
|
{
|
float W = 10;
|
|
// trop bizarre if (slow)
|
W = 13;
|
|
// POSERATE
|
// if (CameraPane.FAST)
|
if (CameraPane.tickcount > 0 || CameraPane.SLOWPOSE)
|
{
|
// if (!slowposed && CameraPane.tickcount > 0)
|
// CameraPane.tickcount--;
|
// slowposed = true;
|
//System.out.println("SLOW POSE");
|
W = 40;
|
|
if (CameraPane.SLOWPOSE)
|
W = 150;
|
}
|
|
v0.set(vtotal);
|
v0.sub(v);
|
|
if (!CameraPane.INERTIA)
|
{
|
W = 1;
|
if (CameraPane.SLOWPOSE)
|
W = 8;
|
}
|
|
v.mul(W-1);
|
v.add(vtotal);
|
v.mul(1/W);
|
|
ntotal.normalize();
|
v.norm.mul(W-1);
|
v.norm.add(ntotal);
|
// v.norm.mul(1/W);
|
}
|
else
|
{
|
// use force
|
float W = 10;
|
|
// trop bizarre if (slow)
|
W = 13;
|
|
// POSE RATE
|
// if (CameraPane.FAST)
|
W = 600;
|
|
if (v.speed == null)
|
v.speed = new cVector();
|
|
v0.set(vtotal);
|
v0.sub(v);
|
double orgdist = v0.length();
|
v0.mul(1/W);
|
|
v.speed.add(v0);
|
|
v.add(v.speed);
|
|
v.speed.mul(0.9); // damping
|
|
v0.set(vtotal);
|
v0.sub(v);
|
|
double newdist = v0.length();
|
|
double K = newdist;
|
|
if (orgdist != 0)
|
K /= orgdist;
|
|
v.norm.mul(K);
|
ntotal.mul(1-K);
|
|
v.norm.add(ntotal);
|
// v.norm.mul(1/W);
|
}
|
}
|
|
|
if (marked)
|
{
|
double diff = //Math.abs
|
(v.y - height);
|
|
if (diff < 0)
|
{
|
// stepout = true;
|
// stepin = false;
|
onein = true;
|
}
|
|
if (diff < 0) // .005)
|
{
|
// if (stepout && !playedonce)
|
// {
|
// // sound
|
// GrafreeD.wav.play();
|
// playedonce = true;
|
// }
|
//
|
// stepout = false;
|
// // stepin = true;
|
allout = false;
|
}
|
|
v.y = height; // keep original height
|
}
|
|
v.norm.normalize();
|
|
// if (other.startvertices != null)
|
// if (Math.abs(testweight - v.totalweight)/testweight > 1E-2)
|
// {
|
// System.err.println("WEIGHT problem");
|
// //new Exception().printStackTrace(); // assert(Math.abs(testweight - v.totalweight)/testweight < 1E-2);
|
// }
|
|
// Recompute weights
|
if (supports != null) // backward compatibility: only for newly linked
|
{
|
// if (other.supports != null)
|
// RecomputeBasis(other, toRoot, v);
|
}
|
|
// Print(v);
|
// Println("");
|
}
|
|
if (false) // slow && stepout && onein)
|
{
|
// sound
|
cVector eye = Globals.theRenderer.EyeCamera().location;
|
|
Vertex v = GetVertex(0);
|
|
tmp.set(v);
|
tmp.sub(eye);
|
|
if (Globals.framecount - lastsoundtime > 30) // 0.25 secs
|
{
|
Grafreed.wav.play((Math.random()+0.5)/Math.max(tmp.length2(),0.2)); //, 1);
|
|
lastsoundtime = Globals.framecount;
|
}
|
|
stepout = false;
|
}
|
|
//stepin = allin;
|
|
if (marked && allout && !stepout)
|
{
|
stepout = true;
|
//System.err.println("stepout = true");
|
}
|
}
|
|
transient KDTree[] kdtrees;
|
//transient KDTree kdtree;
|
|
int GetClosestIndex(Vertex v0, boolean partofmesh, double[][] toRoot, double dist2beat, int object, boolean euclidien)
|
{
|
if (vect == null || normal == null)
|
{
|
// serial
|
vect = new cVector();
|
normal = new cVector();
|
vect2 = new cVector();
|
vect3 = new cVector();
|
vect4 = new cVector();
|
}
|
|
|
patchKDTree = true;
|
|
double mindist2 = 1E10f;
|
int minindex = -1;
|
|
cVector vect = new cVector();
|
Vertex buf = new Vertex();
|
|
int start = 0;
|
int end = VertexCount();
|
|
if (startvertices != null && patchKDTree)
|
{
|
start = startvertices[object-1];
|
end = startvertices[object];
|
}
|
|
if (start == end)
|
return -1;
|
|
if (false) // toRoot != null)
|
{
|
// brute force n^2
|
//for (int i = 0; i < VertexCount(); i++)
|
for (int i = start; i < end; i++)
|
{
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
if (toRoot != null)
|
LA.xformPos(vect,toRoot,vect);
|
|
buf.set(v0);
|
buf.sub(vect);
|
double dist2 = buf.length2();
|
|
if (mindist2 > dist2)
|
{
|
mindist2 = dist2;
|
minindex = i;
|
}
|
}
|
|
return minindex;
|
}
|
|
if (false) // partofmesh) // toRoot == null)
|
{
|
// v0 is part of the mesh
|
if (//GetVertex(0)
|
v0.faceindices == null)
|
{
|
InitFaceIndices();
|
}
|
|
// for (int fii = 0; fii < v0.faceindices.length; fii++)
|
// {
|
// int fi = v0.faceindices[fii];
|
//
|
// if (fi == -1)
|
// break;
|
//
|
// Face f = GetFace(fi);
|
//
|
// Vertex p = GetVertex(f.p);
|
// Vertex q = GetVertex(f.q);
|
// Vertex r = GetVertex(f.r);
|
|
// for (int i = start; i < end; i++)
|
for (int fii = 0; fii < v0.faceindices.length; fii++)
|
//for (int i = 0; i < VertexCount(); i++)
|
{
|
int fi = v0.faceindices[fii];
|
|
if (fi == -1)
|
break;
|
|
Face f = GetFace(fi);
|
|
for (int j=3; --j>=0;)
|
{
|
int i = f.get(j);
|
|
Vertex v = GetVertex(i);
|
|
normal.set(v.norm);
|
LA.xformDir(normal,toRoot,normal);
|
|
normal.normalize(); // useful?
|
|
// if (toRoot != null && vect.dot(v0.norm) < 0.8)
|
// continue;
|
|
vect.set(v);
|
if (toRoot != null)
|
LA.xformPos(vect,toRoot,vect);
|
|
buf.set(v0);
|
buf.sub(vect);
|
double dist2 = buf.length2();
|
|
if (dist2 == 0 && partofmesh) // toRoot == null)
|
continue;
|
|
// if (toRoot != null)
|
// dist2 = Distance2(v0,v, dist2beat, toRoot, object);
|
|
if (false) // bogus
|
//!euclidien)
|
{
|
dist2 = 1/buf.dot(normal);
|
if (dist2 < 0)
|
dist2 = 1E10;
|
dist2 *= dist2;
|
}
|
|
if (mindist2 > dist2)
|
{
|
mindist2 = dist2;
|
minindex = i;
|
}
|
}
|
}
|
|
return minindex;
|
}
|
else
|
{
|
if (kdtrees == null)
|
{
|
// init KD tree
|
if (startvertices == null)
|
kdtrees = new KDTree[1];
|
else
|
kdtrees = new KDTree[startvertices.length - 1];
|
}
|
|
// if (false) // kdtree == null)
|
// {
|
// // init KD tree
|
// kdtree = new KDTree(3);
|
//
|
// for (int i = 0; i < VertexCount(); i++)
|
// {
|
// double[] x = new double[3]; // x,y,z,index
|
//
|
// Vertex v = GetVertex(i);
|
//
|
// vect.set(v);
|
// if (toRoot != null)
|
// LA.xformPos(vect,toRoot,vect);
|
//
|
// x[0] = vect.x;
|
// x[1] = vect.y;
|
// x[2] = vect.z;
|
// //x[3] = i;
|
//
|
// if (vect.x == 0 && vect.y == 0 && vect.z == 0)
|
// {
|
// continue; // ????
|
// }
|
// try
|
// {
|
// kdtree.insert(x, new Integer(i));
|
// }
|
// catch (Exception e)
|
// {
|
// e.printStackTrace();
|
// }
|
// // vertexcompare[i - start] = new VertexCompare(x);
|
// }
|
// }
|
|
//for (int t=kdtree.length; --t>=0;)
|
int t = object-1;
|
if (kdtrees[t] == null)
|
{
|
kdtrees[t] = new KDTree(3); // end - start, 3);
|
//
|
// if (vertexcompare == null || vertexcompare.length != end - start)
|
// {
|
// vertexcompare = new VertexCompare[end - start];
|
////
|
//// for (int k=0; k<end - start; k++)
|
//// {
|
//// }
|
// }
|
//
|
for (int i = start; i < end; i++)
|
{
|
double[] x = new double[3]; // x,y,z,index
|
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
if (toRoot != null)
|
LA.xformPos(vect,toRoot,vect);
|
|
x[0] = vect.x;
|
x[1] = vect.y;
|
x[2] = vect.z;
|
//x[3] = i;
|
|
if (vect.x == 0 && vect.y == 0 && vect.z == 0)
|
{
|
continue; // ????
|
}
|
try
|
{
|
kdtrees[t].insert(x, new Integer(i));
|
}
|
catch (Exception e)
|
{
|
System.err.println("ERROR KDtree: KeyDuplicateException: Key already in tree?? " + this);
|
//e.printStackTrace();
|
}
|
// vertexcompare[i - start] = new VertexCompare(x);
|
}
|
//
|
// // sort...
|
// java.util.Arrays.sort(vertexcompare);
|
//
|
// for (int i = start; i < end; i++)
|
// {
|
// kdtree[t].add(vertexcompare[i - start].x);
|
// }
|
|
}
|
|
KDTree thetree = null; // sept 2013 kdtree;
|
|
if (patchKDTree)
|
thetree = kdtrees[t];
|
|
double[] testpoint = new double[3]; // x,y,z,index
|
|
testpoint[0] = v0.x;
|
testpoint[1] = v0.y;
|
testpoint[2] = v0.z;
|
|
// KDNode kdn = kdtree[object-1].find_nearest(testpoint);
|
//
|
// return (int)kdn.x[3];
|
int index = 0;
|
|
try
|
{
|
index =((Integer)thetree.nearest(testpoint, partofmesh?2:1)).intValue();
|
}
|
catch (Exception e)
|
{
|
//e.printStackTrace();
|
}
|
|
return index;
|
}
|
}
|
|
transient KDTree kdtree;
|
|
void BuildKDtree()
|
{
|
if (kdtree == null)
|
{
|
// init KD tree
|
kdtree = new KDTree(3);
|
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
double[] x = new double[3]; // x,y,z,index
|
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
|
x[0] = vect.x;
|
x[1] = vect.y;
|
x[2] = vect.z;
|
//x[3] = i;
|
|
if (vect.x == 0 && vect.y == 0 && vect.z == 0)
|
{
|
continue; // ????
|
}
|
try
|
{
|
kdtree.insert(x, new Integer(i));
|
}
|
catch (Exception e)
|
{
|
System.err.println("ERROR KDtree: KeyDuplicateException: Key already in tree?? " + this);
|
// e.printStackTrace();
|
}
|
// vertexcompare[i - start] = new VertexCompare(x);
|
}
|
}
|
}
|
|
boolean inside(cVector v0, Object3D obj)
|
{
|
BuildKDtree();
|
|
KDTree thetree = kdtree;
|
|
double[] testpoint = new double[3]; // x,y,z,index
|
|
testpoint[0] = v0.x;
|
testpoint[1] = v0.y;
|
testpoint[2] = v0.z;
|
|
// KDNode kdn = kdtree[object-1].find_nearest(testpoint);
|
//
|
// return (int)kdn.x[3];
|
int index = 0;
|
|
try
|
{
|
index = ((Integer)thetree.nearest(testpoint, 1)).intValue();
|
}
|
catch (Exception e)
|
{
|
//e.printStackTrace();
|
}
|
|
Vertex v = GetVertex(index);
|
|
vect.set(v0);
|
vect.sub(v);
|
|
// mechante patche ici
|
double f = vect.dot(v.norm);
|
|
boolean inside = f <= 0;
|
|
if (obj.depth != -1 && (obj.height <= 0 ^ inside))
|
{
|
Simplex.atom = obj;
|
}
|
|
obj.height = f;
|
obj.depth = 0;
|
|
return inside;
|
}
|
|
void gradient(Vertex v0)
|
{
|
BuildKDtree();
|
|
KDTree thetree = kdtree;
|
|
double[] testpoint = new double[3]; // x,y,z,index
|
|
testpoint[0] = v0.x;
|
testpoint[1] = v0.y;
|
testpoint[2] = v0.z;
|
|
// KDNode kdn = kdtree[object-1].find_nearest(testpoint);
|
//
|
// return (int)kdn.x[3];
|
int index = 0;
|
|
try
|
{
|
index = ((Integer)thetree.nearest(testpoint, 1)).intValue();
|
}
|
catch (Exception e)
|
{
|
//e.printStackTrace();
|
}
|
|
Vertex v = GetVertex(index);
|
|
v0.norm.set(v.norm);
|
}
|
|
// static class VertexCompare implements Comparable
|
// {
|
// double[] x;
|
//
|
// VertexCompare(double[] x)
|
// {
|
// this.x = x;
|
// }
|
//
|
// public int compareTo(Object o)
|
// {
|
// VertexCompare v = (VertexCompare) o;
|
//
|
// return x[0] > v.x[0] ? 1 : -1;
|
// }
|
// }
|
//
|
// transient VertexCompare[] vertexcompare = null;
|
|
// Check if v0 is close enough from any vertex of the given subobject of this.
|
boolean Contains(Vertex v0, int object)
|
{
|
int start = startvertices[object-1];
|
int end = startvertices[object];
|
|
cVector vect = new cVector();
|
|
for (int i = start; i < end; i++)
|
{
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
vect.sub(v0);
|
double dist2 = vect.length2();
|
|
//if (dist2 < 0.02*0.01)
|
if (dist2 < SEUIL*SEUIL)
|
return true;
|
}
|
|
return false;
|
}
|
|
void redimension(int nVerts, int nFaces)
|
{
|
/*
|
if (trimmed)
|
{
|
positions = new float[nVerts*3];
|
normals = new float[nVerts*3];
|
uvmap = new float[nVerts*2];
|
triangles = new int[nFaces*3];
|
countV = 0;
|
countF = 0;
|
*/
|
Init(nVerts, nFaces, true);
|
/*
|
}
|
else
|
{
|
positions = null;
|
normals = null;
|
colors = null;
|
uvmap = null;
|
triangles = null;
|
trimmed = false;
|
{
|
vertices.setSize(nVerts);
|
//vertices = new Vector(nVerts);
|
faces.setSize(nFaces);
|
}
|
bufV = nVerts;
|
bufF = nFaces;
|
}
|
*/
|
}
|
|
void UnfoldUV()
|
{
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
v.x = v.s;
|
v.y = v.t;
|
v.z = 0;
|
|
v.norm.x = 0;
|
v.norm.y = 0;
|
v.norm.z = 1;
|
|
SetVertex(v, i);
|
}
|
}
|
|
float power = 2;
|
|
void GenUV() // float power)
|
{
|
Trim();
|
|
cVector boxcenter = null;
|
cVector minima, maxima;
|
minima = new cVector();
|
maxima = new cVector();
|
minima.x = minima.y = minima.z = Double.MAX_VALUE;
|
maxima.x = maxima.y = maxima.z = -Double.MAX_VALUE;
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
if (minima.x > v.x)
|
{
|
minima.x = v.x;
|
}
|
if (minima.y > v.y)
|
{
|
minima.y = v.y;
|
}
|
if (minima.z > v.z)
|
{
|
minima.z = v.z;
|
}
|
|
if (maxima.x < v.x)
|
{
|
maxima.x = v.x;
|
}
|
if (maxima.y < v.y)
|
{
|
maxima.y = v.y;
|
}
|
if (maxima.z < v.z)
|
{
|
maxima.z = v.z;
|
}
|
}
|
|
boxcenter = new cVector((maxima.x + minima.x) / 2, (maxima.y + minima.y) / 2, (maxima.z + minima.z) / 2);
|
int i2 = 0, i3 = 0;
|
for (int i = 0; i < positions.length/3; i++, i3 += 3, i2 += 2)
|
{
|
// //uvmap[i2] = (float) normals[i3]*0.5f + 0.5f; // v.x;
|
// //uvmap[i2 + 1] = (float) normals[i3+1]*0.5f + 0.5f; //z;
|
// uvmap[i2] = (float) (positions[i3] - boxcenter.x);
|
// uvmap[i2 + 1] = (float) (positions[i3+2] - boxcenter.z);
|
// uvmap[i2] = (float) Math.atan2(positions[i3+1] - boxcenter.y, positions[i3] - boxcenter.x);
|
// uvmap[i2 + 1] = (float)(positions[i3+2] - boxcenter.z);
|
// box UV
|
double x = positions[i3] - minima.x; // - Math.floor(positions[i3]);
|
double y = positions[i3+1] - minima.y; // - Math.floor(positions[i3+1]);
|
double z = positions[i3+2] - minima.z; // - Math.floor(positions[i3+2]);
|
|
x /= maxima.x - minima.x;
|
y /= maxima.y - minima.y;
|
z /= maxima.z - minima.z;
|
|
x -= 0.5;
|
y -= 0.5;
|
z -= 0.5;
|
|
double ax = Math.abs(x);
|
double ay = Math.abs(y);
|
double max = ax;
|
if (max < ay)
|
{
|
max = ay;
|
}
|
|
if (max == 0)
|
{
|
uvmap[i2] = 0.5f;
|
uvmap[i2+1] = 0.5f;
|
continue;
|
}
|
|
x /= max;
|
y /= max;
|
|
double angle = Math.acos(Math.abs(z*2));
|
|
double k = angle / Math.PI * 2;
|
|
assert(k >= 0);
|
|
// k == 0 => uv = 0 (center)
|
// k == 1 => uv = -1,1 (border)
|
|
if (i == 0)
|
System.out.println("power = " + power);
|
|
double length1 = (ax+ay)/max;
|
double length2 = Math.sqrt(ax*ax + ay*ay) / max;
|
|
double t = k;
|
|
t = Math.pow(t, 3);
|
|
// Interpolate between k/length2 (center) and k (border)
|
if (length2 > 0)
|
k *= (1 - t) / length2 + t;
|
|
double u = k*x;
|
double v = k*y;
|
|
u /= 2;
|
v /= 2;
|
u += 0.5;
|
v += 0.5;
|
|
uvmap[i2] = (float) u;
|
uvmap[i2+1] = (float) v;
|
}
|
}
|
|
void GenUVold(float power)
|
{
|
Trim();
|
|
cVector boxcenter = null;
|
cVector minima, maxima;
|
minima = new cVector();
|
maxima = new cVector();
|
minima.x = minima.y = minima.z = Double.MAX_VALUE;
|
maxima.x = maxima.y = maxima.z = -Double.MAX_VALUE;
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
if (minima.x > v.x)
|
{
|
minima.x = v.x;
|
}
|
if (minima.y > v.y)
|
{
|
minima.y = v.y;
|
}
|
if (minima.z > v.z)
|
{
|
minima.z = v.z;
|
}
|
|
if (maxima.x < v.x)
|
{
|
maxima.x = v.x;
|
}
|
if (maxima.y < v.y)
|
{
|
maxima.y = v.y;
|
}
|
if (maxima.z < v.z)
|
{
|
maxima.z = v.z;
|
}
|
}
|
|
boxcenter = new cVector((maxima.x + minima.x) / 2, (maxima.y + minima.y) / 2, (maxima.z + minima.z) / 2);
|
int i2 = 0, i3 = 0;
|
for (int i = 0; i < positions.length/3; i++, i3 += 3, i2 += 2)
|
{
|
// //uvmap[i2] = (float) normals[i3]*0.5f + 0.5f; // v.x;
|
// //uvmap[i2 + 1] = (float) normals[i3+1]*0.5f + 0.5f; //z;
|
// uvmap[i2] = (float) (positions[i3] - boxcenter.x);
|
// uvmap[i2 + 1] = (float) (positions[i3+2] - boxcenter.z);
|
// uvmap[i2] = (float) Math.atan2(positions[i3+1] - boxcenter.y, positions[i3] - boxcenter.x);
|
// uvmap[i2 + 1] = (float)(positions[i3+2] - boxcenter.z);
|
// box UV
|
double x = positions[i3] - minima.x; // - Math.floor(positions[i3]);
|
double y = positions[i3+1] - minima.y; // - Math.floor(positions[i3+1]);
|
double z = positions[i3+2] - minima.z; // - Math.floor(positions[i3+2]);
|
|
// [-1/2, 1/2]
|
x /= maxima.x - minima.x;
|
y /= maxima.y - minima.y;
|
z /= maxima.z - minima.z;
|
|
x -= 0.5;
|
y -= 0.5;
|
z -= 0.5;
|
|
// x *= 2;
|
// y *= 2;
|
// z *= 2;
|
|
if (Double.isNaN(x))
|
x = boxcenter.x;
|
if (Double.isNaN(y))
|
y = boxcenter.y;
|
if (Double.isNaN(z))
|
z = boxcenter.z;
|
|
double length = Math.sqrt(x*x + y*y + z*z);
|
|
x /= length;
|
y /= length;
|
z /= length;
|
|
if (z > 1)
|
z = 1;
|
if (z < -1)
|
z = -1;
|
|
double angle = Math.acos(z);
|
|
z = Math.cos(angle/2);
|
|
assert(z >= 0);
|
assert(z <= 1);
|
|
/**/
|
//z = Math.pow(z, power); //1.08f);
|
|
if (i == 0)
|
System.out.println("power = " + power);
|
|
// sqrt(k2*x2 + k2*z2 + y2) = length
|
// k2*x2 + k2*z2 = length2 - y2
|
// k2 = (length2 - y2) / (x2 + z2)
|
double k = (1 - z*z);
|
|
if (x*x + y*y > 0)
|
{
|
k /= x*x + y*y;
|
}
|
else
|
Grafreed.Assert(z == 1);
|
|
if (k < 0)
|
k = 0;
|
else
|
k = Math.sqrt(k);
|
|
x *= k;
|
y *= k;
|
/**/
|
|
double max = Math.abs(x);
|
if (max < Math.abs(y))
|
{
|
max = Math.abs(y);
|
}
|
if (max < Math.abs(z))
|
{
|
max = Math.abs(z);
|
}
|
|
// max = Math.sqrt(max*2)/2;
|
// double x2 = Math.pow(Math.abs(x), 1/power);
|
// double y2 = Math.pow(Math.abs(y), 1/power);
|
// double z2 = Math.pow(Math.abs(z), 1/power);
|
// max = Math.pow(x2 + y2 + z2, power);
|
|
// if (!(max > 0))
|
//assert(max > 0);
|
assert(max >= 0);
|
|
x /= max;
|
y /= max;
|
z /= max;
|
|
x += 1; x /= 2;
|
y += 1; y /= 2;
|
z += 1; z /= 2;
|
|
double u = x*z + (1-x)*(1-z);
|
double v = y*z + (1-y)*(1-z);
|
|
uvmap[i2] = (float) u;
|
uvmap[i2+1] = (float) v;
|
}
|
}
|
|
void Trim()
|
{
|
if (trimmed) // nov 2013
|
return;
|
|
Trim(true, false, false, false, false);
|
}
|
|
void Trim(boolean gennormals, boolean crease, boolean stripify)
|
{
|
Trim(true, gennormals, crease, stripify, false);
|
}
|
|
void Trim(boolean trim, boolean gennormals, boolean crease, boolean stripify, boolean genUV)
|
{
|
if (trimmed)
|
return;
|
|
if (stripified)
|
Unstripify();
|
|
cVector boxcenter = null;
|
if (genUV)
|
{
|
cVector minima, maxima;
|
minima = new cVector();
|
maxima = new cVector();
|
minima.x = minima.y = minima.z = Double.MAX_VALUE;
|
maxima.x = maxima.y = maxima.z = -Double.MAX_VALUE;
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
if (minima.x > v.x)
|
{
|
minima.x = v.x;
|
}
|
if (minima.y > v.y)
|
{
|
minima.y = v.y;
|
}
|
if (minima.z > v.z)
|
{
|
minima.z = v.z;
|
}
|
|
if (maxima.x < v.x)
|
{
|
maxima.x = v.x;
|
}
|
if (maxima.y < v.y)
|
{
|
maxima.y = v.y;
|
}
|
if (maxima.z < v.z)
|
{
|
maxima.z = v.z;
|
}
|
}
|
|
boxcenter = new cVector((maxima.x + minima.x) / 2, (maxima.y + minima.y) / 2, (maxima.z + minima.z) / 2);
|
}
|
//if (gennormals || stripify)
|
{
|
assert !trimmed;
|
|
//System.out.println("bufV = " + bufV);
|
//System.out.println("maxIndexV = " + maxIndexV);
|
//System.out.println("vertices = " + vertices.size());
|
|
if (maxIndexV == 0)
|
{
|
maxIndexV = vertices.size();
|
if (maxIndexV < bufV)
|
{
|
maxIndexV = bufV;
|
}
|
}
|
if (maxIndexV < vertices.size())
|
{
|
Vector filter = new Vector();
|
|
for (int i = 0; i < vertices.size(); i++)
|
{
|
Vertex v = (Vertex) vertices.get(i);
|
|
//System.out.println("index = " + v.index);
|
if (v.index == filter.size())
|
{
|
filter.addElement(v);
|
}
|
}
|
|
//System.out.println("filter = " + filter.size());
|
|
if (filter.size() != maxIndexV)
|
{
|
System.out.println("WARNING : filter.size() != maxIndexV");
|
}
|
|
vertices = filter;
|
}
|
|
if (!trim)
|
{
|
return;
|
}
|
|
trimmed = true;
|
|
int sV = bufV;
|
//if (sV < maxIndexV) // vertices.size())
|
sV = maxIndexV; // vertices.size();
|
|
int sF = bufF;
|
if (sF < faces.size())
|
{
|
sF = faces.size();
|
}
|
|
positions = new float[sV * 3];
|
normals = new float[sV * 3];
|
colors = new float[sV * 3 /* !!?!??!!! COLORS */];
|
uvmap = new float[sV * 2];
|
|
triangles = new int[sF * 3];
|
|
// why after alloc?
|
if (sV > vertices.size())
|
{
|
sV = vertices.size();
|
}
|
|
int i3 = 0, i2 = 0;
|
|
for (int i = 0; i < sV; i++, i3 += 3, i2 += 2)
|
{
|
Vertex v = (Vertex) vertices.get(i);
|
|
positions[i3] = (float) v./*pos.*/x;
|
positions[i3 + 1] = (float) v./*pos.*/y;
|
positions[i3 + 2] = (float) v./*pos.*/z;
|
if (v.norm != null)
|
{
|
//System.out.println("Normal = " + v.norm.x + ", " + v.norm.y + ", " + v.norm.z);
|
normals[i3] = (float) v.norm.x;
|
normals[i3 + 1] = (float) v.norm.y;
|
normals[i3 + 2] = (float) v.norm.z;
|
} else
|
{
|
normals[i3] = normals[i3 + 1] = normals[i3 + 2] = 0;
|
}
|
|
colors[i] = v.AO;
|
|
if (genUV)
|
{
|
//uvmap[i2] = (float) v.norm.x*0.5f + 0.5f; // v.x;
|
//uvmap[i2 + 1] = (float) v.norm.y*0.5f + 0.5f; //z;
|
float x = positions[i3];
|
float y = positions[i3+1];
|
float z = positions[i3+2];
|
uvmap[i2] = (float) Math.atan2(y, x);
|
uvmap[i2 + 1] = z;
|
//float nx = normals[i3];
|
//float ny = normals[i3+1];
|
//float nz = normals[i3+2];
|
|
//uvmap[i2] = (float) (nx+1)/2;
|
//uvmap[i2+1] = (float) (nz+1)/2;
|
|
/* Deformation correction : nice but faces look different
|
float x = (float) v.x;
|
x = (float) Math.atan2(v.y-boxcenter.y, (v.x-boxcenter.x)*2);
|
uvmap[i2] = (float) (x/Math.PI);
|
uvmap[i2+1] = (float) v.z;
|
*/
|
|
} else
|
{
|
uvmap[i2] = (float) v.s;
|
uvmap[i2 + 1] = (float) v.t;
|
}
|
}
|
|
i3 = 0;
|
|
for (int i = 0; i < faces.size(); i++, i3 += 3)
|
{
|
Face f = (Face) faces.get(i);
|
|
//System.out.print("Face = " + f);
|
//System.out.println("; index = " + i);
|
|
triangles[i3] = f.p;
|
triangles[i3 + 1] = f.q;
|
triangles[i3 + 2] = f.r;
|
}
|
|
vertices = null;
|
faces = null;
|
vertextable = null;
|
// NEW
|
verticesCopy = null;
|
|
//GenerateNormals();
|
//if (vrac)
|
Compress(gennormals, crease, stripify);
|
|
if (genUV) // hum...
|
{
|
i2 = i3 = 0;
|
for (int i = 0; i < sV; i++, i3 += 3, i2 += 2)
|
{
|
//uvmap[i2] = (float) normals[i3]*0.5f + 0.5f; // v.x;
|
//uvmap[i2 + 1] = (float) normals[i3+1]*0.5f + 0.5f; //z;
|
float x = positions[i3];
|
float y = positions[i3+1];
|
float z = positions[i3+2];
|
uvmap[i2] = (float) Math.atan2(y, x);
|
uvmap[i2 + 1] = z;
|
}
|
}
|
/*
|
else
|
{
|
if (gennormals)
|
GenNormals();
|
if (stripify)
|
Stripify();
|
}
|
*/
|
}
|
/*
|
else
|
{
|
vertices.trimToSize();
|
faces.trimToSize();
|
vertextable.clear();
|
System.out.println("#faces = " + faces.size());
|
System.out.println("#vertices = " + vertices.size());
|
//System.out.println("#vertices = " + bRep.vertextable.size());
|
}
|
*/
|
}
|
|
void GenerateNormals2(boolean crease)
|
{
|
cVector tempVector = new cVector();
|
|
// java.util.HashMap<cVector, cVector> tableBase = new java.util.HashMap<cVector, cVector>();
|
//
|
//
|
// for (int i=0; i<this.VertexCount(); i++)
|
// {
|
// Vertex v = this.GetVertex(i);
|
//
|
// tempVector.set(v);
|
//
|
// cVector n = tableBase.get(tempVector.ToFloat());
|
//
|
// if (n != null)
|
// {
|
// continue;
|
// }
|
//
|
// tableBase.put(new cVector(tempVector), new cVector(v.norm));
|
// }
|
|
BoundaryRep tempSupport = this.support;
|
|
this.support = null;
|
|
BoundaryRep tempRep = (BoundaryRep)Grafreed.clone(this);
|
|
this.support = tempSupport;
|
|
//tempRep.Unstripify();
|
|
tempRep.GenerateNormals(crease);
|
|
boolean keepnormal = Vertex.normalmode;
|
boolean epsequal = Grafreed.epsequal;
|
|
Vertex.normalmode = false;
|
Grafreed.epsequal = false; // A bit strange
|
|
// No need to have a match for vertex counts.
|
|
java.util.HashMap<cVector, cVector> table = new java.util.HashMap<cVector, cVector>();
|
|
for (int i=0; i<tempRep.VertexCount(); i++)
|
{
|
Vertex v = tempRep.GetVertex(i);
|
|
cVector n = table.get(tempVector.ToFloat());
|
|
if (v.norm.x == 1 && v.norm.y == 0 && v.norm.z == 0)
|
{
|
//continue;
|
}
|
|
tempVector.set(v);
|
|
//cVector nBase = tableBase.get(tempVector);
|
|
//if (v.norm.dot(nBase) < 0.9)
|
//{
|
// continue;
|
//}
|
|
if (n != null && n.x == 1 && n.y == 0 && n.z == 0)
|
{
|
//continue;
|
}
|
|
if (n != null)
|
{
|
// if (n.dot(v.norm) < 0)
|
// n.sub(v.norm);
|
// else
|
// n.add(v.norm);
|
//
|
// n.normalize();
|
continue;
|
}
|
|
table.put(new cVector(tempVector), new cVector(v.norm));
|
}
|
|
for (int i=0; i<this.VertexCount(); i++)
|
{
|
Vertex v = this.GetVertex(i);
|
|
tempVector.set(v);
|
|
cVector n = table.get(tempVector.ToFloat());
|
|
//if (n.dot(v.norm) < 0)
|
if (n == null)
|
continue;
|
|
if (v.norm == null)
|
v.norm = new cVector();
|
|
LA.vecCopy(n, v.norm);
|
|
this.SetVertex(v, i);
|
}
|
|
Grafreed.epsequal = epsequal;
|
Vertex.normalmode = keepnormal;
|
}
|
|
void GenerateNormals(boolean crease)
|
{
|
boolean wastrim = trimmed;
|
boolean wasstrip = stripified;
|
|
try
|
{
|
Trim(); // aout 2013
|
Untrim();
|
}
|
catch(Exception e)
|
{
|
e.printStackTrace();
|
}
|
|
Trim(true/*wastrim*/,true,crease,wasstrip,false);
|
}
|
|
void GenerateNormalsMesh()
|
{
|
if (stripified)
|
{
|
Unstripify();
|
}
|
|
if (trimmed)
|
{
|
normals = null;
|
}
|
else
|
{
|
for (int i=VertexCount(); --i>=0;)
|
{
|
Vertex v = GetVertex(i);
|
|
v.norm = null;
|
}
|
}
|
}
|
|
void GenNormalsJME()
|
{
|
assert(false);
|
com.jme.util.geom.NormalGenerator ng = new com.jme.util.geom.NormalGenerator();
|
|
System.out.println("#vertices = " + positions.length * 3);
|
System.out.println("#indices = " + triangles.length);
|
// float[] an = ng.generateNormals(positions, triangles, (float) (Math.PI / 4));
|
|
// System.out.println("#an = " + an.length);
|
System.out.println("#triangles = " + triangles.length);
|
|
// assert an.length == triangles.length * 3;
|
|
//System.arraycopy(normals, 0, an, 0, an.length);
|
for (int i = 0; i < triangles.length; i++)
|
{
|
int j = triangles[i];
|
// normals[j * 3] = an[i * 3];
|
// normals[j * 3 + 1] = an[i * 3 + 1];
|
// normals[j * 3 + 2] = an[i * 3 + 2];
|
}
|
}
|
|
void StripifyJME()
|
{
|
com.jme.util.geom.nvtristrip.TriStrip tristrip = new com.jme.util.geom.nvtristrip.TriStrip();
|
|
com.jme.util.geom.nvtristrip.PrimitiveGroup[] strips = tristrip.generateStrips(triangles);
|
|
triangles = new int[strips.length];
|
|
int count = 0;
|
|
for (int i = 0; i < strips.length; i++)
|
//com.jme.util.geom.nvtristrip.PrimitiveGroup pg : strips)
|
{
|
triangles[i] = strips[i].getTrimmedIndices().length;
|
count += triangles[i];
|
}
|
|
float[] tpositions = new float[count * 3];
|
//System.out.println("NEW = " + positions.length);
|
float[] tnormals = new float[count * 3];
|
//System.out.println("NEW = " + positions.length);
|
float[] tuvmap = new float[count * 2];
|
|
int i2 = 0, i3 = 0;
|
|
for (int i = 0; i < strips.length; i++)
|
{
|
int[] strip = strips[i].getTrimmedIndices();
|
for (int j = 0; j < strip.length; j++) // , i2+2, i3+=3)
|
{
|
int j3 = strip[j] * 3;
|
int j2 = strip[j] * 2;
|
tpositions[i3] = positions[j3];
|
tpositions[i3 + 1] = positions[j3 + 1];
|
tpositions[i3 + 2] = positions[j3 + 2];
|
tnormals[i3] = normals[j3];
|
tnormals[i3 + 1] = normals[j3 + 1];
|
tnormals[i3 + 2] = normals[j3 + 2];
|
tuvmap[i2] = uvmap[j2];
|
tuvmap[i2 + 1] = uvmap[j2 + 1];
|
|
i2 += 2;
|
i3 += 3;
|
}
|
}
|
|
positions = tpositions;
|
normals = tnormals;
|
uvmap = tuvmap;
|
|
stripified = true;
|
}
|
|
void Compress(boolean gennormals, boolean crease, boolean stripify)
|
{
|
// Patch to avoid parsing strips
|
// if (!crease)
|
// stripify = false;
|
|
if (positions.length == 0)
|
{
|
return;
|
}
|
|
stripified = false;
|
|
if (!gennormals && !stripify)
|
{
|
return;
|
}
|
|
//GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
|
|
IndexedTriangleArray ita = new IndexedTriangleArray(positions.length / 3, /*TriangleArray.BY_REFERENCE |*/
|
TriangleArray.COORDINATES | TriangleArray.NORMALS | TriangleArray.TEXTURE_COORDINATE_2, triangles.length);
|
|
// initialize the geometry info
|
ita.setCoordinates(0, positions);
|
ita.setNormals(0, normals);
|
ita.setTextureCoordinates(0, 0, uvmap);
|
|
ita.setCoordinateIndices(0, triangles);
|
ita.setNormalIndices(0, triangles);
|
ita.setTextureCoordinateIndices(0, triangles);
|
|
//ita.setCoordRefFloat(positions);
|
//ita.setNormalRefFloat(normals);
|
//ita.setTexCoordRefFloat(0, uvmap);
|
|
GeometryInfo gi = new GeometryInfo(ita);
|
|
// generate normals
|
if (gennormals)
|
{
|
//System.out.println("#units = " + gi.getTexCoordSetCount());
|
NormalGenerator ng;
|
|
if (crease)
|
ng = new NormalGenerator(Math.PI/4); // default is 44 degrees (or Math.PI/3); // /4);
|
else
|
ng = new NormalGenerator(Math.PI); // (Math.PI / 3); // /4);
|
|
ng.generateNormals(gi);
|
//System.out.println(" --> #units = " + gi.getTexCoordSetCount());
|
|
if (!stripify)
|
{
|
//System.out.println("MESH = " + gi.getGeometryArray().getClass().getName());
|
TriangleArray ta = (TriangleArray) gi.getGeometryArray();
|
//System.out.println("OLD = " + positions.length);
|
positions = new float[ta.getVertexCount() * 3];
|
//System.out.println("NEW = " + positions.length);
|
normals = new float[ta.getVertexCount() * 3];
|
//System.out.println("NEW = " + positions.length);
|
uvmap = new float[ta.getVertexCount() * 2];
|
|
ta.getCoordinates(0, positions);
|
ta.getNormals(0, normals);
|
// ta.getColors(0, colors);
|
ta.getTextureCoordinates(0, 0, uvmap);
|
|
System.out.println("UV = " + uvmap[2] + ", " + uvmap[3] + ";");
|
|
colors = null;
|
// colors = new float[ta.getVertexCount()]; // * 3];
|
//
|
// for (int i=colors.length; --i>=0;)
|
// {
|
// colors[i] = 1;
|
// }
|
|
triangles = new int[ta.getVertexCount()];
|
|
for (int i = 0; i < triangles.length; i++)
|
{
|
triangles[i] = i;
|
}
|
|
// Untrim();
|
if (!trimmed)
|
MergeNormals();
|
}
|
}
|
|
//gi.unindexify();
|
|
if (stripify)
|
{
|
// stripify
|
Stripifier st = new Stripifier();
|
st.stripify(gi);
|
GeometryArray ga = gi.getGeometryArray();
|
|
//System.out.println("ga = " + ga);
|
//System.out.println("ga.getVertexCount() = " + ga.getVertexCount());
|
//System.out.println("ga.getValidVertexCount() = " + ga.getValidVertexCount());
|
//System.out.println("positions.length/3 = " + (positions.length/3));
|
|
//assert ga.getVertexCount() == positions.length/3;
|
|
// loses the index
|
try
|
{
|
TriangleStripArray tsa = (TriangleStripArray) ga;
|
|
positions = new float[3 * ga.getVertexCount()];
|
normals = new float[3 * ga.getVertexCount()];
|
uvmap = new float[2 * ga.getVertexCount()];
|
|
tsa.getCoordinates(0, positions);
|
tsa.getNormals(0, normals);
|
tsa.getTextureCoordinates(0, 0, uvmap);
|
// tsa.getColors(0, colors);
|
|
colors = null;
|
// colors = new float[1 * ga.getVertexCount()];
|
// for (int i=colors.length; --i>=0;)
|
// {
|
// colors[i] = 1;
|
// }
|
|
int stripcount = tsa.getNumStrips();
|
triangles = new int[stripcount];
|
tsa.getStripVertexCounts(triangles);
|
|
stripified = true;
|
} catch (ClassCastException e)
|
{
|
// ??? aug 2019
|
TriangleArray ta = (TriangleArray) ga;
|
|
positions = new float[3 * ga.getVertexCount()];
|
normals = new float[3 * ga.getVertexCount()];
|
uvmap = new float[2 * ga.getVertexCount()];
|
colors = new float[1 * ga.getVertexCount()];
|
|
ta.getCoordinates(0, positions);
|
ta.getNormals(0, normals);
|
// ta.getColors(0, colors);
|
|
triangles = new int[1];
|
triangles[0] = 3;
|
}
|
|
//Untrim();
|
if (!trimmed)
|
MergeNormals();
|
}
|
|
/*
|
int stripcount = tsa.getNumStrips();
|
int[] strips = new int[stripcount];
|
tsa.getStripVertexCounts(strips);
|
int tricount = 0;
|
for (int i=0; i<stripcount; i++)
|
tricount += strips[i] - 2;
|
int indexin = 0;
|
int indexout = 0;
|
triangles = new int[tricount + stripcount];
|
for (int i=0; i<stripcount; i++)
|
{
|
for (int j=0; j<strips[i]; j++)
|
{
|
triangles[indexout++] =
|
}
|
}
|
*/
|
}
|
|
void GenerateNormalsMINE()
|
{
|
Vertex.normalmode = true;
|
|
System.out.println("#Vertex = " + VertexCount());
|
System.out.println("#Face = " + FaceCount());
|
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
vertextemp.set(v);
|
|
//if (v.norm.x == 0 && v.norm.y == 0 && v.norm.z == 0)
|
{
|
if (!GenerateNormal(i, vertextemp))
|
continue;
|
|
if (v.norm.dot(vertextemp.norm) < 0)
|
vertextemp.norm.mul(-1);
|
|
if (v.norm.dot(vertextemp.norm) < 0.9)
|
SetVertex(vertextemp, i);
|
}
|
}
|
|
Vertex.normalmode = false;
|
}
|
|
void MergeNormals()
|
{
|
assert(!trimmed);
|
|
boolean smooth = Grafreed.smoothmode;
|
boolean link = Grafreed.linkUV;
|
Grafreed.smoothmode = true;
|
Grafreed.linkUV = true;
|
|
System.out.println("#Vertex = " + VertexCount());
|
System.out.println("#Face = " + FaceCount());
|
|
java.util.HashSet<Vertex> table = new java.util.HashSet<Vertex>();
|
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
if (!table.contains(v))
|
{
|
table.add(v);
|
}
|
}
|
|
Grafreed.smoothmode = smooth;
|
Grafreed.linkUV = link;
|
|
// for (int i = 0; i < VertexCount(); i++)
|
// {
|
// Vertex v = GetVertex(i);
|
//
|
// table.add(v);
|
// }
|
|
}
|
|
static cVector temp1 = new cVector();
|
static cVector temp2 = new cVector();
|
static cVector temp3 = new cVector();
|
|
boolean GenerateNormal(int index, Vertex v)
|
{
|
//System.out.println("Old normal = " + v.norm);
|
LA.setVector(v.norm, 0, 0, 0);
|
for (int i = 0; i < FaceCount(); i++)
|
{
|
Face f = GetFace(i);
|
if (f.p == index)
|
{
|
Vertex q = GetVertex(f.q);
|
Vertex r = GetVertex(f.r);
|
|
LA.vecSub(q/*.pos*/, v/*.pos*/, temp1);
|
LA.vecSub(r/*.pos*/, v/*.pos*/, temp2);
|
} else if (f.q == index)
|
{
|
Vertex r = GetVertex(f.r);
|
Vertex p = GetVertex(f.p);
|
|
LA.vecSub(r/*.pos*/, v/*.pos*/, temp1);
|
LA.vecSub(p/*.pos*/, v/*.pos*/, temp2);
|
} else if (f.r == index)
|
{
|
Vertex p = GetVertex(f.p);
|
Vertex q = GetVertex(f.q);
|
|
LA.vecSub(p/*.pos*/, v/*.pos*/, temp1);
|
LA.vecSub(q/*.pos*/, v/*.pos*/, temp2);
|
}
|
else
|
{
|
continue;
|
}
|
|
//LA.vecNormalize(temp1);
|
//LA.vecNormalize(temp2);
|
LA.vecCross(temp1, temp2, temp3);
|
/*
|
LA.vecScale(temp3, Arccos(LA.vecDot(temp1,temp2)));
|
*/
|
double s = temp3.length();
|
//double c = temp2.dot(temp1);
|
|
if (s == 0)
|
return false;
|
|
float angle = 1; // (float) Math.atan2(s, c);
|
//if(angle < 0) angle = -angle;
|
|
//LA.vecNormalize(temp3);
|
LA.vecScale(temp3, angle / s);
|
|
// if (temp3.dot(v.norm) < 0)
|
// assert(temp3.dot(v.norm) >= 0);
|
|
LA.vecAdd(temp3, v.norm, v.norm);
|
}
|
|
LA.vecNormalize(v.norm);
|
//System.out.println("New normal = " + v.norm);
|
|
return true;
|
}
|
|
double Arccos(double x)
|
{
|
return Math.PI / 2 - (x + x * x * x / 6);
|
}
|
|
/*
|
void AddFace(int indexF, int indexP, int indexQ, int indexR)
|
{
|
if (trimmed)
|
{
|
assert indexF == countF;
|
setFace(indexF, indexP, indexQ, indexR);
|
}
|
else
|
{
|
faces.addElement(null);
|
setFace(indexF, indexP, indexQ, indexR);
|
}
|
}
|
*/
|
void AddFace(int p, int q, int r)
|
{
|
if (trimmed)
|
{
|
setFace(countF++, p, q, r);
|
} else
|
{
|
Face face = new Face();
|
assert (vertices != null);
|
//if (p != ((Vertex) vertices.get(p)).index)
|
{
|
p = ((Vertex) vertices.get(p)).index;
|
}
|
//if (q != ((Vertex) vertices.get(q)).index)
|
{
|
q = ((Vertex) vertices.get(q)).index;
|
}
|
//if (r != ((Vertex) vertices.get(r)).index)
|
{
|
r = ((Vertex) vertices.get(r)).index;
|
}
|
face.p = p;
|
face.q = q;
|
face.r = r;
|
faces.addElement(face);
|
//System.out.println("AddFace = " + faces.size());
|
}
|
}
|
|
void SetVertex(Vertex v, int index)
|
{
|
if (trimmed)
|
{
|
int v3 = index * 3;
|
positions[v3] = (float) v./*pos.*/x;
|
positions[v3 + 1] = (float) v./*pos.*/y;
|
positions[v3 + 2] = (float) v./*pos.*/z;
|
|
int v2 = index * 2;
|
uvmap[v2] = (float) v.s;
|
uvmap[v2 + 1] = (float) v.t;
|
|
if (v.norm != null)
|
{
|
//System.out.println("Normal = " + v.norm.x + ", " + v.norm.y + ", " + v.norm.z);
|
normals[v3] = (float) v.norm.x;
|
normals[v3 + 1] = (float) v.norm.y;
|
normals[v3 + 2] = (float) v.norm.z;
|
}
|
} else
|
{
|
if (vertices.elementAt(index) == null)
|
vertices.setElementAt(v, index);
|
else
|
vertices.elementAt(index).set(v);
|
|
sortedVertices = null;
|
}
|
}
|
|
float[] getRawVertices()
|
{
|
if (trimmed)
|
{
|
// PATCH
|
vertextable = null;
|
verticesCopy = null;
|
return positions;
|
} else
|
{
|
return new float[bufV * 3];
|
}
|
}
|
|
float[] getRawNormals()
|
{
|
if (trimmed)
|
{
|
return normals;
|
} else
|
{
|
return new float[bufV * 3];
|
}
|
}
|
|
float[] getRawColors()
|
{
|
return colors;
|
}
|
|
float[] getRawUVMap()
|
{
|
if (trimmed)
|
{
|
return uvmap;
|
} else
|
{
|
return new float[bufV * 2];
|
}
|
}
|
|
int[] getRawIndices()
|
{
|
if (true) // trimmed)
|
{
|
return triangles;
|
} else
|
{
|
//assert false;
|
new Exception().printStackTrace();
|
}
|
|
return null;
|
}
|
static Vertex[] sVertex = new Vertex[100000];
|
static int indexV = 0;
|
|
static
|
{
|
for (int i = 0; i < sVertex.length; i++)
|
{
|
sVertex[i] = new Vertex(true);
|
// sVertex[i].norm = new cVector();
|
}
|
}
|
|
transient Vector<Vertex> sortedVertices = null;
|
|
void Transform(double[][] t)
|
{
|
if (trimmed)
|
{
|
if (e1 == null)
|
e1 = new cVector();
|
|
for (int i=positions.length/3; --i>=0;)
|
{
|
int i3 = i * 3;
|
e1.x = positions[i3];
|
e1.y = positions[i3 + 1];
|
e1.z = positions[i3 + 2];
|
LA.xformPos(e1, t, e1);
|
positions[i3] = (float)e1.x;
|
positions[i3 + 1] = (float)e1.y;
|
positions[i3 + 2] = (float)e1.z;
|
}
|
} else
|
{
|
for (int i=vertices.size(); --i>=0;)
|
{
|
Vertex v = (Vertex) vertices.elementAt(i);
|
LA.xformPos(v, t, v);
|
}
|
}
|
}
|
|
transient cVector centroid;
|
|
float GetGround(cVector point)
|
{
|
float maxheight = Float.NEGATIVE_INFINITY;
|
|
int count = FaceCount();
|
for (int i = 0; i < count; i++)
|
{
|
Face f = GetFace(i);
|
|
Vertex pp = GetVertex(f.p);
|
Vertex pq = GetVertex(f.q);
|
Vertex pr = GetVertex(f.r);
|
|
vect2.set(pq);
|
vect2.sub(pp);
|
|
vect3.set(pr);
|
vect3.sub(pp);
|
|
normal.cross(vect2, vect3);
|
|
// face orientation
|
if (normal.y <= 0)
|
continue;
|
|
vect2.set(vect2.z,0,-vect2.x);
|
|
vect.set(point);
|
vect.sub(pp);
|
|
// edge side
|
if (vect.dot(vect2) < 0)
|
continue;
|
|
vect2.set(pr);
|
vect2.sub(pq);
|
|
vect2.set(vect2.z,0,-vect2.x);
|
|
vect.set(point);
|
vect.sub(pq);
|
|
// edge side
|
if (vect.dot(vect2) < 0)
|
continue;
|
|
vect2.set(pp);
|
vect2.sub(pr);
|
|
vect2.set(vect2.z,0,-vect2.x);
|
|
vect.set(point);
|
vect.sub(pr);
|
|
// edge side
|
if (vect.dot(vect2) < 0)
|
continue;
|
|
normal.normalize();
|
|
// ax + by + cz + d = 0
|
// (x,y,z) = (px,py,pz) + K*(0,-1,0)
|
// apx + b*(py - K) + cpz + d == 0
|
// K = (apx + bpy + cpz + d) / b
|
|
double a = normal.x;
|
double b = normal.y;
|
double c = normal.z;
|
double d = -(a*pp.x + b*pp.y + c*pp.z);
|
|
double px = point.x;
|
double py = point.y;
|
double pz = point.z;
|
|
double K = a*px + b*py + c*pz + d;
|
|
K /= b;
|
|
if (Math.abs(K) > 1)
|
continue;
|
|
double height = point.y - K;
|
|
if (maxheight < height)
|
maxheight = (float)height;
|
}
|
|
return maxheight;
|
}
|
|
void getCentroid(cVector min, Object3D root)
|
{
|
int step = 1; // 10;
|
|
if (true) // centroid == null || !trimmed)
|
{
|
// if (trimmed)
|
// centroid = new cVector();
|
|
min.x = min.y = min.z = 0;
|
|
int count = VertexCount();
|
|
if (count < step*10)
|
step = 1;
|
|
int realcount = 0;
|
|
for (int i = 0; i < count; i+=step)
|
{
|
Vertex v = GetVertex(i);
|
|
if (Double.isNaN(v.x))
|
{
|
new Exception().printStackTrace();
|
continue;
|
}
|
|
vect.set(v);
|
|
if (root != null) // && !(this instanceof Texture))
|
{
|
root.TransformToWorld(vect);
|
}
|
|
min.x += vect.x;
|
min.y += vect.y;
|
min.z += vect.z;
|
realcount++;
|
}
|
|
min.x /= realcount;
|
min.y /= realcount;
|
min.z /= realcount;
|
|
// if (trimmed)
|
// centroid.set(min);
|
}
|
|
// if (trimmed)
|
// min.set(centroid);
|
}
|
|
void getFloor(cVector min)
|
{
|
min.x = min.z = 0;
|
min.y = Float.MAX_VALUE;
|
|
int count = VertexCount();
|
for (int i = 0; i < count; i++)
|
{
|
Vertex v = GetVertex(i);
|
|
if (min.y > v.y)
|
{
|
min.y = v.y;
|
min.x = v.x;
|
min.z = v.z;
|
}
|
|
// min.x += v.x;
|
// min.z += v.z;
|
}
|
|
// min.x /= count;
|
// min.z /= count;
|
}
|
|
long getFloor(cVector min, Object3D root)
|
{
|
min.x = min.z = 0;
|
min.y = Float.MAX_VALUE;
|
|
long id = 0;
|
|
int count = VertexCount();
|
for (int i = 0; i < count; i++)
|
{
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
|
if (root != null) // && !(this instanceof Texture))
|
{
|
root.TransformToWorld(vect);
|
}
|
|
if (min.y > vect.y)
|
{
|
min.y = vect.y;
|
min.x = vect.x;
|
min.z = vect.z;
|
id = i+1;
|
}
|
|
// min.x += v.x;
|
// min.z += v.z;
|
}
|
|
// min.x /= count;
|
// min.z /= count;
|
|
return id;
|
}
|
|
void getMinMax(cVector min, cVector max, int step)
|
{
|
min.x = min.y = min.z = Float.MAX_VALUE;
|
max.x = max.y = max.z = -Float.MAX_VALUE;
|
|
int count = VertexCount();
|
|
// mars 2014
|
while (step > count)
|
step /= 10;
|
|
for (int i = 0; i < count; i+=step)
|
{
|
Vertex v = GetVertex(i);
|
|
if (min.x > v.x)
|
min.x = v.x;
|
if (min.y > v.y)
|
min.y = v.y;
|
if (min.z > v.z)
|
min.z = v.z;
|
if (max.x < v.x)
|
max.x = v.x;
|
if (max.y < v.y)
|
max.y = v.y;
|
if (max.z < v.z)
|
max.z = v.z;
|
}
|
}
|
|
void getBounds(cVector minima, cVector maxima, Object3D root)
|
{
|
//minima.x = minima.y = minima.z = Float.MAX_VALUE;
|
//maxima.x = maxima.y = maxima.z = -Float.MAX_VALUE;
|
minima.x = minima.y = minima.z = Double.POSITIVE_INFINITY;
|
maxima.x = maxima.y = maxima.z = Double.NEGATIVE_INFINITY;
|
|
int step = 11;
|
|
if (VertexCount() < 100)
|
step = 1;
|
|
for (int i = 0; i < VertexCount(); i+=step)
|
{
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
|
if (root != null) // && !(this instanceof Texture))
|
{
|
root.TransformToWorld(vect);
|
}
|
|
if (minima.x > vect.x)
|
{
|
minima.x = vect.x;
|
}
|
if (minima.y > vect.y)
|
{
|
minima.y = vect.y;
|
}
|
if (minima.z > vect.z)
|
{
|
minima.z = vect.z;
|
}
|
|
if (maxima.x < vect.x)
|
{
|
maxima.x = vect.x;
|
}
|
if (maxima.y < vect.y)
|
{
|
maxima.y = vect.y;
|
}
|
if (maxima.z < vect.z)
|
{
|
maxima.z = vect.z;
|
}
|
}
|
}
|
|
transient cVector bbmin, bbmax;
|
|
transient
|
boolean allbehind;
|
transient
|
boolean allinfront;
|
transient
|
boolean allleft;
|
transient
|
boolean allright;
|
transient
|
boolean allup;
|
transient
|
boolean alldown;
|
|
void CullVertexRoot(Object3D root, Camera parentcam, Camera cam, boolean shadow)
|
{
|
if (root != null) // && !(this instanceof Texture))
|
{
|
root.TransformToWorld(vect);
|
}
|
if (parentcam != cam) // if not the light
|
{
|
for (int count = parentcam.GetTransformCount(); --count>=0;)
|
LA.xformPos(vect, parentcam.toParent, vect);
|
}
|
LA.xformPos(vect, cam.toScreen, vect);
|
if (shadow)
|
{
|
double scale = cam.SCALE / cam.Distance();
|
// gl.glScaled(2 * scale, 2 * scale, -scale);
|
// gl.glTranslated(0, 0, cam.DECAL);
|
|
vect.x *= 2*scale;
|
vect.y *= 2*scale;
|
|
if (vect.x < 1)
|
allright = false;
|
if (vect.x > -1)
|
allleft = false;
|
if (vect.y < 1)
|
allup = false;
|
if (vect.y > -1)
|
alldown = false;
|
} else
|
{
|
if (vect.z > 0)
|
{
|
allinfront = false;
|
return; // behind
|
}
|
allbehind = false;
|
// System.out.print("v0 = " + v0);
|
double fov = cam.shaper_fovy * Math.PI / 180;
|
double atanx = Math.atan2(vect.x,-vect.z);
|
double atany = Math.atan2(vect.y,-vect.z);
|
// System.out.print("FOV = " + fov);
|
// System.out.print("; X = " + atan00x);
|
// System.out.println("; Y = " + atan00y);
|
//
|
// if (atan00x > fov/4 ||
|
// atan00y > fov/4 ||
|
// false)
|
// return;
|
if (atanx < fov/4)
|
allright = false;
|
if (atanx > -fov/4)
|
allleft = false;
|
if (atany < fov/4)
|
allup = false;
|
if (atany > -fov/4)
|
alldown = false;
|
}
|
}
|
|
void CullVertex(javax.media.opengl.GL glNOTUSED, boolean shadowNOTUSED)
|
{
|
CameraPane.glu.gluProject(vect5.x,vect5.y,vect5.z,
|
CameraPane.tempmat,0, CameraPane.tempmat2,0,
|
CameraPane.viewport,0, CameraPane.model,0); // CameraPane.selectedpoint.toParent[3],0);
|
|
vect5.x = CameraPane.model[0]; // selectedpoint.toParent[3][0];
|
vect5.y = CameraPane.model[1]; // selectedpoint.toParent[3][1];
|
vect5.z = CameraPane.model[2]; // selectedpoint.toParent[3][2];
|
|
if (vect5.z > 1)
|
{
|
allinfront = false;
|
return; // behind
|
}
|
allbehind = false;
|
|
if (vect5.x - CameraPane.viewport[2]/4 < CameraPane.viewport[2]/2)
|
allright = false;
|
if (vect5.x - CameraPane.viewport[2]/4 > CameraPane.viewport[0]/2)
|
allleft = false;
|
if (vect5.y - CameraPane.viewport[3]/4 < CameraPane.viewport[3]/2)
|
allup = false;
|
if (vect5.y - CameraPane.viewport[3]/4 > CameraPane.viewport[1]/2)
|
alldown = false;
|
}
|
|
boolean FrustumCull(Object3D root, javax.media.opengl.GL gl, Camera cam, boolean shadow)
|
{
|
// june 2014
|
// Camera parentcam = cam;
|
//
|
// if (cam == Globals.theRenderer.cameras[0])
|
// {
|
// parentcam = Globals.theRenderer.cameras[1];
|
// }
|
//
|
// if (cam == Globals.theRenderer.cameras[1])
|
// {
|
// parentcam = Globals.theRenderer.cameras[0];
|
// }
|
|
gl.glGetDoublev(gl.GL_MODELVIEW_MATRIX, CameraPane.tempmat, 0);
|
gl.glGetDoublev(gl.GL_PROJECTION_MATRIX, CameraPane.tempmat2, 0);
|
gl.glGetIntegerv(gl.GL_VIEWPORT, CameraPane.viewport, 0);
|
|
// System.err.println("tempmat = " + tempmat[0] + " " + tempmat[1] + " " + tempmat[2] + " " + tempmat[3]);
|
// System.err.println("tempmat = " + tempmat[4] + " " + tempmat[5] + " " + tempmat[6] + " " + tempmat[7]);
|
// System.err.println("tempmat = " + tempmat[8] + " " + tempmat[9] + " " + tempmat[10] + " " + tempmat[11]);
|
// System.err.println("tempmat = " + tempmat[12] + " " + tempmat[13] + " " + tempmat[14] + " " + tempmat[15]);
|
//
|
// System.err.println("view = " + view[0] + " " + view[1] + " " + view[2] + " " + view[3]);
|
// System.err.println("view = " + view[4] + " " + view[5] + " " + view[6] + " " + view[7]);
|
// System.err.println("view = " + view[8] + " " + view[9] + " " + view[10] + " " + view[11]);
|
// System.err.println("view = " + view[12] + " " + view[13] + " " + view[14] + " " + view[15]);
|
|
allbehind = true; // !shadow;
|
allinfront = true; // !shadow;
|
allleft = true;
|
allright = true;
|
allup = true;
|
alldown = true;
|
|
if (bbmin == null)
|
{
|
bbmin = new cVector();
|
bbmax = new cVector();
|
|
getBounds(bbmin, bbmax, null);
|
}
|
|
vect5.set(bbmin.x, bbmin.y, bbmin.z);
|
//CullVertex(root, parentcam, cam, shadow);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmin.x, bbmin.y, bbmax.z);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmin.x, bbmax.y, bbmin.z);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmin.x, bbmax.y, bbmax.z);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmax.x, bbmin.y, bbmin.z);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmax.x, bbmin.y, bbmax.z);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmax.x, bbmax.y, bbmin.z);
|
CullVertex(gl, shadow);
|
|
// if (allbehind || allright || allleft || allup || alldown)
|
// return true;
|
|
vect5.set(bbmax.x, bbmax.y, bbmax.z);
|
CullVertex(gl, shadow);
|
|
if (allbehind ||
|
allinfront && (allright || allleft || allup || alldown))
|
{
|
return true;
|
}
|
|
if (true)
|
return false;
|
|
/////////////////////////////////
|
|
int step = 11;
|
|
|
for (int i = 0; i < VertexCount(); i+=step)
|
{
|
Vertex v = GetVertex(i);
|
|
vect.set(v);
|
|
//CullVertex(root, parentcam, cam, shadow);
|
|
if (!allbehind && !allright && !allleft && !allup && !alldown)
|
break;
|
}
|
|
return allbehind || allright || allleft || allup || alldown;
|
}
|
|
Vertex GetVertex(int i)
|
{
|
if (trimmed)
|
{
|
if (indexV >= sVertex.length)
|
{
|
new Exception().printStackTrace();
|
indexV = 0; // sort multithreaded ?????
|
}
|
Vertex v = sVertex[indexV++];
|
indexV %= sVertex.length;
|
|
int i3 = i * 3;
|
int i2 = i * 2;
|
|
if (i3 >= positions.length)
|
{
|
i3 = positions.length-3;
|
i2 = uvmap.length - 2;
|
//new Exception().printStackTrace();
|
}
|
|
v./*pos.*/x = positions[i3];
|
v./*pos.*/y = positions[i3 + 1];
|
v./*pos.*/z = positions[i3 + 2];
|
|
if (normals == null)
|
{
|
v.norm.x = 0;
|
v.norm.y = 0;
|
v.norm.z = 0;
|
}
|
else
|
{
|
v.norm.x = normals[i3];
|
v.norm.y = normals[i3 + 1];
|
v.norm.z = normals[i3 + 2];
|
}
|
|
v.s = uvmap[i2];
|
v.t = uvmap[i2 + 1];
|
|
v.AO = 1;
|
|
if (colors != null)
|
v.AO = colors[i]; // ?? i3];
|
|
return v;
|
} else
|
{
|
if (sortedVertices == null)
|
{
|
// SortVertices();
|
}
|
|
Vertex v = null;
|
|
try
|
{
|
v = (Vertex) vertices.elementAt(i);
|
}
|
catch (Exception e)
|
{
|
e.printStackTrace();
|
}
|
|
if (v == null)
|
vertices.setElementAt(v = new Vertex(true), i);
|
|
v.index = i; // assert???
|
|
return v;
|
}
|
}
|
|
void SortVertices()
|
{
|
Vertex.sortaxis = 0;
|
|
Object[] array = (Object[]) vertices.toArray();
|
|
SortVertices0(array, 0,vertices.size(), 0);
|
|
sortedVertices = new Vector(array.length);
|
|
for (int i=0; i<vertices.size(); i++)
|
sortedVertices.add((Vertex)array[i]);
|
}
|
|
void SortVertices0(Object[] array, int startindex, int endindex, int sortaxis)
|
{
|
if (startindex == endindex)
|
return; // done
|
|
if (startindex+1 == endindex)
|
return; // done
|
|
Vertex.sortaxis = sortaxis;
|
java.util.Arrays.sort(array, startindex, endindex);
|
|
sortaxis += 1;
|
sortaxis %= 3;
|
|
int mid = (startindex + endindex)/2;
|
|
SortVertices0(array, startindex,mid, sortaxis);
|
SortVertices0(array, mid,endindex, sortaxis);
|
}
|
|
void Remove(Vertex v)
|
{
|
if (trimmed)
|
{
|
//
|
}
|
else
|
{
|
vertices.remove(v);
|
vertextable.remove(v);
|
}
|
}
|
|
void AddVertex(Vertex v)
|
{
|
if (trimmed)
|
{
|
int v3 = countV * 3;
|
positions[v3] = (float) v./*pos.*/x;
|
positions[v3 + 1] = (float) v./*pos.*/y;
|
positions[v3 + 2] = (float) v./*pos.*/z;
|
|
int v2 = countV * 2;
|
uvmap[v2] = (float) v.s;
|
uvmap[v2 + 1] = (float) v.t;
|
|
if (v.norm != null)
|
{
|
normals[v3] = (float) v.norm.x;
|
normals[v3 + 1] = (float) v.norm.y;
|
normals[v3 + 2] = (float) v.norm.z;
|
}
|
|
countV++;
|
} else
|
{
|
if (v.index == -1)
|
{
|
v.index = maxIndexV++;
|
}
|
|
if (maxIndexV <= v.index)
|
{
|
maxIndexV = v.index + 1;
|
}
|
|
sortedVertices = null;
|
|
vertices.addElement(v); // new Vertex(v));
|
}
|
}
|
|
int Remember(Vertex v)
|
{
|
assert !trimmed;
|
|
if (Double.isNaN(v.x))
|
assert(!Double.isNaN(v.x));
|
|
AddVertex(v);
|
|
//if (true) return;
|
|
vertextable.put(v, v);
|
|
return v.index;
|
}
|
|
int VertexCount()
|
{
|
if (trimmed && positions != null)
|
{
|
return positions.length / 3;
|
} else
|
{
|
return vertices.size();
|
}
|
}
|
|
int FaceCount()
|
{
|
if (trimmed && triangles != null)
|
//if (trimmed || triangles != null) // juin 2014
|
{
|
return triangles.length / 3;
|
} else
|
{
|
return faces.size();
|
}
|
}
|
|
static Face[] sFace = new Face[1000];
|
static int indexF = 0;
|
|
static
|
{
|
for (int i = 0; i < sFace.length; i++)
|
{
|
sFace[i] = new Face();
|
}
|
}
|
|
Face GetFace(int i)
|
{
|
// assert(!stripified);
|
// if (stripified)
|
// return null;
|
|
if (trimmed)
|
//if (trimmed || triangles != null) // juin 2014
|
{
|
Face f = sFace[indexF++];
|
indexF %= sFace.length;
|
|
int i3 = i * 3;
|
f.p = triangles[i3];
|
f.q = triangles[i3 + 1];
|
f.r = triangles[i3 + 2];
|
|
return f;
|
} else
|
{
|
return (Face) faces.elementAt(i);
|
}
|
}
|
|
Vertex GetCache(Vertex v)
|
{
|
assert !trimmed;
|
|
return (Vertex) vertextable.get(v);
|
}
|
|
void setFace(int face, int p, int q, int r)
|
{
|
if (trimmed)
|
{
|
int f3 = face * 3;
|
triangles[f3] = p;
|
triangles[f3 + 1] = q;
|
triangles[f3 + 2] = r;
|
} else
|
{
|
Face temp = new Face();
|
if (p < VertexCount() && vertices.get(p) != null)
|
{
|
if (p != ((Vertex) vertices.get(p)).index && // NEW
|
((Vertex) vertices.get(p)).index != -1)
|
{
|
p = ((Vertex) vertices.get(p)).index;
|
}
|
if (q != ((Vertex) vertices.get(q)).index &&
|
((Vertex) vertices.get(p)).index != -1)
|
{
|
q = ((Vertex) vertices.get(q)).index;
|
}
|
if (r != ((Vertex) vertices.get(r)).index &&
|
((Vertex) vertices.get(p)).index != -1)
|
{
|
r = ((Vertex) vertices.get(r)).index;
|
}
|
}
|
temp.p = p;
|
temp.q = q;
|
temp.r = r;
|
faces.setElementAt(temp, face);
|
//System.out.println("AddFace = " + p + ", " + q + ", " + r);
|
}
|
}
|
|
void setFace(int face, int verts[])
|
{
|
setFace(face, verts[0], verts[1], verts[2]);
|
}
|
|
void setVertex(int vert, double x, double y, double z, float u, float v)
|
{
|
if (trimmed)
|
{
|
int v3 = vert * 3;
|
positions[v3] = (float) x;
|
positions[v3 + 1] = (float) y;
|
positions[v3 + 2] = (float) z;
|
} else
|
{
|
Vertex temp = new Vertex();
|
temp./*pos.*/x = x; // = LA.newVector(x, y, z);
|
temp./*pos.*/y = y;
|
temp./*pos.*/z = z;
|
temp.s = u;
|
temp.t = v;
|
vertices.setElementAt(temp, vert);
|
}
|
}
|
|
//static Vertex[] temp = new Vertex[0];
|
Vertex[] transform(double mat[][])
|
{
|
new Exception().printStackTrace();
|
int nVerts = VertexCount();
|
|
if (verticesCopy == null || verticesCopy.length != nVerts)
|
{
|
verticesCopy = new Vertex[nVerts];
|
for (int i = 0; i < nVerts; i++)
|
{
|
verticesCopy[i] = new Vertex();
|
//verticesCopy[i].pos = new cVector();
|
}
|
}
|
for (int i = 0; i < nVerts; i++)
|
{
|
Vertex in = (Vertex) GetVertex(i);
|
LA.xformPos(in/*.pos*/, mat, verticesCopy[i]/*.pos*/);
|
}
|
|
return verticesCopy;
|
}
|
|
void PreprocessOcclusion(iCameraPane cp, double[][] transform)
|
{
|
if (//!trimmed ||
|
AOdone)
|
{
|
// no color in Vertex
|
return;
|
}
|
|
cp.PrepOcclusion(this, transform);
|
|
AOdone = true;
|
}
|
|
void Append(StringBuffer s, float f)
|
{
|
boolean neg = false;
|
|
if (f != 0)
|
{
|
float factor = 1;
|
|
if (f < 0)
|
{
|
neg = true;
|
f = -f;
|
}
|
|
while (f*factor < 100)
|
{
|
factor *= 10;
|
}
|
|
f = (float) Math.floor(f*factor) / factor;
|
}
|
|
s.append(neg?-f:f);
|
}
|
|
String export()
|
{
|
if (!trimmed || !stripified)
|
return "0";
|
|
StringBuffer s = new StringBuffer();
|
|
s.append(triangles.length);
|
s.append(" ");
|
|
for (int i=0; i<triangles.length; i++)
|
{
|
s.append(triangles[i]);
|
s.append(" ");
|
}
|
|
s.append("\n");
|
s.append(positions.length/3);
|
s.append(" ");
|
|
for (int i=0; i<positions.length; i++)
|
{
|
Append(s, positions[i]);
|
s.append(" ");
|
}
|
|
s.append("\n");
|
|
for (int i=0; i<normals.length; i++)
|
{
|
Append(s, normals[i]);
|
s.append(" ");
|
}
|
|
s.append("\n");
|
|
int l = positions.length;
|
|
if (colors != null)
|
{
|
assert (l == colors.length);
|
}
|
|
for (int i=0; i<l; i++)
|
{
|
if (colors != null)
|
Append(s, colors[i]);
|
else
|
Append(s, 1.0f);
|
|
s.append(" ");
|
}
|
|
s.append("\n");
|
|
for (int i=0; i<uvmap.length; i++)
|
{
|
Append(s, uvmap[i]);
|
s.append(" ");
|
}
|
|
s.append("\n");
|
|
return s.toString();
|
}
|
|
void ClearColors()
|
{
|
AOdone = false;
|
if (colors == null)
|
{
|
for (int i = 0; i < VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
v.AO = 1;
|
}
|
}
|
colors = null;
|
}
|
|
void CreateMesh(iHeightField hf, int x, int y)
|
{
|
BoundaryRep tmp = new BoundaryRep();
|
|
int vc = 0;
|
|
Vertex v = new Vertex(true);
|
|
for (int i=0; i<x; i++)
|
{
|
for (int j=0; j<y; j++)
|
{
|
// Vertex v = tmp.GetVertex(vc++);
|
|
v.s = v.x = i;
|
v.t = v.z = j;
|
v.s /= x; v.t /= y;
|
v.y = hf.f(i,j);
|
|
int iu = tmp.AddTableVertex(v);
|
|
v.s = v.x = i+1;
|
v.t = v.z = j;
|
v.s /= x; v.t /= y;
|
v.y = hf.f(i+1,j);
|
|
int iv = tmp.AddTableVertex(v);
|
|
v.s = v.x = i+1;
|
v.t = v.z = j+1;
|
v.s /= x; v.t /= y;
|
v.y = hf.f(i+1,j+1);
|
|
int iw = tmp.AddTableVertex(v);
|
|
v.s = v.x = i;
|
v.t = v.z = j+1;
|
v.s /= x; v.t /= y;
|
v.y = hf.f(i,j+1);
|
|
int ix = tmp.AddTableVertex(v);
|
|
tmp.AddFace(iu,iw,iv);
|
tmp.AddFace(iu,ix,iw);
|
}
|
}
|
|
Set(tmp);
|
|
Trim(true,false,true);
|
ClearColors();
|
}
|
|
void Stripify()
|
{
|
if (stripified)
|
return;
|
|
try
|
{
|
Untrim();
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
Trim(true,false,true,true,false);
|
}
|
|
void Unstripify()
|
{
|
if (trimmed) // may 2014
|
Untrim();
|
|
BoundaryRep bRep = this;
|
|
if (bRep.stripified)
|
{
|
//throw new Error();
|
|
int[] strips = bRep.getRawIndices();
|
|
if (strips == null)
|
{
|
// dec 2012
|
new Exception().printStackTrace();
|
return;
|
}
|
|
// TRIANGLE STRIP ARRAY
|
if (false) // bRep.trimmed)
|
{
|
}
|
else // !trimmed
|
{
|
BoundaryRep newrep = new BoundaryRep();
|
|
int count = 0;
|
for (int i = 0; i < strips.length; i++)
|
{
|
int index = count++;
|
|
if (bRep.indices != null)
|
{
|
index = bRep.indices[count-1];
|
}
|
|
Vertex p = bRep.GetVertex(index);
|
|
index = count++;
|
|
if (bRep.indices != null)
|
{
|
index = bRep.indices[count-1];
|
}
|
|
Vertex q = bRep.GetVertex(index);
|
|
int indexp = newrep.AddTableVertex(p);
|
int indexq = newrep.AddTableVertex(q);
|
// drawVertex(gl, p, selectmode);
|
// drawVertex(gl, q, selectmode);
|
|
int indexr;
|
|
for (int j = 0; j < strips[i] - 2; j++)
|
{
|
index = count++;
|
|
if (bRep.indices != null)
|
{
|
index = bRep.indices[count-1];
|
}
|
|
Vertex r = bRep.GetVertex(index);
|
|
indexr = newrep.AddTableVertex(r);
|
|
if (j%2 == 0)
|
newrep.AddFace(indexp, indexq, indexr);
|
else
|
newrep.AddFace(indexp, indexr, indexq);
|
|
indexp = indexq;
|
indexq = indexr;
|
|
// if (j%2 == 0)
|
// drawFace(p, q, r, display, null);
|
// else
|
// drawFace(p, r, q, display, null);
|
|
// p = q;
|
// q = r;
|
// drawVertex(gl, r, selectmode);
|
}
|
}
|
|
Set(newrep);
|
}
|
}
|
}
|
|
void ReverseNormals()
|
{
|
if (normals == null)
|
return;
|
|
for (int i=0; i<normals.length; i++)
|
{
|
normals[i] = -normals[i];
|
}
|
}
|
|
void ReverseTriangles()
|
{
|
boolean wastrimmed = trimmed;
|
|
try
|
{
|
Untrim();
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
for (int i=0; i<faces.size(); i++)
|
{
|
Face f = faces.get(i);
|
int t = f.p;
|
f.p = f.q;
|
f.q = t;
|
}
|
|
//Trim(true,true,false,true,false);
|
if (wastrimmed)
|
Trim(true,false,false,false,false);
|
}
|
|
int ChooseBestTriangle()
|
{
|
int chosen = -1;
|
|
double weight = 1E10;
|
|
Vector<Face> used = new Vector();
|
cVector e1 = new cVector();
|
|
for (int i=0; i<faces.size(); i++)
|
{
|
Face face = (Face) faces.get(i);
|
|
if (face.weight < 0)
|
continue;
|
|
/*
|
Vertex p = (Vertex) vertices.get(face.p);
|
Vertex q = (Vertex) vertices.get(face.q);
|
Vertex r = (Vertex) vertices.get(face.r);
|
|
e1.cross(p.norm, q.norm);
|
|
double test = r.norm.dot(e1);
|
|
if (test < 0)
|
test = -test;
|
|
if (test > 0.001)
|
continue;
|
*/
|
|
float w = 0; // face.weight;
|
int count = 0;
|
|
used.clear();
|
|
Vector<Face> faces = links.get(face.p);
|
//for (Face f : links.get(face.p))
|
for (int j=faces.size(); --j>=0;)
|
{
|
Face f = faces.get(j);
|
if (!used.contains(f))
|
{
|
w += /*Math.abs*/(f.weight);
|
//count += 1;
|
used.add(f);
|
}
|
}
|
|
faces = links.get(face.q);
|
//for (Face f : links.get(face.q))
|
for (int j=faces.size(); --j>=0;)
|
{
|
Face f = faces.get(j);
|
|
if (!used.contains(f))
|
{
|
w += /*Math.abs*/(f.weight);
|
//count += 1;
|
used.add(f);
|
}
|
}
|
|
faces = links.get(face.r);
|
//for (Face f : links.get(face.r))
|
for (int j=faces.size(); --j>=0;)
|
{
|
Face f = faces.get(j);
|
if (!used.contains(f))
|
{
|
w += /*Math.abs*/(f.weight);
|
//count += 1;
|
used.add(f);
|
}
|
}
|
|
//w /= count;
|
|
//if (face.weight < 0)
|
// w *= 10;
|
|
if (weight > w)
|
{
|
weight = w;
|
chosen = i;
|
}
|
}
|
|
return chosen;
|
}
|
|
boolean Valid(Face face)
|
{
|
if (face.good == 0)
|
return false;
|
|
// if (!ValidVertex(face.p))
|
// return false;
|
// if (!ValidVertex(face.q))
|
// return false;
|
//if (!ValidVertex(face.r))
|
// return false;
|
|
return true;
|
}
|
|
transient int nbbadfaces; // ?? = 1000000;
|
|
/*
|
*/
|
int ChooseTriangle(boolean firstEquilateral)
|
{
|
int chosen = -1;
|
|
double minweight = 1E10;
|
|
int step = 8; // ?
|
|
if (firstEquilateral)
|
step = 1;
|
|
nbbadfaces = 0;
|
for (int i=0; i<faces.size(); i+=step)
|
// for (int i=faces.size(); (i-=8)>=0;)
|
{
|
Face face = (Face) faces.get(i);
|
|
if (face.used)
|
continue;
|
|
if (!Valid(face))
|
{
|
nbbadfaces++;
|
continue;
|
}
|
|
if (Boundary(face))
|
continue;
|
|
// if (Boundary(face.p))
|
// continue;
|
//
|
// if (Boundary(face.q))
|
// continue;
|
//
|
// if (Boundary(face.r))
|
// continue;
|
|
if (!ValidValence(face))
|
continue;
|
|
if (!ValidValence(face.p) ||
|
!ValidValence(face.q) ||
|
!ValidValence(face.r))
|
continue;
|
|
//?? if (face.weight < 0)
|
// continue;
|
|
if (firstEquilateral)
|
{
|
if (OneFaceUsed(links.get(face.p)))
|
continue;
|
|
if (OneFaceUsed(links.get(face.q)))
|
continue;
|
|
if (OneFaceUsed(links.get(face.r)))
|
continue;
|
|
chosen = i;
|
break;
|
}
|
else
|
{
|
double K = 1; // 0.01; // .25;
|
|
double factor = (1-K)*face.nbiterations + K; //*face.weight;
|
|
double weight = FaceWeight(face); // *Math.pow(PerimeterMax(face),0.25)*factor;
|
|
if (minweight > weight)
|
{
|
minweight = weight;
|
chosen = i;
|
if (minweight == 0)
|
break;
|
}
|
}
|
}
|
|
return chosen;
|
}
|
|
private boolean OneFaceUsed(Vector<Face> faces)
|
{
|
if (faces.size() != 6)
|
return true;
|
|
for (int i=0; i<6; i+=1)
|
{
|
if (faces.get(i).used)
|
{
|
return true;
|
}
|
}
|
|
return false;
|
}
|
|
static boolean remove3valence = true;
|
|
//boolean[] linkstouched;
|
|
boolean InitLinks(boolean valenceonly) // throws Exception
|
{
|
//valenceonly = false; // june 2014
|
|
int loopcount = 0;
|
|
boolean modified = false;
|
|
while (true)
|
{
|
loopcount++;
|
if (links == null || !valenceonly || loopcount > 1) // == 2)
|
{
|
// if (linkstouched == null || linkstouched.length != vertices.size())
|
// {
|
// linkstouched = new boolean[vertices.size()];
|
// }
|
|
if (links == null)
|
{
|
links = new Vector(vertices.size());
|
|
for (int i=vertices.size(); --i>=0;)
|
{
|
links.add(new Vector(8));
|
}
|
}
|
else
|
{
|
// TODO Grafreed.Assert(links.size() == vertices.size());
|
|
links.setSize(vertices.size());
|
for (int i=vertices.size(); --i>=0;)
|
{
|
// linkstouched[i] = false;
|
if (links.get(i) == null) // ??
|
{
|
new Exception().printStackTrace();
|
links.set(i, new Vector(8));
|
// linkstouched[i] = true;
|
}
|
else
|
links.get(i).clear();
|
|
vertices.get(i).boundary = -1;
|
}
|
}
|
|
boolean once = false;
|
|
for (int i=faces.size(); --i>=0;)
|
{
|
Face face = (Face) faces.get(i);
|
|
//if (linkstouched[face.p])
|
links.get(face.p).add(face);
|
//if (linkstouched[face.q])
|
links.get(face.q).add(face);
|
//if (linkstouched[face.r])
|
links.get(face.r).add(face);
|
|
if (face.used)
|
once = true;
|
|
face.good = 1;
|
face.boundary = -1;
|
}
|
|
modified = true;
|
}
|
|
boolean broken = true;
|
|
// remove 3-valence vertices
|
if (remove3valence)
|
for (int i=vertices.size(); --i>=0;)
|
{
|
if (links == null)
|
links = null;
|
|
Vector<Face> vfaces = links.get(i);
|
|
//if (vfaces == null) // june 2014
|
// continue;
|
|
if (vfaces.size() != 3)
|
continue;
|
|
if (Boundary(i))
|
continue;
|
|
Face f0 = vfaces.get(0);
|
Face f1 = vfaces.get(1);
|
Face f2 = vfaces.get(2);
|
|
int otherindex = -1;
|
|
if (f1.p != f0.p && f1.p != f0.q && f1.p != f0.r)
|
otherindex = f1.p;
|
if (f1.q != f0.p && f1.q != f0.q && f1.q != f0.r)
|
otherindex = f1.q;
|
if (f1.r != f0.p && f1.r != f0.q && f1.r != f0.r)
|
otherindex = f1.r;
|
|
if (otherindex == -1)
|
{
|
// WARNING!!!
|
//assert (otherindex != -1);
|
if (f2.p != f0.p && f2.p != f0.q && f2.p != f0.r)
|
otherindex = f2.p;
|
if (f2.q != f0.p && f2.q != f0.q && f2.q != f0.r)
|
otherindex = f2.q;
|
if (f2.r != f0.p && f2.r != f0.q && f2.r != f0.r)
|
otherindex = f2.r;
|
|
// assert (otherindex != -1);
|
//System.err.println("otherindex == -1 !!");
|
continue;
|
// if (otherindex == -1)
|
// throw new Exception("index == -1");
|
}
|
|
broken = false;
|
|
// assert(!lock);
|
faces.remove(f1);
|
faces.remove(f2);
|
|
if (f0.p == i)
|
{
|
f0.p = otherindex;
|
}
|
if (f0.q == i)
|
{
|
f0.q = otherindex;
|
}
|
if (f0.r == i)
|
{
|
f0.r = otherindex;
|
}
|
|
f0.good = 0;
|
if (leafweights)
|
f0.weight = -1;
|
else
|
{
|
FaceWeight(f0);
|
f0.weight += FaceWeight(f1);
|
f0.weight += FaceWeight(f2);
|
}
|
|
f0.boundary = -1;
|
f0.nbiterations += 1;
|
TouchVertex(f0.p, false);
|
TouchVertex(f0.q, false);
|
TouchVertex(f0.r, false);
|
}
|
|
// remove3valence = false;
|
|
if (broken)
|
break;
|
}
|
|
// assert(loopcount <= 2);
|
|
return modified;
|
}
|
|
double Curvature(Vertex p, Vertex q, Vertex r)
|
{
|
double curvature = 0;
|
|
if (true)
|
{
|
/*
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
double area;
|
|
if (true) // true)
|
{
|
// triangle area
|
e3.cross(e1,e2);
|
area = e3.length()/2;
|
}
|
else
|
{
|
e3.set(r);
|
e3.sub(q);
|
|
area = e1.length() + e2.length() + e3.length();
|
}
|
|
e3.cross(p.norm, q.norm);
|
|
double vol = r.norm.dot(e3);
|
|
if (vol < 0)
|
vol = -vol;
|
|
//area *= Math.sqrt(vol) + 0.0001;
|
//area = vol;
|
|
face.weight = (float) area;
|
|
// if (vol > 0.01)
|
// face.weight = -face.weight;
|
*/
|
|
p1.set(p.norm);
|
p2.set(q.norm);
|
p3.set(r.norm);
|
|
// p1.sub(p2);
|
// p2.sub(p3);
|
// p3.sub(p.norm);
|
// e1.set(p);
|
// e1.sub(q);
|
// e2.set(p);
|
// e2.sub(r);
|
// e3.set(q);
|
// e3.sub(r);
|
// //double volume = Volume(p1,p2,p3); // hmm...
|
// curvature = Math.sqrt(p1.dot(p1) + p2.dot(p2) + p3.dot(p3));
|
//
|
// curvature *= Math.sqrt(e1.dot(e1) + e2.dot(e2) + e3.dot(e3));
|
|
curvature = PerimeterMax2(p1,p2,p3); // + 1; // #1
|
curvature *= PerimeterMax2(p,q,r);
|
// curvature = Area(p1,p2,p3); // +1; // #2
|
// curvature *= Perimeter(p,q,r);
|
|
// curvature = PerimeterDelta(p1,p2,p3)*Perimeter(p,q,r);
|
// curvature /= PerimeterDelta(p,q,r)/PerimeterMax(p,q,r);
|
|
//curvature *= MinAngle(p,q,r);
|
// curvature *= Math.sqrt(Area(p,q,r));
|
// curvature = Area(p1,p2,p3);
|
// curvature *= Area(p,q,r);
|
|
// volume
|
/* TETRA
|
double volume = Volume(p,r,q);
|
|
p1.set(p);
|
p1.add(p.norm);
|
p1.add(p.norm);
|
p1.add(p.norm);
|
p2.set(q);
|
p2.add(q.norm);
|
p2.add(q.norm);
|
p2.add(q.norm);
|
p3.set(r);
|
p3.add(r.norm);
|
p3.add(r.norm);
|
p3.add(r.norm);
|
|
volume += Volume(p,p1,r);
|
volume += Volume(p1,p3,r);
|
volume += Volume(p,q,p2);
|
volume += Volume(p,p2,p1);
|
volume += Volume(q,p3,p2);
|
volume += Volume(q,r,p3);
|
volume += Volume(p1,p2,p3);
|
*/
|
|
// if (volume < 0) // hum
|
// volume = -volume;
|
|
// e2.set(q.s-p.s,q.t-p.t,0);
|
// e3.set(r.s-p.s,r.t-p.t,0);
|
// e1.set(r.s-q.s,r.t-q.t,0);
|
// //e1.cross(e2,e3);
|
//
|
// double texarea = e1.dot(e1) + e2.dot(e2) + e3.dot(e3); // e1.length();
|
}
|
else
|
{
|
double areabase = Area(p,q,r);
|
|
/*
|
p1.set(p);
|
p2.set(q);
|
p3.set(r);
|
p1.add(p.norm);
|
p2.add(q.norm);
|
p3.add(r.norm);
|
|
double areanorm = Area(p1,p2,p3);
|
|
curvature = (areanorm - areabase); ///areabase;
|
*/
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
double mindot = e3.dot(p.norm);
|
|
double dot = e3.dot(q.norm);
|
|
if (mindot > dot)
|
mindot = dot;
|
|
dot = e3.dot(r.norm);
|
|
if (mindot > dot)
|
mindot = dot;
|
|
curvature = Math.sqrt(areabase)/mindot;
|
}
|
|
return Math.abs(curvature);
|
}
|
|
double AngleWeight(Face face)
|
{
|
double weight = 0;
|
|
Vertex p = GetVertex(face.p);
|
Vertex q = GetVertex(face.q);
|
Vertex r = GetVertex(face.r);
|
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
p1.set(p);
|
p1.add(q);
|
p1.add(r);
|
p1.mul(1.0/3); // triangle center
|
|
//int count = 0;
|
|
for (int v=0; v<3; v++)
|
{
|
int vert = face.p;
|
if (v == 1)
|
vert = face.q;
|
if (v == 2)
|
vert = face.r;
|
|
Vector<Face> vf = links.get(vert);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (!Valid(f))
|
{
|
return 1E10;
|
// continue;
|
}
|
|
while (vert != f.r)
|
{
|
int temp = f.p;
|
f.p = f.q;
|
f.q = f.r;
|
f.r = temp;
|
}
|
|
if (f.p == face.p || f.p == face.q || f.p == face.r)
|
{
|
continue;
|
}
|
if (f.q == face.p || f.q == face.q || f.q == face.r)
|
{
|
continue;
|
}
|
|
Vertex a = GetVertex(f.p);
|
Vertex b = GetVertex(f.q);
|
|
e1.set(a);
|
e1.sub(p1);
|
e2.set(b);
|
e2.sub(p1);
|
|
r1.cross(e1, e2); // new triangle normal
|
r1.normalize();
|
|
double cos = r1.dot(e3);
|
double tan = Math.sqrt
|
(1 - cos*cos) //
|
// 1 - Math.abs(cos)
|
;
|
|
if (weight < tan)
|
weight = tan;
|
|
//count++;
|
}
|
}
|
|
return weight // * Eccentricity(face); // Math.sqrt(Area(face));
|
// * Perimeter(face);
|
// * Math.sqrt(Area(face));
|
* Area(face);
|
// * Eccentricity(face);
|
// * PerimeterMax(face);
|
}
|
|
double CenterWeight(Face face)
|
{
|
double weight = 0;
|
|
Vertex p = GetVertex(face.p);
|
Vertex q = GetVertex(face.q);
|
Vertex r = GetVertex(face.r);
|
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
p1.set(p);
|
p1.add(q);
|
p1.add(r);
|
p1.mul(1.0/3); // triangle center
|
|
//int count = 0;
|
|
for (int v=0; v<3; v++)
|
{
|
int vert = face.p;
|
if (v == 1)
|
vert = face.q;
|
if (v == 2)
|
vert = face.r;
|
|
Vertex vertex = vertices.get(vert);
|
|
e1.set(p1);
|
e1.sub(vertex);
|
|
double dn = e3.dot(vertex.norm);
|
|
double w = e1.dot(vertex.norm);
|
|
w = w / dn;
|
//w = Math.abs(w);
|
w = w*w;
|
// w = w*w;
|
|
if (weight < w)
|
{
|
weight = w;
|
}
|
}
|
|
return weight; // * Area(face);
|
}
|
|
double CurvatureWeight(Face face)
|
{
|
double weight = 0;
|
|
Vertex p = GetVertex(face.p);
|
Vertex q = GetVertex(face.q);
|
Vertex r = GetVertex(face.r);
|
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
for (int v=0; v<3; v++)
|
{
|
int vert = face.p;
|
if (v == 1)
|
vert = face.q;
|
if (v == 2)
|
vert = face.r;
|
|
Vector<Face> vf = links.get(vert);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex pq = GetVertex(f.q);
|
Vertex pr = GetVertex(f.r);
|
|
e1.set(pp);
|
e1.sub(p);
|
|
double dot = Math.abs(e1.dot(e3));
|
|
if (weight < dot)
|
weight = dot;
|
|
e1.set(pq);
|
e1.sub(p);
|
|
dot = Math.abs(e1.dot(e3));
|
|
if (weight < dot)
|
weight = dot;
|
|
e1.set(pr);
|
e1.sub(p);
|
|
dot = Math.abs(e1.dot(e3));
|
|
if (weight < dot)
|
weight = dot;
|
}
|
}
|
|
return weight * Eccentricity(face); // * PerimeterMax(face);
|
}
|
|
double Eccentricity(Face face)
|
{
|
return Perimeter(face) / Math.sqrt(Area(face));
|
}
|
|
double AreaRatio(Face face)
|
{
|
double area;
|
|
double basearea = 0;
|
double baseweight = 0;
|
|
int weightcount = 0;
|
|
Vector<Face> vf = links.get(face.p);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.q || f.q == face.q || f.r == face.q)
|
continue;
|
|
basearea += Area(f);
|
baseweight += Weight(f);
|
weightcount += 1;
|
}
|
|
vf = links.get(face.q);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.r || f.q == face.r || f.r == face.r)
|
continue;
|
|
basearea += Area(f);
|
baseweight += Weight(f);
|
weightcount += 1;
|
}
|
|
vf = links.get(face.r);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.p || f.q == face.p || f.r == face.p)
|
continue;
|
|
basearea += Area(f);
|
baseweight += Weight(f);
|
weightcount += 1;
|
}
|
|
basearea += Area(face);
|
baseweight += Weight(face);
|
weightcount += 1;
|
baseweight /= weightcount;
|
|
Vertex p = GetVertex(face.p);
|
Vertex q = GetVertex(face.q);
|
Vertex r = GetVertex(face.r);
|
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
q1.set(p);
|
q2.set(q);
|
q3.set(r);
|
|
s1.set(p.norm);
|
s2.set(q.norm);
|
s3.set(r.norm);
|
|
p1.set(p);
|
p1.add(q);
|
p1.add(r);
|
p1.mul(1./3);
|
|
p.set(p1);
|
q.set(p1);
|
r.set(p1);
|
|
p1.set(p.norm);
|
p1.add(q.norm);
|
p1.add(r.norm);
|
p1.mul(1./3);
|
p1.normalize();
|
|
p.norm.set(p1);
|
q.norm.set(p1);
|
r.norm.set(p1);
|
|
double weight = 0;
|
weightcount = 0;
|
|
double resultarea = 0;
|
double dispersion = -1;
|
|
double scattering = -1;
|
|
vf = links.get(face.p);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.q || f.q == face.q || f.r == face.q ||
|
f.p == face.r || f.q == face.r || f.r == face.r)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex qp = GetVertex(f.q);
|
Vertex rp = GetVertex(f.r);
|
|
e1.set(qp);
|
e1.sub(pp);
|
e2.set(rp);
|
e2.sub(pp);
|
|
p3.cross(e1, e2); // triangle normal
|
p3.normalize();
|
|
double angle = Math.acos((e3.dot(p3)+1)/2);
|
|
area = Area(f);
|
|
double disp = angle*Area(f);
|
|
if (dispersion < disp)
|
dispersion = disp;
|
|
resultarea += area;
|
|
double scat = Scattering(f);
|
if (scattering < scat)
|
scattering = scat;
|
|
//double w = PerimeterDelta(f)*PerimeterDelta(f)*Perimeter(f);
|
double w = Weight(f); // PerimeterMax2(f)*PerimeterMax2(pp,qp,rp);
|
if (weight < w)
|
weight = w;
|
weightcount += 1;
|
}
|
|
vf = links.get(face.q);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.p || f.q == face.p || f.r == face.p ||
|
f.p == face.r || f.q == face.r || f.r == face.r)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex qp = GetVertex(f.q);
|
Vertex rp = GetVertex(f.r);
|
|
e1.set(qp);
|
e1.sub(pp);
|
e2.set(rp);
|
e2.sub(pp);
|
|
p3.cross(e1, e2); // triangle normal
|
p3.normalize();
|
|
double angle = Math.acos((e3.dot(p3)+1)/2);
|
|
area = Area(f);
|
|
double disp = angle*Area(f);
|
|
if (dispersion < disp)
|
dispersion = disp;
|
|
resultarea += area;
|
|
double scat = Scattering(f);
|
if (scattering < scat)
|
scattering = scat;
|
|
//double w = PerimeterDelta(f)*PerimeterDelta(f)*Perimeter(f);
|
double w = Weight(f); // PerimeterMax2(f)*PerimeterMax2(pp,qp,rp);
|
if (weight < w)
|
weight = w;
|
weightcount += 1;
|
}
|
|
vf = links.get(face.r);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.p || f.q == face.p || f.r == face.p ||
|
f.p == face.q || f.q == face.q || f.r == face.q)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex qp = GetVertex(f.q);
|
Vertex rp = GetVertex(f.r);
|
|
e1.set(qp);
|
e1.sub(pp);
|
e2.set(rp);
|
e2.sub(pp);
|
|
p3.cross(e1, e2); // triangle normal
|
p3.normalize();
|
|
double angle = Math.acos((e3.dot(p3)+1)/2);
|
|
area = Area(f);
|
|
double disp = angle*Area(f);
|
|
if (dispersion < disp)
|
dispersion = disp;
|
|
resultarea += area;
|
|
double scat = Scattering(f);
|
if (scattering < scat)
|
scattering = scat;
|
|
//double w = PerimeterDelta(f)*PerimeterDelta(f)*Perimeter(f);
|
double w = Weight(f); // PerimeterMax2(f)*PerimeterMax2(pp,qp,rp);
|
if (weight < w)
|
weight = w;
|
weightcount += 1;
|
}
|
|
p.set(q1);
|
q.set(q2);
|
r.set(q3);
|
|
p.norm.set(s1);
|
q.norm.set(s2);
|
r.norm.set(s3);
|
|
// if (basearea < resultarea)
|
// assert(basearea >= resultarea * (1 - 1E-5));
|
|
//return scattering; // dispersion;
|
return weight; // Math.abs(weight/weightcount); // - baseweight); //
|
// (basearea - resultarea); // / basearea;
|
}
|
|
double FaceWeight(Face face)
|
{
|
if (face.weight == -1)
|
{
|
// if (neighbors) // criterion
|
// {
|
// face.weight = (float) AreaRatio(face);
|
// }
|
// else
|
// {
|
// //Vertex p = (Vertex)vertices.get(face.p);
|
// //Vertex q = (Vertex)vertices.get(face.q);
|
// //Vertex r = (Vertex)vertices.get(face.r);
|
//
|
// face.weight = (float)Weight(face); // (float) Curvature(p,q,r);
|
// }
|
face.weight = (float) CenterWeight(face); // CurvatureWeight(face);
|
}
|
|
return face.weight;
|
}
|
|
void InitWeights()
|
{
|
new Exception().printStackTrace();
|
System.exit(0);
|
int n = 0;
|
int b = 0;
|
for (int i=faces.size(); --i>=0;)
|
{
|
Face face = (Face) faces.get(i);
|
|
if (face.good == 1)
|
continue;
|
|
n++;
|
b++;
|
|
//if (!firstpass)
|
face.good = 1; // true;
|
|
face.weight = 10000;
|
|
if (Boundary(face))
|
continue;
|
|
face.good = 1; // true;
|
|
b--;
|
|
if (neighbors) // criterion
|
{
|
face.weight = (float) AreaRatio(face);
|
}
|
else
|
{
|
Vertex p = (Vertex)vertices.get(face.p);
|
Vertex q = (Vertex)vertices.get(face.q);
|
Vertex r = (Vertex)vertices.get(face.r);
|
|
face.weight = (float) Curvature(p,q,r);
|
}
|
if (face.weight >= 10000)
|
assert(face.weight < 10000);
|
//face.weight += (float)texarea;
|
|
// if (face.weight > 1)
|
// face.weight = -1;
|
}
|
|
//System.out.println("" + b + " boundary out of " + n + " updates");
|
}
|
|
double Perimeter(cVector p, cVector q, cVector r)
|
{
|
r1.set(p);
|
r1.sub(q);
|
r2.set(p);
|
r2.sub(r);
|
r3.set(q);
|
r3.sub(r);
|
|
return Math.sqrt(r1.dot(r1)) + Math.sqrt(r2.dot(r2)) + Math.sqrt(r3.dot(r3));
|
}
|
|
double Perimeter2(cVector p, cVector q, cVector r)
|
{
|
r1.set(p);
|
r1.sub(q);
|
r2.set(p);
|
r2.sub(r);
|
r3.set(q);
|
r3.sub(r);
|
|
return e1.dot(e1) + e2.dot(e2) + e3.dot(e3);
|
}
|
|
// roughly the max
|
double PerimeterMax2(cVector p, cVector q, cVector r)
|
{
|
r1.set(p);
|
r1.sub(q);
|
r2.set(p);
|
r2.sub(r);
|
r3.set(q);
|
r3.sub(r);
|
|
return Math.sqrt(r1.dot(r1) + r2.dot(r2) + r3.dot(r3));
|
//return (r1.dot(r1) + r2.dot(r2) + r3.dot(r3));
|
}
|
|
double PerimeterMax(cVector p, cVector q, cVector r)
|
{
|
r1.set(p);
|
r1.sub(q);
|
r2.set(p);
|
r2.sub(r);
|
r3.set(q);
|
r3.sub(r);
|
|
double max = r1.dot(r1);
|
double test = r2.dot(r2);
|
|
if (max < test)
|
max = test;
|
|
test = r3.dot(r3);
|
|
if (max < test)
|
max = test;
|
|
return Math.sqrt(max);
|
}
|
|
// max - min
|
double PerimeterDelta(cVector p, cVector q, cVector r)
|
{
|
r1.set(p);
|
r1.sub(q);
|
r2.set(p);
|
r2.sub(r);
|
r3.set(q);
|
r3.sub(r);
|
|
double max = r1.dot(r1);
|
double min = max;
|
double test = r2.dot(r2);
|
|
if (max < test)
|
max = test;
|
if (min > test)
|
min = test;
|
|
test = r3.dot(r3);
|
|
if (max < test)
|
max = test;
|
if (min > test)
|
min = test;
|
|
return Math.sqrt(max) - Math.sqrt(min);
|
}
|
|
double Perimeter(Face f)
|
{
|
return Perimeter(vertices.get(f.p), vertices.get(f.q), vertices.get(f.r));
|
}
|
|
double PerimeterMax(Face f)
|
{
|
return PerimeterMax(vertices.get(f.p), vertices.get(f.q), vertices.get(f.r));
|
}
|
|
double Weight(Face f)
|
{
|
Vertex p = vertices.get(f.p);
|
Vertex q = vertices.get(f.q);
|
Vertex r = vertices.get(f.r);
|
cVector np = vertices.get(f.p).norm;
|
cVector nq = vertices.get(f.q).norm;
|
cVector nr = vertices.get(f.r).norm;
|
|
r1.set(q);
|
r1.sub(p);
|
r2.set(r);
|
r2.sub(p);
|
r3.set(r);
|
r3.sub(q);
|
|
if (false)
|
{
|
//r1.normalize();
|
//r2.normalize();
|
//r3.normalize();
|
|
e1.cross(r1, np);
|
//e1.normalize();
|
e2.cross(r2, np);
|
//e2.normalize();
|
e3.cross(r3, nq);
|
//e3.normalize();
|
|
double twist = Math.abs(e1.dot(nq));
|
double t = Math.abs(e2.dot(nr));
|
//if (twist < t)
|
twist += t;
|
|
t = Math.abs(e3.dot(nr));
|
//if (twist < t)
|
twist += t;
|
|
e1.cross(r1, nq);
|
//e1.normalize();
|
e2.cross(r2, nr);
|
//e2.normalize();
|
e3.cross(r3, nr);
|
//e3.normalize();
|
|
t = Math.abs(e1.dot(np));
|
//if (twist < t)
|
twist += t;
|
t = Math.abs(e2.dot(np));
|
//if (twist < t)
|
twist += t;
|
t = Math.abs(e3.dot(nq));
|
//if (twist < t)
|
twist += t;
|
}
|
else
|
{
|
double weight = 0;
|
|
double dot = np.dot(nq);
|
dot = Math.pow(1 - dot*dot,0.5); // /(1 + dot);
|
// dot *= Math.pow(r1.length(), 0.5);
|
|
if (weight < dot)
|
weight = dot;
|
|
dot = np.dot(nr);
|
dot = Math.pow(1 - dot*dot,0.5); // /(1 + dot);
|
// dot *= Math.pow(r2.length(), 0.5);
|
|
if (weight < dot)
|
weight = dot;
|
|
dot = nq.dot(nr);
|
dot = Math.pow(1 - dot*dot,0.5); // /(1 + dot);
|
// dot *= Math.pow(r3.length(), 0.5);
|
|
if (weight < dot)
|
weight = dot;
|
|
double delta = (MaxAngle(p,q,r) - MinAngle(p,q,r))/Math.PI;
|
//return weight; // * (delta + 0.5); // * Perimeter(p,q,r);
|
|
e1.cross(r1, r2);
|
e1.normalize();
|
|
e2.set(np);
|
e2.add(nq);
|
e2.add(nr);
|
e2.normalize();
|
|
dot = Math.abs(e1.dot(e2));
|
// if(dot <= 0)
|
// assert(dot > 0);
|
return 1/dot - 0.75; // Math.pow(1 - dot, 0.25);
|
}
|
|
double dispersion = PerimeterMax(p.norm, q.norm, r.norm);
|
//return /*Math.sqrt*/(PerimeterMax2(p, q, r))*
|
// dispersion; // *dispersion;
|
//return twist; // * Perimeter(f);
|
return dispersion;
|
}
|
|
double PerimeterMax2(Face f)
|
{
|
return PerimeterMax2(vertices.get(f.p).norm, vertices.get(f.q).norm, vertices.get(f.r).norm);
|
}
|
|
double Area(Face f)
|
{
|
return Area(vertices.get(f.p), vertices.get(f.q), vertices.get(f.r));
|
}
|
|
double Distance(cVector a, cVector b)
|
{
|
double dx = b.x - a.x;
|
double dy = b.y - a.y;
|
double dz = b.z - a.z;
|
|
return /*Math.sqrt*/(dx*dx + dy*dy + dz*dz);
|
}
|
|
double Scattering(Face f)
|
{
|
r1.set(vertices.get(f.q));
|
r1.sub(vertices.get(f.p));
|
r2.set(vertices.get(f.r));
|
r2.sub(vertices.get(f.p));
|
|
r3.cross(e1, e2); // triangle normal
|
r3.normalize();
|
|
double scattering = 0;
|
|
scattering += Distance(r3,vertices.get(f.p).norm);
|
scattering += Distance(r3,vertices.get(f.q).norm);
|
scattering += Distance(r3,vertices.get(f.r).norm);
|
|
return PerimeterMax(vertices.get(f.p).norm, vertices.get(f.q).norm, vertices.get(f.r).norm);
|
// return scattering;
|
}
|
|
double PerimeterDelta(Face f)
|
{
|
return PerimeterDelta(vertices.get(f.p).norm, vertices.get(f.q).norm, vertices.get(f.r).norm);
|
// return scattering;
|
}
|
|
double Area(cVector p, cVector q, cVector r)
|
{
|
r1.set(q);
|
r1.sub(p);
|
r2.set(r);
|
r2.sub(p);
|
|
r3.cross(r1, r2);
|
|
return Math.sqrt(r3.dot(r3))/2;
|
}
|
|
double MinAngle(cVector p, cVector q, cVector r)
|
{
|
r1.set(q);
|
r1.sub(p);
|
r2.set(r);
|
r2.sub(p);
|
r3.set(r);
|
r3.sub(q);
|
|
r1.normalize();
|
r2.normalize();
|
r3.normalize();
|
|
double minangle = Math.acos(r1.dot(r2));
|
double angle = Math.acos(-r1.dot(r3));
|
double other = Math.acos(r2.dot(r3));
|
|
double test = minangle + angle + other;
|
|
// if ((float)test != (float) Math.PI);
|
// assert((float)test == (float) Math.PI);
|
|
if (minangle > angle)
|
minangle = angle;
|
if (minangle > other)
|
minangle = other;
|
|
return minangle;
|
}
|
|
double MaxAngle(cVector p, cVector q, cVector r)
|
{
|
r1.set(q);
|
r1.sub(p);
|
r2.set(r);
|
r2.sub(p);
|
r3.set(r);
|
r3.sub(q);
|
|
r1.normalize();
|
r2.normalize();
|
r3.normalize();
|
|
double maxangle = Math.acos(r1.dot(r2));
|
double angle = Math.acos(-r1.dot(r3));
|
double other = Math.acos(r2.dot(r3));
|
|
double test = maxangle + angle + other;
|
|
// if ((float)test != (float) Math.PI);
|
// assert((float)test == (float) Math.PI);
|
|
if (maxangle < angle)
|
maxangle = angle;
|
if (maxangle < other)
|
maxangle = other;
|
|
return maxangle;
|
}
|
|
double Volume(cVector p, cVector q, cVector r)
|
{
|
e3.cross(p, q);
|
|
return r.dot(e3);
|
}
|
|
int FaceCount(int index)
|
{
|
Vector<Face> vf = links.get(index);
|
|
return vf.size();
|
}
|
|
boolean ValidValence(int index)
|
{
|
int i = FaceCount(index); // vf.size();
|
|
boolean invalidvertex = i > 10; // june 2014 8; // i != 4 && i != 6 && i != 8;
|
|
//if (remove3valence)
|
// invalidvertex &= i != 3;
|
|
return !invalidvertex;
|
}
|
|
boolean Boundary(int index)
|
{
|
Vertex v = vertices.get(index);
|
|
int cachedb = v.boundary;
|
if (v.boundary != -1)
|
return v.boundary == 1;
|
|
v.boundary = 0;
|
|
Vector<Face> vf = links.get(index);
|
|
int i = FaceCount(index); // vf.size();
|
|
//boolean invalidvertex = i != 4 && i != 6 && i != 8;
|
|
//if (remove3valence)
|
// invalidvertex &= i != 3;
|
|
//if (invalidvertex) // i > 10)
|
//{
|
// v.boundary = 1;
|
//}
|
//else
|
{
|
for (;--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
boolean atleastonep = false;
|
boolean atleastoneq = false;
|
boolean atleastoner = false;
|
|
for (int j = vf.size();--j>=0;)
|
{
|
if (i == j)
|
continue;
|
|
Face f2 = vf.get(j);
|
|
if (f.p == f2.p || f.p == f2.q || f.p == f2.r)
|
atleastonep = true;
|
if (f.q == f2.p || f.q == f2.q || f.q == f2.r)
|
atleastoneq = true;
|
if (f.r == f2.p || f.r == f2.q || f.r == f2.r)
|
atleastoner = true;
|
}
|
|
if (!atleastonep || !atleastoneq || !atleastoner)
|
{
|
v.boundary = 1;
|
break;
|
}
|
}
|
|
/**
|
double a = 0;
|
|
cVector o=null,x=null,y=null;
|
|
//for (Face f : v)
|
for (;--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f.p == index)
|
{
|
o = (cVector)vertices.get(f.p);
|
x = (cVector)vertices.get(f.q);
|
y = (cVector)vertices.get(f.r);
|
}
|
if (f.q == index)
|
{
|
o = (cVector)vertices.get(f.q);
|
x = (cVector)vertices.get(f.r);
|
y = (cVector)vertices.get(f.p);
|
}
|
if (f.r == index)
|
{
|
o = (cVector)vertices.get(f.r);
|
x = (cVector)vertices.get(f.p);
|
y = (cVector)vertices.get(f.q);
|
}
|
|
e1.set(x.x-o.x, x.y-o.y, x.z-o.z);
|
e2.set(y.x-o.x, y.y-o.y, y.z-o.z);
|
|
// projection
|
cVector normal = ((Vertex)o).norm;
|
double dot = e1.dot(normal);
|
p1.set(normal);
|
p1.mul(-dot);
|
e1.add(p1);
|
dot = e2.dot(normal);
|
p1.set(normal);
|
p1.mul(-dot);
|
e2.add(p1);
|
|
e3.cross(e1, e2);
|
|
double sin = e3.length();
|
double cos = e1.dot(e2);
|
|
a += Math.atan2(sin, cos);
|
}
|
|
if (a < 1.9 * Math.PI) // BOUNDARY !!
|
v.boundary = 1;
|
/**/
|
}
|
|
assert(cachedb == -1 || cachedb == v.boundary);
|
|
return v.boundary == 1;
|
}
|
|
boolean ValidValence(Face face)
|
{
|
int countp = FaceCount(face.p);
|
int countq = FaceCount(face.q);
|
int countr = FaceCount(face.r);
|
|
return (countp-2 + countq-2 + countr-2 - 3 <= 12); // june 2014 11);
|
}
|
|
boolean Boundary(Face face)
|
{
|
|
// int countp = FaceCount(face.p);
|
// int countq = FaceCount(face.q);
|
// int countr = FaceCount(face.r);
|
|
// if (countp-2 + countq-2 + countr-2 - 3 > 11)
|
// return true;
|
|
int cachedb = face.boundary;
|
|
if (face.boundary != -1)
|
return face.boundary == 1;
|
|
int bcount = 0;
|
|
if (Boundary(face.p))
|
bcount += 1;
|
if (Boundary(face.q))
|
bcount += 1;
|
if (Boundary(face.r))
|
bcount += 1;
|
|
if (bcount >= 1) // 2
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
|
Vertex p = GetVertex(face.p);
|
Vertex q = GetVertex(face.q);
|
Vertex r = GetVertex(face.r);
|
|
// float eps = 0.1f;
|
|
// if (Math.abs(qv.s - pv.s) > eps || Math.abs(qv.t - pv.t) > eps ||
|
// Math.abs(rv.s - pv.s) > eps || Math.abs(rv.t - pv.t) > eps)
|
// {
|
// return true;
|
// }
|
|
if (p.s == 0 || p.s == 1)
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
if (q.s == 0 || q.s == 1)
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
if (r.s == 0 || r.s == 1)
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
if (p.t == 0 || p.t == 1)
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
if (q.t == 0 || q.t == 1)
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
if (r.t == 0 || r.t == 1)
|
{
|
assert(cachedb == -1 || cachedb == 1);
|
return (face.boundary = 1) == 1;
|
}
|
|
// June 2019
|
if (true)
|
return (face.boundary = 0) == 1;
|
|
// reverse triangle test
|
q1.set(p);
|
q2.set(q);
|
q3.set(r);
|
|
p1.set(p);
|
p1.add(q);
|
p1.add(r);
|
p1.mul(1./3);
|
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
p.set(p1);
|
q.set(p1);
|
r.set(p1);
|
|
boolean discard = false;
|
|
Vector<Face> vf = links.get(face.p);
|
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.q || f.q == face.q || f.r == face.q ||
|
f.p == face.r || f.q == face.r || f.r == face.r)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex qp = GetVertex(f.q);
|
Vertex rp = GetVertex(f.r);
|
|
// if (MinAngle(pp,qp,rp) < Math.PI/16)
|
// {
|
// discard = true;
|
// break;
|
// }
|
if (MaxAngle(pp,qp,rp) > Math.PI*7/8)
|
{
|
discard = true;
|
break;
|
}
|
|
e1.set(qp);
|
e1.sub(pp);
|
e2.set(rp);
|
e2.sub(pp);
|
|
p3.cross(e1, e2); // triangle normal
|
p3.normalize();
|
|
if (p3.dot(e3) < 0)
|
{
|
discard = true;
|
break;
|
}
|
}
|
|
vf = links.get(face.q);
|
|
if (!discard)
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.p || f.q == face.p || f.r == face.p ||
|
f.p == face.r || f.q == face.r || f.r == face.r)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex qp = GetVertex(f.q);
|
Vertex rp = GetVertex(f.r);
|
|
// if (MinAngle(pp,qp,rp) < Math.PI/16)
|
// {
|
// discard = true;
|
// break;
|
// }
|
if (MaxAngle(pp,qp,rp) > Math.PI*7/8)
|
{
|
discard = true;
|
break;
|
}
|
|
e1.set(qp);
|
e1.sub(pp);
|
e2.set(rp);
|
e2.sub(pp);
|
|
p3.cross(e1, e2); // triangle normal
|
p3.normalize();
|
|
if (p3.dot(e3) < 0)
|
{
|
discard = true;
|
break;
|
}
|
}
|
|
vf = links.get(face.r);
|
|
if (!discard)
|
for (int i=vf.size();--i>=0;)
|
{
|
Face f = vf.get(i);
|
|
if (f == face)
|
continue;
|
|
if (f.p == face.p || f.q == face.p || f.r == face.p ||
|
f.p == face.q || f.q == face.q || f.r == face.q)
|
continue;
|
|
Vertex pp = GetVertex(f.p);
|
Vertex qp = GetVertex(f.q);
|
Vertex rp = GetVertex(f.r);
|
|
// if (MinAngle(pp,qp,rp) < Math.PI/16)
|
// {
|
// discard = true;
|
// break;
|
// }
|
if (MaxAngle(pp,qp,rp) > Math.PI*7/8)
|
{
|
discard = true;
|
break;
|
}
|
|
e1.set(qp);
|
e1.sub(pp);
|
e2.set(rp);
|
e2.sub(pp);
|
|
p3.cross(e1, e2); // triangle normal
|
p3.normalize();
|
|
if (p3.dot(e3) < 0)
|
{
|
discard = true;
|
break;
|
}
|
}
|
|
p.set(q1);
|
q.set(q2);
|
r.set(q3);
|
|
if (discard)
|
face.boundary = 1;
|
else
|
face.boundary = 0;
|
|
//System.out.println("#Vertex = " + VertexCount());
|
//System.out.println("#Face = " + FaceCount());
|
if (!(cachedb == -1 || cachedb == face.boundary))
|
assert(cachedb == -1 || cachedb == face.boundary);
|
|
return face.boundary == 1;
|
}
|
|
void Invariants()
|
{
|
for (int i=faces.size(); --i>=0;)
|
{
|
Face face = (Face) faces.get(i);
|
|
assert(face.weight <= 10000);
|
assert(leafweights || nbbadfaces == 0);
|
// assert(face.weight > 0);
|
// if (Boundary(face))
|
// continue;
|
|
Vertex p = (Vertex)vertices.get(face.p);
|
Vertex q = (Vertex)vertices.get(face.q);
|
Vertex r = (Vertex)vertices.get(face.r);
|
|
/*
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
e3.normalize();
|
|
if (p.norm.dot(e3) < -0.5)
|
assert(p.norm.dot(e3) > -0.5);
|
if (q.norm.dot(e3) < -0.5)
|
assert(q.norm.dot(e3) > -0.5);
|
if (r.norm.dot(e3) < -0.5)
|
assert(r.norm.dot(e3) > -0.5);
|
*/
|
|
|
}
|
}
|
|
boolean RemoveOneVertex() throws Exception
|
{
|
// if (trimmed || faces.size() == 0)
|
// return false;
|
|
InitLinks(false); // nbbadfaces < 128);
|
|
boolean atleastone = false;
|
|
// remove one 4-valence vertex
|
for (int i=vertices.size(); --i>=0;)
|
{
|
Vector<Face> vfaces = links.get(i);
|
|
if (vfaces.size() != 4)
|
continue;
|
|
if (Boundary(i))
|
continue;
|
|
Face f0 = vfaces.get(0);
|
Face f1 = vfaces.get(1);
|
Face f2 = vfaces.get(2);
|
Face f3 = vfaces.get(3);
|
|
if (!Valid(f0))
|
{
|
continue;
|
}
|
if (!Valid(f1))
|
{
|
continue;
|
}
|
if (!Valid(f2))
|
{
|
continue;
|
}
|
if (!Valid(f3))
|
{
|
continue;
|
}
|
|
assert(f0.contains(i));
|
assert(f1.contains(i));
|
assert(f2.contains(i));
|
assert(f3.contains(i));
|
|
// when r is the "center", p is along the boundary
|
while (f0.r != i)
|
{
|
int t = f0.p;
|
f0.p = f0.q;
|
f0.q = f0.r;
|
f0.r = t;
|
}
|
|
while (f1.r != i)
|
{
|
int t = f1.p;
|
f1.p = f1.q;
|
f1.q = f1.r;
|
f1.r = t;
|
}
|
|
while (f2.r != i)
|
{
|
int t = f2.p;
|
f2.p = f2.q;
|
f2.q = f2.r;
|
f2.r = t;
|
}
|
|
while (f3.r != i)
|
{
|
int t = f3.p;
|
f3.p = f3.q;
|
f3.q = f3.r;
|
f3.r = t;
|
}
|
|
// make f0 the lowest triangle
|
double miny = vertices.get(f0.p).y;
|
|
if (miny > vertices.get(f1.p).y)
|
{
|
miny = vertices.get(f1.p).y;
|
Face t = f0;
|
f0 = f1;
|
f1 = t;
|
}
|
if (miny > vertices.get(f2.p).y)
|
{
|
miny = vertices.get(f2.p).y;
|
Face t = f0;
|
f0 = f2;
|
f2 = t;
|
}
|
if (miny > vertices.get(f3.p).y)
|
{
|
miny = vertices.get(f3.p).y;
|
Face t = f0;
|
f0 = f3;
|
f3 = t;
|
}
|
|
int va = f0.q;
|
int vb = f0.r;
|
int vc = -1;
|
|
Face toremove1 = null;
|
Face toremove2 = null;
|
|
// f0 is the buffer for the first new triangle,
|
// and otherf is the other upper one.
|
Face otherf = null;
|
|
if (f1.contains(f0.p))
|
{
|
if (f1.p == f0.p)
|
{
|
assert(false);
|
f0.r = f1.q;
|
}
|
else
|
{
|
assert(f1.q == f0.p);
|
vc = f1.p;
|
}
|
|
otherf = f2;
|
toremove1 = f1;
|
toremove2 = f3;
|
}
|
else
|
if (f2.contains(f0.p))
|
{
|
if (f2.p == f0.p)
|
{
|
assert(false);
|
f0.r = f2.q;
|
}
|
else
|
{
|
assert(f2.q == f0.p);
|
vc = f2.p;
|
}
|
|
otherf = f3;
|
toremove1 = f1;
|
toremove2 = f2;
|
}
|
if (f3.contains(f0.p))
|
{
|
if (f3.p == f0.p)
|
{
|
// assert(false);
|
new Exception().printStackTrace();
|
f0.r = f3.q;
|
}
|
else
|
{
|
assert(f3.q == f0.p);
|
vc = f3.p;
|
}
|
|
otherf = f1;
|
toremove1 = f2;
|
toremove2 = f3;
|
}
|
|
vertextemp.set(vertices.get(va));
|
vertextemp.sub(vertices.get(vb));
|
vertextemp.normalize();
|
vertextemp2.set(vertices.get(vc));
|
vertextemp2.sub(vertices.get(vb));
|
vertextemp2.normalize();
|
|
if (vertextemp.dot(vertextemp2) > -0.95)
|
{
|
continue;
|
}
|
|
atleastone = true;
|
|
f0.r = vc;
|
|
faces.remove(toremove1);
|
faces.remove(toremove2);
|
|
if (!f0.contains(otherf.p))
|
{
|
otherf.r = otherf.p;
|
}
|
else
|
if (!f0.contains(otherf.q))
|
{
|
otherf.r = otherf.q;
|
}
|
|
otherf.p = f0.r;
|
otherf.q = f0.q;
|
|
otherf.good = 0;
|
otherf.boundary = 0;
|
otherf.nbiterations = 0;
|
|
f0.good = 0;
|
f0.boundary = -1;
|
f0.nbiterations += 1;
|
|
TouchVertex(f0.p, false);
|
TouchVertex(f0.q, false);
|
TouchVertex(f0.r, false);
|
TouchVertex(otherf.p, false);
|
TouchVertex(otherf.q, false);
|
TouchVertex(otherf.r, false);
|
|
//vertices.remove(i);
|
//links.remove(i);
|
//break;
|
}
|
|
return atleastone;
|
}
|
|
static int iterationcount = 0;
|
|
boolean RemoveOneTriangle() throws Exception
|
{
|
if (trimmed || faces.size() == 0)
|
return false;
|
|
if (true) // nbbadfaces > faces.size()/8)
|
{
|
//if (
|
InitLinks(//!veryfirst))
|
nbbadfaces < 128); // faces.size()/8);
|
//InitWeights();
|
}
|
|
int chosen = ChooseTriangle(true); // Best is slow and not really better
|
|
if (chosen == -1)
|
{
|
if (nbbadfaces == 0)
|
return false;
|
else
|
{
|
//System.exit(0);
|
remove3valence = true;
|
InitLinks(false);
|
//remove3valence = false;
|
// InitWeights();
|
|
chosen = ChooseTriangle(true);
|
}
|
}
|
|
if (chosen == -1)
|
return false;
|
|
// Invariants();
|
|
// if (iterationcount > 0)
|
return RemoveTriangle(chosen);
|
|
//?
|
// Invariants();
|
// june 2014 return true;
|
}
|
|
int stackdepth = 0;
|
int rotatecount = 0;
|
|
double THRESHOLD;
|
|
void TestFace(int p, int q, int r)
|
{
|
// try
|
// {
|
// AddFace(p,q,r);
|
// }
|
// catch(Exception e)
|
// {
|
// e.printStackTrace();
|
// return;
|
// }
|
|
stackdepth++;
|
rotatecount++;
|
|
rotatecount %= 3;
|
|
// if (stackdepth > 50)
|
// {
|
// stackdepth--;
|
// return;
|
// }
|
|
switch(rotatecount)
|
{
|
case 2: int t = p; p = q; q = r; r = t;
|
case 1: int u = p; p = q; q = r; r = u;
|
case 0:
|
}
|
|
Vertex vp = (Vertex)vertices.get(p);
|
Vertex vq = (Vertex)vertices.get(q);
|
Vertex vr = (Vertex)vertices.get(r);
|
|
vect.set(vp);
|
vect.sub(vq);
|
|
double length2pq = vect.length2();
|
|
vect.set(vr);
|
vect.sub(vq);
|
|
double length2qr = vect.length2();
|
|
vect.set(vp);
|
vect.sub(vr);
|
|
double length2rp = vect.length2();
|
|
double seuil = THRESHOLD;
|
|
if (length2pq > seuil*seuil && length2pq >= length2qr && length2pq >= length2rp)
|
{
|
// split PQ
|
vert.set(vp);
|
vert.add(vq);
|
vert.mul(0.5);
|
vert.norm.set(vp.norm);
|
vert.norm.add(vq.norm);
|
vert.norm.normalize();
|
|
vert.s = (vp.s + vq.s)/2;
|
vert.t = (vp.t + vq.t)/2;
|
|
int newindex = AddTableVertex(vert);
|
|
TestFace(p,newindex,r);
|
TestFace(newindex,q,r);
|
}
|
else
|
if (length2qr > seuil*seuil && length2qr >= length2pq && length2qr >= length2rp)
|
{
|
// split QR
|
vert.set(vr);
|
vert.add(vq);
|
vert.mul(0.5);
|
vert.norm.set(vr.norm);
|
vert.norm.add(vq.norm);
|
vert.norm.normalize();
|
|
vert.s = (vr.s + vq.s)/2;
|
vert.t = (vr.t + vq.t)/2;
|
|
int newindex = AddTableVertex(vert);
|
|
TestFace(p,q,newindex);
|
TestFace(p,newindex,r);
|
}
|
else
|
if (length2rp > seuil*seuil && length2rp >= length2pq && length2rp >= length2qr)
|
{
|
// split RP
|
vert.set(vp);
|
vert.add(vr);
|
vert.mul(0.5);
|
vert.norm.set(vp.norm);
|
vert.norm.add(vr.norm);
|
vert.norm.normalize();
|
|
vert.s = (vp.s + vr.s)/2;
|
vert.t = (vp.t + vr.t)/2;
|
|
int newindex = AddTableVertex(vert);
|
|
TestFace(p,q,newindex);
|
TestFace(newindex,q,r);
|
}
|
else
|
AddFace(p,q,r);
|
|
stackdepth--;
|
}
|
|
void IncreaseMesh()
|
{
|
// if (stripified)
|
Trim();
|
Untrim();
|
|
BoundaryRep tmp = new BoundaryRep(); // (BoundaryRep) GrafreeD.clone(this);
|
|
double minx = Float.POSITIVE_INFINITY;
|
double maxx = Float.NEGATIVE_INFINITY;
|
double miny = Float.POSITIVE_INFINITY;
|
double maxy = Float.NEGATIVE_INFINITY;
|
double minz = Float.POSITIVE_INFINITY;
|
double maxz = Float.NEGATIVE_INFINITY;
|
|
for (int i=0; i<VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
int index = tmp.AddTableVertex(v);
|
|
assert(index == i);
|
|
if (minx > v.x)
|
minx = v.x;
|
if (miny > v.y)
|
miny = v.y;
|
if (minz > v.z)
|
minz = v.z;
|
if (maxx < v.x)
|
maxx = v.x;
|
if (maxy < v.y)
|
maxy = v.y;
|
if (maxz < v.z)
|
maxz = v.z;
|
}
|
|
double max = maxx - minx;
|
|
if (max < maxy - miny)
|
max = maxy - miny;
|
if (max < maxz - minz)
|
max = maxz - minz;
|
|
tmp.THRESHOLD = 0.5; // max/25; // 50;
|
|
tmp.faces.clear();
|
|
for (int i=FaceCount(); --i>=0;)
|
{
|
Face face = GetFace(i);
|
|
tmp.TestFace(face.p,face.q,face.r);
|
|
// Vertex vert = new Vertex(true);
|
//
|
// vert.norm.x = n[count3];
|
// vert.norm.y = n[count3+1];
|
// vert.norm.z = n[count3+2];
|
//
|
// vert.s = uv[count2];
|
// vert.t = uv[count2+1];
|
//
|
// //System.out.println("vertex1 = " + v[count3] + ", " + v[count3+1] + ", " + v[count3+2]);
|
// vert.x = v[count3];
|
// vert.y = v[count3+1];
|
// vert.z = v[count3+2];
|
//
|
// int index1 = AddTableVertex(vert);
|
|
|
}
|
|
tmp./*mar 2013*/vertextable.clear(); // = tmp.vertextable;
|
|
// faces = tmp.faces;
|
// vertices = tmp.vertices;
|
Set(tmp);
|
}
|
|
void ClipMesh(Object3D clip, double[][] toRoot)
|
{
|
// if (stripified)
|
// Trim(); // je deviens fou...
|
// Untrim();
|
if (stripified)
|
Unstripify();
|
|
BoundaryRep tmp = new BoundaryRep();
|
|
boolean untransform = true;
|
|
for (int i=0; i<VertexCount(); i++)
|
{
|
Vertex v = GetVertex(i);
|
|
v.valid = -1;
|
|
temp1.set(v);
|
LA.xformPos(temp1, toRoot, temp1);
|
|
if (clip.inside(temp1.x, temp1.y, temp1.z, untransform))
|
{
|
int index = tmp.AddTableVertex(v);
|
v.valid = index;
|
}
|
}
|
|
tmp.faces.clear();
|
|
for (int i=FaceCount(); --i>=0;)
|
{
|
Face face = GetFace(i);
|
|
int indexp = GetVertex(face.p).valid;
|
|
if (indexp == -1)
|
continue;
|
|
int indexq = GetVertex(face.q).valid;
|
|
if (indexq == -1)
|
continue;
|
|
int indexr = GetVertex(face.r).valid;
|
|
if (indexr == -1)
|
continue;
|
|
tmp.AddFace(indexp,indexq,indexr);
|
}
|
|
tmp./*mar 2013*/vertextable.clear(); // = tmp.vertextable;
|
|
// faces = tmp.faces;
|
// vertices = tmp.vertices;
|
Set(tmp);
|
}
|
|
// boolean lock;
|
|
boolean SplitInTwo(boolean reduction34, boolean onlyone)
|
{
|
if (stripified)
|
{
|
// sept 2013
|
//return; // Can't untrim the thing...
|
Unstripify(); // may 2014
|
}
|
|
if (e1 == null)
|
{
|
e1 = new cVector();
|
e2 = new cVector();
|
e3 = new cVector();
|
p1 = new cVector();
|
p2 = new cVector();
|
p3 = new cVector();
|
q1 = new cVector();
|
q2 = new cVector();
|
q3 = new cVector();
|
r1 = new cVector();
|
r2 = new cVector();
|
r3 = new cVector();
|
s1 = new cVector();
|
s2 = new cVector();
|
s3 = new cVector();
|
}
|
|
Globals.theRenderer.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
|
|
try
|
{
|
Untrim();
|
} catch (Exception e)
|
{
|
System.err.println("EXCEPTION CAUGHT");
|
e.printStackTrace();
|
return false;
|
} catch (Error e)
|
{
|
System.err.println("ERROR CAUGHT");
|
e.printStackTrace();
|
return false;
|
}
|
|
System.out.println("# faces = " + faces.size());
|
System.out.println("# vertices = " + vertices.size());
|
|
for (int i=0; i<faces.size(); i++)
|
{
|
Face face = (Face) faces.get(i);
|
|
face.used = false;
|
face.nbiterations = 1;
|
face.weight = -1;
|
face.boundary = -1;
|
|
// while(lock)
|
// {
|
// try
|
// {
|
// Thread.sleep(1);
|
// }
|
// catch (Exception e)
|
// {
|
// }
|
// }
|
|
if (face.p == face.q || face.q == face.r || face.r == face.p)
|
{
|
faces.remove(i--);
|
}
|
else
|
{
|
/**/
|
Vertex p = (Vertex)vertices.get(face.p);
|
Vertex q = (Vertex)vertices.get(face.q);
|
Vertex r = (Vertex)vertices.get(face.r);
|
|
p.boundary = -1;
|
q.boundary = -1;
|
r.boundary = -1;
|
|
e1.set(q);
|
e1.sub(p);
|
e2.set(r);
|
e2.sub(p);
|
|
e3.cross(e1, e2); // triangle normal
|
if (!e3.normalize())
|
faces.remove(i--);
|
// july 2014 else if (p.norm.dot(e3) < -0.5)
|
// faces.remove(i--);
|
// else if (q.norm.dot(e3) < -0.5)
|
// faces.remove(i--);
|
// else if (r.norm.dot(e3) < -0.5)
|
// faces.remove(i--);
|
/**/
|
}
|
}
|
|
nbbadfaces = faces.size();
|
//remove3valence = true;
|
|
int count = 2;
|
|
if (onlyone)
|
count = 1;
|
|
firstpass = true;
|
|
int n = faces.size();
|
int v = vertices.size();
|
|
for (int i=0; i<v; i++)
|
{
|
vertices.get(i).valid = -1;
|
}
|
|
for (int i=0; i<n/1000; i++)
|
{
|
System.out.print('.');
|
}
|
System.out.println();
|
boolean atleastone = false;
|
int i = 0;
|
while (true) // reduction34 || faces.size() > n/2)
|
{
|
if (i++%100 == 0)
|
{
|
Globals.theRenderer.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
|
System.out.println("#faces = " + faces.size());
|
// if (i != 1)
|
// break;
|
}
|
try
|
{
|
// if (i > iterationcount)
|
// break;
|
if (reduction34)
|
{
|
if (!RemoveOneVertex())
|
break;
|
}
|
else
|
{
|
if (!RemoveOneTriangle())
|
break;
|
|
atleastone = true;
|
}
|
// if (iterationcount == 0)
|
// break;
|
}
|
catch (Exception e)
|
{
|
e.printStackTrace();
|
break;
|
}
|
firstpass = false;
|
// if (--count<0 && !reduction34)
|
// break; // one triangle only
|
}
|
|
InitLinks(false); // for further display
|
|
iterationcount++;
|
|
System.out.println();
|
|
System.out.println("# faces = " + n + "; downto " + faces.size());
|
System.out.println("# vertices = " + v + "; downto " + vertices.size());
|
|
//Trim(true,cJME.gennormals,true,false); // doesn't work
|
Trim(true,false,false,false,false);
|
|
Globals.theRenderer.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
|
|
return atleastone;
|
}
|
|
void UpdateIndices(Face face, Face minface)
|
{
|
if (face == minface)
|
return;
|
|
if (face.p == minface.p || face.p == minface.q || face.p == minface.r)
|
{
|
face.p = minface.p;
|
//if (leafweights)
|
face.good = 0; // false;
|
face.used = true;
|
}
|
if (face.q == minface.p || face.q == minface.q || face.q == minface.r)
|
{
|
face.q = minface.p;
|
//if (leafweights)
|
face.good = 0; // false;
|
face.used = true;
|
}
|
if (face.r == minface.p || face.r == minface.q || face.r == minface.r)
|
{
|
face.r = minface.p;
|
//if (leafweights)
|
face.good = 0; // false;
|
face.used = true;
|
}
|
|
if (face.p >/*=*/ minface.q && face.p < minface.r)
|
face.p -= 1;
|
if (face.q >/*=*/ minface.q && face.q < minface.r)
|
face.q -= 1;
|
if (face.r >/*=*/ minface.q && face.r < minface.r)
|
face.r -= 1;
|
if (face.p >/*=*/ minface.r)
|
face.p -= 2;
|
if (face.q >/*=*/ minface.r)
|
face.q -= 2;
|
if (face.r >/*=*/ minface.r)
|
face.r -= 2;
|
}
|
|
transient Vector<Face> tempfaces;
|
|
static boolean leafweights = false; // true;
|
static boolean neighbors = true; // true means "preventive"
|
|
boolean RemoveTriangle(int chosen)
|
{
|
// while(lock)
|
// {
|
// try
|
// {
|
// Thread.sleep(1);
|
// }
|
// catch (Exception e)
|
// {
|
// }
|
// }
|
|
Face minface = (Face) faces.get(chosen);
|
|
double minfaceweight = minface.weight; // FaceWeight(minface);
|
|
// if (minfaceweight <= 0)
|
// assert(minfaceweight > 0);
|
|
//System.out.println("minfaceweight = " + minfaceweight);
|
//if (false)
|
if (minfaceweight > 0.01)
|
{
|
System.out.println("minfaceweight = " + minfaceweight);
|
|
return false;
|
}
|
|
// for (int i=0; i<faces.size(); i++)
|
for (int v=0; v<3; v++)
|
{
|
int vert = minface.p;
|
if (v == 1)
|
vert = minface.q;
|
if (v == 2)
|
vert = minface.r;
|
// Face face = (Face) faces.get(i);
|
Vector<Face> vertfaces = links.get(vert);
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
|
// if (face.weight == 10000)
|
// continue;
|
|
if (face.p == minface.p || face.q == minface.p || face.r == minface.p ||
|
face.p == minface.q || face.q == minface.q || face.r == minface.q ||
|
face.p == minface.r || face.q == minface.r || face.r == minface.r)
|
{
|
if (!leafweights)
|
{
|
// if(minfaceweight <= 0)
|
// assert(minfaceweight > 0);
|
//
|
// //FaceWeight(face);
|
// if(face.weight < 0)
|
// assert(face.weight >= 0);
|
|
face.weight += minfaceweight;
|
|
// if (face.weight >= 10000)
|
// assert(face.weight < 10000);
|
}
|
else
|
face.weight = -1;
|
|
face.nbiterations += 1;
|
face.boundary = -1;
|
|
Vertex p = (Vertex)vertices.get(face.p);
|
Vertex q = (Vertex)vertices.get(face.q);
|
Vertex r = (Vertex)vertices.get(face.r);
|
|
p.boundary = -1;
|
q.boundary = -1;
|
r.boundary = -1;
|
}
|
else
|
assert(false);
|
}
|
}
|
|
// TouchVertex(minface.p);
|
// TouchVertex(minface.q);
|
// TouchVertex(minface.r);
|
|
//assert (minface.p != minface.q);
|
//assert (minface.p != minface.r);
|
//assert (minface.q != minface.r);
|
|
/*
|
int minindex = minface.p;
|
|
if (minindex > minface.q)
|
minindex = minface.q;
|
if (minindex > minface.r)
|
minindex = minface.r;
|
*/
|
|
boolean loop = true;
|
for(;loop;)
|
{
|
loop = false;
|
if (minface.p > minface.q)
|
{
|
int t = minface.q;
|
minface.q = minface.p;
|
minface.p = t;
|
loop = true;
|
}
|
if (minface.p > minface.r)
|
{
|
int t = minface.r;
|
minface.r = minface.p;
|
minface.p = t;
|
loop = true;
|
}
|
if (minface.q > minface.r)
|
{
|
int t = minface.q;
|
minface.q = minface.r;
|
minface.r = t;
|
loop = true;
|
}
|
}
|
|
if (true)
|
{
|
if (false)
|
{
|
for (int v=0; v<3; v++)
|
{
|
int vert = minface.p;
|
if (v == 1)
|
vert = minface.q;
|
if (v == 2)
|
vert = minface.r;
|
|
Vector<Face> vertfaces = links.get(vert);
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
|
UpdateIndices(face, minface);
|
}
|
}
|
}
|
else
|
{
|
for (int i=0; i<faces.size(); i++)
|
{
|
// if (i == chosen)
|
// continue;
|
|
Face face = (Face) faces.get(i);
|
|
UpdateIndices(face, minface);
|
}
|
}
|
}
|
else
|
{
|
if (tempfaces == null)
|
tempfaces = new Vector<Face>();
|
else
|
tempfaces.clear();
|
|
Vector<Face> vertfaces = links.get(minface.p);
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
|
UpdateIndices(face, minface);
|
|
tempfaces.add(face);
|
}
|
|
vertfaces = links.get(minface.q);
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
|
if (tempfaces.contains(face))
|
continue;
|
|
UpdateIndices(face, minface);
|
|
tempfaces.add(face);
|
}
|
|
vertfaces = links.get(minface.r);
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
|
if (tempfaces.contains(face))
|
continue;
|
|
UpdateIndices(face, minface);
|
|
tempfaces.add(face);
|
}
|
}
|
|
// new vertex
|
Vertex p = (Vertex)vertices.get(minface.p);
|
Vertex q = (Vertex)vertices.get(minface.q);
|
Vertex r = (Vertex)vertices.get(minface.r);
|
|
e1.set(p);
|
e1.add(r);
|
e1.add(q);
|
e1.mul(1.0/3);
|
|
p.set(e1);
|
|
e1.set(p.norm);
|
e1.add(r.norm);
|
e1.add(q.norm);
|
e1.normalize();
|
|
p.norm.set(e1);
|
|
p.s = (p.s + q.s + r.s)/3;
|
p.t = (p.t + q.t + r.t)/3;
|
|
// p.AO = minface.weight;
|
|
vertices.remove(minface.r);
|
links.remove(minface.r);
|
if (minface.r < minface.q)
|
{
|
assert(false);
|
vertices.remove(minface.q-1);
|
links.remove(minface.q-1);
|
}
|
else
|
{
|
vertices.remove(minface.q);
|
links.remove(minface.q);
|
}
|
|
//TouchVertex(minface.p);
|
//TouchVertex(minface.q);
|
//TouchVertex(minface.r);
|
|
minface.q = minface.r = minface.p;
|
|
int count = 0;
|
|
for (int i=0; i<faces.size(); i++)
|
{
|
Face face = (Face) faces.get(i);
|
|
if (face.p == face.q || face.q == face.r || face.r == face.p)
|
{
|
TouchVertex(face.p, true); // , minface.weight);
|
TouchVertex(face.q, true); // , minface.weight);
|
TouchVertex(face.r, true); // , minface.weight);
|
// assert(!lock);
|
faces.remove(i--);
|
count++;
|
if (count == 4)
|
break;
|
}
|
}
|
|
return true;
|
}
|
|
void TouchVertex(int index, boolean clear) // , double weight)
|
{
|
vertices.get(index).valid = -1;
|
vertices.get(index).boundary = -1;
|
Vector<Face> vertfaces = links.get(index);
|
if (vertfaces == null)
|
return; // already done
|
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
face.used = true;
|
face.good = 0; // false;
|
if (leafweights)
|
face.weight = -1;
|
face.boundary = -1;
|
// face.weight += weight;
|
|
// Vertex p = (Vertex)vertices.get(face.p);
|
// Vertex q = (Vertex)vertices.get(face.q);
|
// Vertex r = (Vertex)vertices.get(face.r);
|
|
// p.boundary = -1;
|
// q.boundary = -1;
|
// r.boundary = -1;
|
}
|
|
// if (clear)
|
// links.setElementAt(null, index); // june 2014
|
}
|
|
boolean ValidVertex(int index)
|
{
|
Vertex v = vertices.get(index);
|
if (v.valid == -1)
|
{
|
v.valid = 1;
|
|
Vector<Face> vertfaces = links.get(index);
|
for (int i=vertfaces.size(); --i>=0;)
|
{
|
Face face = (Face) vertfaces.get(i);
|
if (face.good == 0)
|
{
|
v.valid = 0;
|
break;
|
}
|
}
|
}
|
|
return v.valid == 1;
|
}
|
|
void Untrim() // throws Exception
|
{
|
if (!trimmed)
|
return;
|
|
Grafreed.linkUV = false;
|
|
try
|
{
|
maxIndexV = 0;
|
|
vertices = new Vector();
|
faces = new Vector();
|
|
if (!stripified)
|
{
|
vertextable = new Hashtable();
|
int facecount = FaceCount();
|
|
for (int i = 0; i < facecount; i++)
|
{
|
trimmed = true;
|
Face face = GetFace(i);
|
|
Vertex pv = GetVertex(face.p);
|
Vertex qv = GetVertex(face.q);
|
Vertex rv = GetVertex(face.r);
|
|
trimmed = false;
|
int index1 = AddTableVertex(pv);
|
int index2 = AddTableVertex(qv);
|
int index3 = AddTableVertex(rv);
|
|
AddFace(index1,index2,index3);
|
}
|
|
triangles = null;
|
colors = null;
|
normals = null;
|
uvmap = null;
|
positions = null;
|
return;
|
}
|
|
float[] v = getRawVertices();
|
float[] n = getRawNormals();
|
float[] c = getRawColors();
|
float[] uv = getRawUVMap();
|
|
int[] strips = getRawIndices();
|
|
trimmed = false;
|
|
// june 2013 triangles = null;
|
|
colors = null;
|
normals = null;
|
uvmap = null;
|
|
vertextable = new Hashtable();
|
|
// june 2013 stripified = false;
|
|
int count = 0;
|
|
for (int i = 0; i < strips.length; i++)
|
{
|
count += strips[i];
|
}
|
|
indices = new int[count];
|
|
int count2 = 0;
|
int count3 = 0;
|
|
if (n.length > 0)
|
{
|
count = 0;
|
|
for (int i = 0; i < strips.length; i++)
|
{
|
Vertex vert = new Vertex(true);
|
|
vert.norm.x = n[count3];
|
vert.norm.y = n[count3+1];
|
vert.norm.z = n[count3+2];
|
|
vert.s = uv[count2];
|
vert.t = uv[count2+1];
|
|
//System.out.println("vertex1 = " + v[count3] + ", " + v[count3+1] + ", " + v[count3+2]);
|
vert.x = v[count3];
|
vert.y = v[count3+1];
|
vert.z = v[count3+2];
|
|
int index1 = AddTableVertex(vert);
|
|
indices[count++] = index1;
|
|
count2 += 2;
|
count3 += 3;
|
|
//vert = new Vertex(true);
|
|
vert.index = -1;
|
|
vert.norm.x = n[count3];
|
vert.norm.y = n[count3+1];
|
vert.norm.z = n[count3+2];
|
|
vert.s = uv[count2];
|
vert.t = uv[count2+1];
|
|
//System.out.println("vertex1 = " + v[count3] + ", " + v[count3+1] + ", " + v[count3+2]);
|
vert.x = v[count3];
|
vert.y = v[count3+1];
|
vert.z = v[count3+2];
|
|
int index2 = AddTableVertex(vert);
|
|
indices[count++] = index2;
|
|
count2 += 2;
|
count3 += 3;
|
|
for (int j = 0; j < strips[i] - 2; j++)
|
{
|
//vert = new Vertex(true);
|
vert.index = -1;
|
|
vert.norm.x = n[count3];
|
vert.norm.y = n[count3+1];
|
vert.norm.z = n[count3+2];
|
|
vert.s = uv[count2];
|
vert.t = uv[count2+1];
|
|
//System.out.println("vertex1 = " + v[count3] + ", " + v[count3+1] + ", " + v[count3+2]);
|
vert.x = v[count3];
|
vert.y = v[count3+1];
|
vert.z = v[count3+2];
|
|
int index3 = AddTableVertex(vert);
|
|
indices[count++] = index3;
|
|
count2 += 2;
|
count3 += 3;
|
|
// june 2013 if (j%2 == 0)
|
// AddFace(index1,index2,index3);
|
// else
|
// AddFace(index1,index3,index2);
|
|
if (true) // j%2 == 0)
|
{
|
index1 = index2;
|
index2 = index3;
|
}
|
else
|
{
|
index1 = index3;
|
index2 = index2;
|
}
|
}
|
}
|
}
|
|
positions = null;
|
|
assert count3 == v.length;
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
|
}
|
|
int AddTableVertex(Vertex vert)
|
{
|
Vertex in = GetCache(vert);
|
if (in == null)
|
{
|
vert.index = -1;
|
return Remember(new Vertex(vert));
|
}
|
else
|
{
|
//AddVertex(in);
|
return in.index;
|
}
|
}
|
|
void InitVertexTable()
|
{
|
// jan 2014 if (vertextable != null && !vertextable.isEmpty())
|
// return; // already done
|
|
vertextable = new Hashtable();
|
|
for (int i = VertexCount(); --i>=0;)
|
{
|
Vertex v = GetVertex(i);
|
|
vertextable.put(v, v);
|
}
|
}
|
|
public String toString()
|
{
|
//return "trim = " + trimmed + "; stripped = " + stripified + "; AOdone = " + AOdone + "; colors = " + colors;
|
return "trim = " + trimmed +
|
"; stripped = " + stripified +
|
"; colors = " + colors +
|
"; faces = " + (faces!=null?faces.size():null) +
|
"; triangles = " + (triangles!=null?triangles.length:null) +
|
((indices==null)?"":"; indices = " + indices.length);
|
}
|
|
boolean trimmed = false;
|
boolean stripified = false;
|
transient boolean AOdone = false;
|
/*transient*/ int countV = 0, countF = 0;
|
/*transient*/ int maxIndexV = 0;
|
/*transient*/ int bufV, bufF;
|
// Raw version
|
//private
|
float[] positions;
|
//private
|
float[] normals;
|
float[] colors;
|
private float[] uvmap;
|
private int[] triangles;
|
int[] indices; // for stripify not trimmed
|
|
// Linked version
|
/*private*/ Vector<Vertex> vertices; // class Vertex
|
/*private*/ Vector<Face> faces; // class Face
|
|
// rag doll support
|
int[] startvertices;
|
float[] averagepoints;
|
float[] extremepoints;
|
float[] supportminsize; // distance of closest point
|
float[] supportmaxsize; // distance of fartest point
|
|
transient Hashtable vertextable;
|
/*transient*/ private Vertex[] verticesCopy;
|
|
transient Vector<Vector<Face>> links; // list of triangles for each index
|
transient boolean firstpass;
|
//transient int[] indices;
|
//transient int[] offsets;
|
transient cVector e1; // = new cVector();
|
transient cVector e2; // = new cVector();
|
transient cVector e3; // = new cVector();
|
transient cVector p1; // = new cVector();
|
transient cVector p2; // = new cVector();
|
transient cVector p3; // = new cVector();
|
transient cVector q1; // = new cVector();
|
transient cVector q2; // = new cVector();
|
transient cVector q3; // = new cVector();
|
transient cVector r1; // = new cVector();
|
transient cVector r2; // = new cVector();
|
transient cVector r3; // = new cVector();
|
transient cVector s1; // = new cVector();
|
transient cVector s2; // = new cVector();
|
transient cVector s3; // = new cVector();
|
}
|