protected void createInitialSimplex() { double max = 0; int imax = 0; for (int i = 0; i < 3; i++) { double diff = maxVtxs[i].pnt.get(i) - minVtxs[i].pnt.get(i); if (diff > max) { max = diff; imax = i; } } if (max <= tolerance) { throw new Exception("Input points appear to be coincident"); } Vertex[] vtx = new Vertex[4]; // set first two vertices to be those with the greatest // one dimensional separation vtx[0] = maxVtxs[imax]; vtx[1] = minVtxs[imax]; // set third vertex to be the vertex farthest from // the line between vtx0 and vtx1 Vector3d u01 = new Vector3d(); Vector3d diff02 = new Vector3d(); Vector3d nrml = new Vector3d(); Vector3d xprod = new Vector3d(); double maxSqr = 0; u01.sub(vtx[1].pnt, vtx[0].pnt); u01.normalize(); for (int i = 0; i < numPoints; i++) { diff02.sub(pointBuffer[i].pnt, vtx[0].pnt); xprod.cross(u01, diff02); double lenSqr = xprod.normSquared(); if (lenSqr > maxSqr && pointBuffer[i] != vtx[0] && // paranoid pointBuffer[i] != vtx[1]) { maxSqr = lenSqr; vtx[2] = pointBuffer[i]; nrml.set(xprod); } } if (Math.Sqrt(maxSqr) <= 100 * tolerance) { throw new Exception("Input points appear to be colinear"); } nrml.normalize(); double maxDist = 0; double d0 = vtx[2].pnt.dot(nrml); for (int i = 0; i < numPoints; i++) { double dist = Math.Abs(pointBuffer[i].pnt.dot(nrml) - d0); if (dist > maxDist && pointBuffer[i] != vtx[0] && // paranoid pointBuffer[i] != vtx[1] && pointBuffer[i] != vtx[2]) { maxDist = dist; vtx[3] = pointBuffer[i]; } } if (Math.Abs(maxDist) <= 100 * tolerance) { throw new Exception("Input points appear to be coplanar"); } Face[] tris = new Face[4]; if (vtx[3].pnt.dot(nrml) - d0 < 0) { tris[0] = Face.createTriangle(vtx[0], vtx[1], vtx[2]); tris[1] = Face.createTriangle(vtx[3], vtx[1], vtx[0]); tris[2] = Face.createTriangle(vtx[3], vtx[2], vtx[1]); tris[3] = Face.createTriangle(vtx[3], vtx[0], vtx[2]); for (int i = 0; i < 3; i++) { int k = (i + 1) % 3; tris[i + 1].getEdge(1).setOpposite(tris[k + 1].getEdge(0)); tris[i + 1].getEdge(2).setOpposite(tris[0].getEdge(k)); } } else { tris[0] = Face.createTriangle(vtx[0], vtx[2], vtx[1]); tris[1] = Face.createTriangle(vtx[3], vtx[0], vtx[1]); tris[2] = Face.createTriangle(vtx[3], vtx[1], vtx[2]); tris[3] = Face.createTriangle(vtx[3], vtx[2], vtx[0]); for (int i = 0; i < 3; i++) { int k = (i + 1) % 3; tris[i + 1].getEdge(0).setOpposite(tris[k + 1].getEdge(1)); tris[i + 1].getEdge(2).setOpposite(tris[0].getEdge((3 - i) % 3)); } } for (int i = 0; i < 4; i++) { faces.Add(tris[i]); } for (int i = 0; i < numPoints; i++) { Vertex v = pointBuffer[i]; if (v == vtx[0] || v == vtx[1] || v == vtx[2] || v == vtx[3]) { continue; } maxDist = tolerance; Face maxFace = null; for (int k = 0; k < 4; k++) { double dist = tris[k].distanceToPlane(v.pnt); if (dist > maxDist) { maxFace = tris[k]; maxDist = dist; } } if (maxFace != null) { addPointToFace(v, maxFace); } } }
private bool doAdjacentMerge(Face face, int mergeType) { HalfEdge hedge = face.he0; bool convex = true; do { Face oppFace = hedge.oppositeFace(); bool merge = false; double dist1, dist2; if (mergeType == NONCONVEX) { // then merge faces if they are definitively non-convex if (oppFaceDistance(hedge) > -tolerance || oppFaceDistance(hedge.opposite) > -tolerance) { merge = true; } } else // mergeType == NONCONVEX_WRT_LARGER_FACE { // merge faces if they are parallel or non-convex // wrt to the larger face; otherwise, just mark // the face non-convex for the second pass. if (face.area > oppFace.area) { if ((dist1 = oppFaceDistance(hedge)) > -tolerance) { merge = true; } else if (oppFaceDistance(hedge.opposite) > -tolerance) { convex = false; } } else { if (oppFaceDistance(hedge.opposite) > -tolerance) { merge = true; } else if (oppFaceDistance(hedge) > -tolerance) { convex = false; } } } if (merge) { if (debug) { Console.WriteLine( " merging " + face.getVertexString() + " and " + oppFace.getVertexString()); } int numd = face.mergeAdjacentFace(hedge, discardedFaces); for (int i = 0; i < numd; i++) { deleteFacePoints(discardedFaces[i], face); } if (debug) { Console.WriteLine( " result: " + face.getVertexString()); } return(true); } hedge = hedge.next; }while (hedge != face.he0); if (!convex) { face.mark = Face.NON_CONVEX; } return(false); }
/** * Constructs a HalfEdge with head vertex <code>v</code> and * left-hand triangular face <code>f</code>. * * @param v head vertex * @param f left-hand triangular face */ public HalfEdge(Vertex v, Face f) { vertex = v; face = f; }