public void DisplayMeshMain(HalfEdgeData2 meshData, Normalizer2 normalizer) { //UnNormalize and to 3d HalfEdgeData3 meshDataUnNormalized_3d = new HalfEdgeData3(); //We dont want to modify the original data //HalfEdgeData2 meshDataUnNormalized = normalizer.UnNormalize(meshData); HashSet <HalfEdgeFace2> faces_2d = meshData.faces; foreach (HalfEdgeFace2 f in faces_2d) { MyVector2 p1 = f.edge.v.position; MyVector2 p2 = f.edge.nextEdge.v.position; MyVector2 p3 = f.edge.nextEdge.nextEdge.v.position; p1 = normalizer.UnNormalize(p1); p2 = normalizer.UnNormalize(p2); p3 = normalizer.UnNormalize(p3); meshDataUnNormalized_3d.AddTriangle(p1.ToMyVector3_Yis3D(), p2.ToMyVector3_Yis3D(), p3.ToMyVector3_Yis3D()); } this.meshData = meshDataUnNormalized_3d.faces; DisplayMesh(meshDataUnNormalized_3d.faces, displayMeshHere); //Normalize again //meshData = normalizer.Normalize(meshDataUnNormalized); }
private IEnumerator GenerateHull(HashSet <MyVector3> points, HalfEdgeData3 convexHull) { //PAUSE FOR VISUALIZATION //Display what we have so far controller.DisplayMeshMain(convexHull.faces); controller.HideAllVisiblePoints(convexHull.verts); yield return(new WaitForSeconds(10f)); //Add all other points one-by-one List <MyVector3> pointsToAdd = new List <MyVector3>(points); foreach (MyVector3 p in pointsToAdd) { //Is this point within the tetrahedron bool isWithinHull = _Intersections.PointWithinConvexHull(p, convexHull); if (isWithinHull) { points.Remove(p); controller.HideVisiblePoint(p); continue; } //PAUSE FOR VISUALIZATION //Display active point controller.DisplayActivePoint(p); //Rotate camera to this point //Important to turn this vector to 2d Vector3 unity_pos = controller.normalizer.UnNormalize(p).ToVector3(); controller.cameraScript.SetWantedHeight(unity_pos.y); unity_pos.y = 0f; controller.cameraScript.SetWantedDirection((Vector3.zero - unity_pos).normalized); yield return(new WaitForSeconds(2f)); //Find visible triangles and edges on the border between the visible and invisible triangles HashSet <HalfEdgeFace3> visibleTriangles = null; HashSet <HalfEdge3> borderEdges = null; IterativeHullAlgorithm3D.FindVisibleTrianglesAndBorderEdgesFromPoint(p, convexHull, out visibleTriangles, out borderEdges); //Remove all visible triangles foreach (HalfEdgeFace3 triangle in visibleTriangles) { convexHull.DeleteFace(triangle); } //PAUSE FOR VISUALIZATION //For visualization purposes we now need to create two meshes and then remove the triangles again controller.DisplayMeshMain(convexHull.faces); controller.DisplayMeshOther(visibleTriangles); controller.HideAllVisiblePoints(convexHull.verts); yield return(new WaitForSeconds(2f)); //PAUSE FOR VISUALIZATION //Remove all now visible triangles that forms the hole List <HalfEdgeFace3> visibleTrianglesList = new List <HalfEdgeFace3>(visibleTriangles); for (int i = 0; i < visibleTrianglesList.Count; i++) { visibleTriangles.Remove(visibleTrianglesList[i]); controller.DisplayMeshOther(visibleTriangles); yield return(new WaitForSeconds(0.5f)); } //Save all ned edges so we can connect them with an opposite edge //To make it faster you can use the ideas in the Valve paper to get a sorted list of newEdges HashSet <HalfEdge3> newEdges = new HashSet <HalfEdge3>(); foreach (HalfEdge3 borderEdge in borderEdges) { //Each edge is point TO a vertex MyVector3 p1 = borderEdge.prevEdge.v.position; MyVector3 p2 = borderEdge.v.position; //The border edge belongs to a triangle which is invisible //Because triangles are oriented clockwise, we have to add the vertices in the other direction //to build a new triangle with the point HalfEdgeFace3 newTriangle = convexHull.AddTriangle(p2, p1, p); //PAUSE FOR VISUALIZATION controller.DisplayMeshMain(convexHull.faces); yield return(new WaitForSeconds(0.5f)); //Connect the new triangle with the opposite edge on the border //When we create the face we give it a reference edge which goes to p2 //So the edge we want to connect is the next edge HalfEdge3 edgeToConnect = newTriangle.edge.nextEdge; edgeToConnect.oppositeEdge = borderEdge; borderEdge.oppositeEdge = edgeToConnect; //Two edges are still not connected, so save those HalfEdge3 e1 = newTriangle.edge; //HalfEdge3 e2 = newTriangle.edge.nextEdge; HalfEdge3 e3 = newTriangle.edge.nextEdge.nextEdge; newEdges.Add(e1); //newEdges.Add(e2); newEdges.Add(e3); } //Two edges in each triangle are still not connected with an opposite edge foreach (HalfEdge3 e in newEdges) { if (e.oppositeEdge != null) { continue; } convexHull.TryFindOppositeEdge(e, newEdges); } //PAUSE FOR VISUALIZATION //controller.DisplayMeshMain(convexHull.faces); //yield return new WaitForSeconds(2f); controller.HideVisiblePoint(p); } controller.HideActivePoint(); controller.cameraScript.SetWantedDirection(Vector3.zero); controller.cameraScript.SetWantedHeight(0f); //controller.DisplayMeshMain(convexHull.faces); //yield return new WaitForSeconds(5f); yield return(null); }
// // Add the constraints to the delaunay triangulation // //timer is for debugging private IEnumerator AddConstraints(HalfEdgeData2 triangleData, List <MyVector2> constraints, bool shouldRemoveTriangles, Normalizer2 normalizer, System.Diagnostics.Stopwatch timer = null) { //Validate the data if (constraints == null) { yield return(null); } // // PAUSE AND VISUALIZE // //Show the constraint with a line mesh HashSet <Triangle2> lineTriangles = _GenerateMesh.ConnectedLineSegments(constraints, width: 0.01f, isConnected: true); //UnNormalized and to half-edge 3 (also move each vertex up a little or will intersect with the underlying mesh) HalfEdgeData3 lineData = new HalfEdgeData3(); foreach (Triangle2 t in lineTriangles) { MyVector2 p1 = t.p1; MyVector2 p2 = t.p2; MyVector2 p3 = t.p3; p1 = normalizer.UnNormalize(p1); p2 = normalizer.UnNormalize(p2); p3 = normalizer.UnNormalize(p3); lineData.AddTriangle(p1.ToMyVector3_Yis3D(0.1f), p2.ToMyVector3_Yis3D(0.1f), p3.ToMyVector3_Yis3D(0.1f)); } visualizeController.DisplayMeshOtherUnNormalized(lineData.faces); yield return(new WaitForSeconds(2f)); //Get a list with all edges //This is faster than first searching for unique edges //The report suggest we should do a triangle walk, but it will not work if the mesh has holes //The mesh has holes because we remove triangles while adding constraints one-by-one //so maybe better to remove triangles after we added all constraints... HashSet <HalfEdge2> edges = triangleData.edges; //The steps numbering is from the report //Step 1. Loop over each constrained edge. For each of these edges, do steps 2-4 for (int i = 0; i < constraints.Count; i++) { //Let each constrained edge be defined by the vertices: MyVector2 c_p1 = constraints[i]; MyVector2 c_p2 = constraints[MathUtility.ClampListIndex(i + 1, constraints.Count)]; //Check if this constraint already exists in the triangulation, //if so we are happy and dont need to worry about this edge //timer.Start(); if (IsEdgeInListOfEdges(edges, c_p1, c_p2)) { continue; } //timer.Stop(); //Step 2. Find all edges in the current triangulation that intersects with this constraint //Is returning unique edges only, so not one edge going in the opposite direction //timer.Start(); Queue <HalfEdge2> intersectingEdges = FindIntersectingEdges_BruteForce(edges, c_p1, c_p2); //timer.Stop(); //Debug.Log("Intersecting edges: " + intersectingEdges.Count); //Step 3. Remove intersecting edges by flipping triangles //This takes 0 seconds so is not bottleneck //timer.Start(); List <HalfEdge2> newEdges = new List <HalfEdge2>(); yield return(StartCoroutine(RemoveIntersectingEdges(c_p1, c_p2, intersectingEdges, newEdges, triangleData, normalizer))); //timer.Stop(); //Step 4. Try to restore delaunay triangulation //Because we have constraints we will never get a delaunay triangulation //This takes 0 seconds so is not bottleneck //timer.Start(); yield return(StartCoroutine(RestoreDelaunayTriangulation(c_p1, c_p2, newEdges, triangleData, normalizer))); //timer.Stop(); } //Step 5. Remove superfluous triangles, such as the triangles "inside" the constraints if (shouldRemoveTriangles) { //timer.Start(); yield return(StartCoroutine(RemoveSuperfluousTriangles(triangleData, constraints, normalizer))); //timer.Stop(); } //return triangleData; // // PAUSE AND VISUALIZE // visualizeController.HideMeshOther(); yield return(new WaitForSeconds(2f)); }