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 = -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) Grafreed.clone(other.vertices); faces = (Vector) 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 = 3; // 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 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 tableBase = new java.util.HashMap(); // // // for (int i=0; i table = new java.util.HashMap(); for (int i=0; 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 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 used = new Vector(); cVector e1 = new cVector(); for (int i=0; i 0.001) continue; */ float w = 0; // face.weight; int count = 0; used.clear(); Vector 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=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 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 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 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 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 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 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 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 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 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 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=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 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 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 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 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(); else tempfaces.clear(); Vector 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 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 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 = " + indices; } 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 vertices; // class Vertex /*private*/ Vector 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> 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(); }