/// <summary> /// Construit une représentation graphique du Diagramme de Voronoi de la triangulation /// </summary> public void BuildVoronoi(WingedEdgeMesh mesh) { List <StandardVertex> lines = new List <StandardVertex>(); // On va commencer par construire les sommets correspondant aux centre des faces de la triangulation // qui sont les noeuds du diagramme de voronoir CleanVoronoi(); for (int i = 0; i < mesh.Faces.Count; i++) { // On récupère le centre de la face (barycentre) List <VertexWE> vertices = mesh.GetFaceVertices(mesh.Faces[i]); Vector3 center = vertices[0].Position + vertices[1].Position + vertices[2].Position; center = center / 3.0f; Troll3D.Entity entity = new Troll3D.Entity(Entity); entity.transform_.SetPosition( center.X, center.Y, 0.0f); entity.transform_.SetScale(0.02f, 0.02f, 1.0f); MaterialDX11 material = new MaterialDX11(); material.SetMainColor(0.0f, 1.0f, 1.0f, 1.0f); MeshRenderer meshrenderer = entity.AddComponent <MeshRenderer>(); meshrenderer.material_ = material; meshrenderer.model_ = Quad.GetMesh(); // On récupère les voisins List <FaceWE> neighbours = mesh.GetFaceNeighbours(mesh.Faces[i]); for (int j = 0; j < neighbours.Count; j++) { // On récupère le centre de la face (barycentre) List <VertexWE> verticesNeighbour = mesh.GetFaceVertices(neighbours[j]); Vector3 centerNeighbour = verticesNeighbour[0].Position + verticesNeighbour[1].Position + verticesNeighbour[2].Position; centerNeighbour = centerNeighbour / 3.0f; lines.Add(new StandardVertex(center)); lines.Add(new StandardVertex(centerNeighbour)); } VoronoiPoints.Add(entity); } if (lines.Count > 0) { (( LineRenderer )VoronoiLines.GetComponent(ComponentType.LineRenderer)).Display = true; (( LineRenderer )VoronoiLines.GetComponent(ComponentType.LineRenderer)).Vertices = lines; (( LineRenderer )VoronoiLines.GetComponent(ComponentType.LineRenderer)).UpdateRenderer(); } }
public void BuildVoronoi(WingedEdgeMesh mesh) { List <StandardVertex> lines = new List <StandardVertex>(); // We start by building the vertices corresponding to the face's center of the triangulation who are node of the Voronoi diagram CleanVoronoi(); for (int i = 0; i < mesh.Faces.Count; i++) { // We get back the face's center (barycentre) List <VertexWE> vertices = mesh.GetFaceVertices(mesh.Faces[i]); Vector3 center = vertices[0].Position + vertices[1].Position + vertices[2].Position; center = center / 3.0f; Troll3D.Entity entity = new Troll3D.Entity(Entity); entity.transform_.SetPosition( center.X, center.Y, 0.0f); entity.transform_.SetScale(0.02f, 0.02f, 1.0f); MaterialDX11 material = new MaterialDX11(); material.SetMainColor(0.0f, 1.0f, 1.0f, 1.0f); MeshRenderer meshrenderer = entity.AddComponent <MeshRenderer>(); meshrenderer.material_ = material; meshrenderer.model_ = Quad.GetMesh(); // We get back the neighbours List <FaceWE> neighbours = mesh.GetFaceNeighbours(mesh.Faces[i]); for (int j = 0; j < neighbours.Count; j++) { // On récupère le centre de la face (barycentre) List <VertexWE> verticesNeighbour = mesh.GetFaceVertices(neighbours[j]); Vector3 centerNeighbour = verticesNeighbour[0].Position + verticesNeighbour[1].Position + verticesNeighbour[2].Position; centerNeighbour = centerNeighbour / 3.0f; lines.Add(new StandardVertex(center)); lines.Add(new StandardVertex(centerNeighbour)); } VoronoiPoints.Add(entity); } if (lines.Count > 0) { (( LineRenderer )VoronoiLines.GetComponent(ComponentType.LineRenderer)).Display = true; (( LineRenderer )VoronoiLines.GetComponent(ComponentType.LineRenderer)).Vertices = lines; (( LineRenderer )VoronoiLines.GetComponent(ComponentType.LineRenderer)).UpdateRenderer(); } }
public void DelaunayIncremental() { List <Entity> p = new List <Entity>(); List <Entity> currentPoints = new List <Entity>(); p.AddRange(Points); WingedEdgeMesh mesh = new WingedEdgeMesh(); // We start by making a first triangle mesh.AddVertex(-2.0f, -1.0f, 0.0f); mesh.AddVertex(-2.0f, 5.0f, 0.0f); mesh.AddVertex(2.0f, -1.0f, 0.0f); mesh.AddFace(mesh.Vertices[0], mesh.Vertices[1], mesh.Vertices[2]); // Now, we're going to triangulate vertex per vertex // We get back 1 vertex from the set of vertices, we look for the triangle containing it, then, // we subdivide it in 3 triangles. We then check that every new triangle is Delaunay. If not, we flip/switchover the // opposite edge of the new vertex while (p.Count > 0) { // We start by extracting a point from the set of vertices Entity point = p[0]; p.RemoveAt(0); FaceWE f = null; int findex = 0; // Looking for the triangle that contains the dot for (int i = 0; i < mesh.Faces.Count; i++) { FaceWE currentFace = mesh.Faces[i]; List <VertexWE> vertices = mesh.GetFaceVertices(currentFace); bool isIn = Troll3D.TRaycast.PointInTriangle(vertices[0].Position, vertices[1].Position, vertices[2].Position, point.transform_.position_); if (isIn) { f = currentFace; findex = i; } } // In theory, we should have get back a triangle that contains the vertex. We're now going to divide that // in 3 triangles using the current vertex List <FaceWE> faces = mesh.AddVertex(f, point.transform_.position_.X, point.transform_.position_.Y, point.transform_.position_.Z); // Now we must check that the triangles we found are Delaunay. Meaning that the // circumscribed circle of the triangle must contains only points of the triangle. // Checking the faces created for (int i = 0; i < faces.Count; i++) { InspectEdge(faces[i].Edges, mesh); } } //Removing mesh thing used for triangulation List <FaceWE> faceToRemove = new List <FaceWE>(); for (int i = mesh.Faces.Count - 1; i >= 0; i--) { if (mesh.IsFaceBorder(mesh.Faces[i])) { faceToRemove.Add(mesh.Faces[i]); } } for (int i = 0; i < faceToRemove.Count; i++) { mesh.RemoveFace(faceToRemove[i]); } for (int i = 0; i < CircleCenter.Count; i++) { Scene.CurrentScene.RemoveRenderable(( MeshRenderer )CircleCenter[i].GetComponent(ComponentType.MeshRenderer)); } if (DisplayCenters) { for (int i = 0; i < Circles.Count; i++) { Scene.CurrentScene.RemoveRenderable(( LineRenderer )Circles[i].GetComponent(ComponentType.LineRenderer)); } CircleCenter.Clear(); for (int i = 0; i < mesh.Faces.Count; i++) { List <VertexWE> vertices = mesh.GetFaceVertices(mesh.Faces[i]); Vector3 circleCenter = GetCircleCenter(vertices[0].Position, vertices[1].Position, vertices[2].Position); float radius = GetCircleRadius(vertices[0].Position, vertices[1].Position, vertices[2].Position, circleCenter); AddCircleCenter(circleCenter.X, circleCenter.Y, radius); } } else { for (int i = 0; i < Circles.Count; i++) { Scene.CurrentScene.RemoveRenderable(( LineRenderer )Circles[i].GetComponent(ComponentType.LineRenderer)); } CircleCenter.Clear(); } if (mesh.MakeMesh() != null) { meshRenderer.model_ = mesh.MakeMesh(); meshRenderer.SetFillMode(SharpDX.Direct3D11.FillMode.Wireframe); meshRenderer.material_.SetMainColor(1.0f, 0.0f, 0.0f, 1.0f); } else { } if (DisplayVoronoi) { BuildVoronoi(mesh); } else { CleanVoronoi(); } }
/// <summary> /// Check an edge and determine if it needs to be change? If yes the function call itself again /// </summary> /// <param name="e"></param> private void InspectEdge(List <EdgeWE> edges, WingedEdgeMesh mesh) { foreach (EdgeWE e in edges) { // Wefirstcheck that the edge connect 2 triangles if (e.LeftFace != null && e.RightFace != null) { List <VertexWE> v1 = mesh.GetFaceVertices(e.LeftFace); List <VertexWE> v2 = mesh.GetFaceVertices(e.RightFace); // We get the opposite side of the left face VertexWE leftOppositeVertex = null; for (int i = 0; i < v1.Count; i++) { if ((v1[i] != e.Vertex1) && (v1[i] != e.Vertex2)) { leftOppositeVertex = v1[i]; } } //We get the opposite side of the right face VertexWE rightOppositeVertex = null; for (int i = 0; i < v2.Count; i++) { if ((v2[i] != e.Vertex1) && (v2[i] != e.Vertex2)) { rightOppositeVertex = v1[i]; } } // We get back informations about the circles from the left and right face Vector3 leftCircleCenter = GetCircleCenter(v1[0].Position, v1[1].Position, v1[2].Position); float leftCircleRadius = GetCircleRadius(v1[0].Position, v1[1].Position, v1[2].Position, leftCircleCenter); Vector3 rightCircleCenter = GetCircleCenter(v2[0].Position, v2[1].Position, v2[2].Position); float rightCircleRadius = GetCircleRadius(v2[0].Position, v2[1].Position, v2[2].Position, rightCircleCenter); // We check if one of the opposite side can fit in the circle of the opposite face if (IsPointInCircle(leftOppositeVertex.Position, rightCircleCenter, rightCircleRadius) || IsPointInCircle(rightOppositeVertex.Position, leftCircleCenter, leftCircleRadius)) { // We switchover the edge List <FaceWE> newfaces = mesh.FlipEdge(e); // We inspect the new edges List <EdgeWE> newEdges = new List <EdgeWE>(); for (int i = 0; i < newfaces.Count; i++) { for (int j = 0; j < newfaces[i].Edges.Count; j++) { if (newEdges.Contains(newfaces[i].Edges[j])) { newEdges.Add(newfaces[i].Edges[j]); } } } InspectEdge(newEdges, mesh); return; } } } return; }
/// <summary> /// Implémentation de l'algorithme de triangulation de Delaunay incremental /// </summary> public void DelaunayIncremental() { List <Entity> p = new List <Entity>(); List <Entity> currentPoints = new List <Entity>(); p.AddRange(Points); WingedEdgeMesh mesh = new WingedEdgeMesh(); // On commence par créer un big triangle capable de contenir tout les autres mesh.AddVertex(-2.0f, -1.0f, 0.0f); mesh.AddVertex(-2.0f, 5.0f, 0.0f); mesh.AddVertex(2.0f, -1.0f, 0.0f); mesh.AddFace(mesh.Vertices[0], mesh.Vertices[1], mesh.Vertices[2]); // Maintenant, on va trianguler point par point // On récupère un point de l'ensemble de point, on cherche le triangle qui le contient, // puis, on subdivise en 3 triangles. On vérifie ensuite que chacun des triangles crée est // Delaunay, si ce n'est pas le cas, on flip l'arrête "opposé" au sommet rajouté while (p.Count > 0) { // On commence par extraire le point Entity point = p[0]; p.RemoveAt(0); FaceWE f = null; int findex = 0; // On cherche le triangle qui contient le point for (int i = 0; i < mesh.Faces.Count; i++) { FaceWE currentFace = mesh.Faces[i]; List <VertexWE> vertices = mesh.GetFaceVertices(currentFace); bool isIn = Troll3D.TRaycast.PointInTriangle(vertices[0].Position, vertices[1].Position, vertices[2].Position, point.transform_.position_); if (isIn) { f = currentFace; findex = i; } } // En théorie, on a récupéré le triangle qui contient le point, on va désormais diviser // ce triangle en 3 en utilisant le point actuel List <FaceWE> faces = mesh.AddVertex(f, point.transform_.position_.X, point.transform_.position_.Y, point.transform_.position_.Z); // Maintenant, on doit vérifier que les triangles obtenus sont delaunay, c'est à dire // que le cercle circonscrit au triangle ne contienne que des points du triangle // On inspecte les faces crées for (int i = 0; i < faces.Count; i++) { InspectEdge(faces[i].Edges, mesh); } } // Je retire les parties du maillage qui sont utilisé pour construire la triangulation List <FaceWE> faceToRemove = new List <FaceWE>(); for (int i = mesh.Faces.Count - 1; i >= 0; i--) { if (mesh.IsFaceBorder(mesh.Faces[i])) { faceToRemove.Add(mesh.Faces[i]); } } for (int i = 0; i < faceToRemove.Count; i++) { mesh.RemoveFace(faceToRemove[i]); } for (int i = 0; i < CircleCenter.Count; i++) { Scene.CurrentScene.RemoveRenderable(( MeshRenderer )CircleCenter[i].GetComponent(ComponentType.MeshRenderer)); } if (DisplayCenters) { for (int i = 0; i < Circles.Count; i++) { Scene.CurrentScene.RemoveRenderable(( LineRenderer )Circles[i].GetComponent(ComponentType.LineRenderer)); } CircleCenter.Clear(); for (int i = 0; i < mesh.Faces.Count; i++) { List <VertexWE> vertices = mesh.GetFaceVertices(mesh.Faces[i]); Vector3 circleCenter = GetCircleCenter(vertices[0].Position, vertices[1].Position, vertices[2].Position); float radius = GetCircleRadius(vertices[0].Position, vertices[1].Position, vertices[2].Position, circleCenter); AddCircleCenter(circleCenter.X, circleCenter.Y, radius); } } else { for (int i = 0; i < Circles.Count; i++) { Scene.CurrentScene.RemoveRenderable(( LineRenderer )Circles[i].GetComponent(ComponentType.LineRenderer)); } CircleCenter.Clear(); } if (mesh.MakeMesh() != null) { meshRenderer.model_ = mesh.MakeMesh(); meshRenderer.SetFillMode(SharpDX.Direct3D11.FillMode.Wireframe); meshRenderer.material_.SetMainColor(1.0f, 0.0f, 0.0f, 1.0f); } else { } if (DisplayVoronoi) { BuildVoronoi(mesh); } else { CleanVoronoi(); } }
/// <summary> /// Inspecte une edge et détermine si un basculement est nécéssaire /// Si un basculement a eu lieu, réinvoque la fonction /// </summary> /// <param name="e"></param> private void InspectEdge(List <EdgeWE> edges, WingedEdgeMesh mesh) { foreach (EdgeWE e in edges) { // On vérifie d'abord que l'arrête relie 2 triangles if (e.LeftFace != null && e.RightFace != null) { List <VertexWE> v1 = mesh.GetFaceVertices(e.LeftFace); List <VertexWE> v2 = mesh.GetFaceVertices(e.RightFace); // Récupère le coté opposé à la face gauche VertexWE leftOppositeVertex = null; for (int i = 0; i < v1.Count; i++) { if ((v1[i] != e.Vertex1) && (v1[i] != e.Vertex2)) { leftOppositeVertex = v1[i]; } } // Récupère le coté opposé à la face droite VertexWE rightOppositeVertex = null; for (int i = 0; i < v2.Count; i++) { if ((v2[i] != e.Vertex1) && (v2[i] != e.Vertex2)) { rightOppositeVertex = v1[i]; } } // On récupère les informations sur les cercle Right et Left Face Vector3 leftCircleCenter = GetCircleCenter(v1[0].Position, v1[1].Position, v1[2].Position); float leftCircleRadius = GetCircleRadius(v1[0].Position, v1[1].Position, v1[2].Position, leftCircleCenter); Vector3 rightCircleCenter = GetCircleCenter(v2[0].Position, v2[1].Position, v2[2].Position); float rightCircleRadius = GetCircleRadius(v2[0].Position, v2[1].Position, v2[2].Position, rightCircleCenter); // On vérifie si un des coté opposé ne rentre pas dans le cercle de la face opposé if (IsPointInCircle(leftOppositeVertex.Position, rightCircleCenter, rightCircleRadius) || IsPointInCircle(rightOppositeVertex.Position, leftCircleCenter, leftCircleRadius)) { // On bascule l'arrête List <FaceWE> newfaces = mesh.FlipEdge(e); // On inspecte les nouvelles arrêtes List <EdgeWE> newEdges = new List <EdgeWE>(); for (int i = 0; i < newfaces.Count; i++) { for (int j = 0; j < newfaces[i].Edges.Count; j++) { if (newEdges.Contains(newfaces[i].Edges[j])) { newEdges.Add(newfaces[i].Edges[j]); } } } InspectEdge(newEdges, mesh); return; } } } return; }