public void Smooth(IMesh mesh, int limit) { var smoothedMesh = (Mesh)mesh; var mesher = new GenericMesher(config); var predicates = config.Predicates(); // The smoother should respect the mesh segment splitting behavior. this.options.SegmentSplitting = smoothedMesh.behavior.NoBisect; // Take a few smoothing rounds (Lloyd's algorithm). for (int i = 0; i < limit; i++) { Step(smoothedMesh, factory, predicates); // Actually, we only want to rebuild, if the mesh is no longer // Delaunay. Flipping edges could be the right choice instead // of re-triangulating... smoothedMesh = (Mesh)mesher.Triangulate(Rebuild(smoothedMesh), options); factory.Reset(); } smoothedMesh.CopyTo((Mesh)mesh); }
public static void ExtrudeText(this MeshBuilder builder, string text, string font, FontStyle fontStyle, FontWeight fontWeight, double fontSize, Vector3D textDirection, Point3D p0, Point3D p1) { var outlineList = GetTextOutlines(text, font, fontStyle, fontWeight, fontSize); // Build the polygon to mesh (using Triangle.NET to triangulate) var polygon = new TriangleNet.Geometry.Polygon(); int marker = 0; foreach (var outlines in outlineList) { var outerOutline = outlines.OrderBy(x => x.AreaOfSegment()).Last(); for (int i = 0; i < outlines.Count; i++) { var outline = outlines[i]; var isHole = i != outlines.Count - 1 && IsPointInPolygon(outerOutline, outline[0]); polygon.AddContour(outline.Select(p => new Vertex(p.X, p.Y)), marker++, isHole); builder.AddExtrudedSegments(outline.ToSegments().ToList(), textDirection, p0, p1); } } var mesher = new GenericMesher(); var options = new ConstraintOptions(); var mesh = mesher.Triangulate(polygon, options); var u = textDirection; u.Normalize(); var z = p1 - p0; z.Normalize(); var v = Vector3D.CrossProduct(z, u); // Convert the triangles foreach (var t in mesh.Triangles) { var v0 = t.GetVertex(0); var v1 = t.GetVertex(1); var v2 = t.GetVertex(2); // Add the top triangle. // Project the X/Y vertices onto a plane defined by textdirection, p0 and p1. builder.AddTriangle(v0.Project(p0, u, v, z, 1), v1.Project(p0, u, v, z, 1), v2.Project(p0, u, v, z, 1)); // Add the bottom triangle. builder.AddTriangle(v2.Project(p0, u, v, z, 0), v1.Project(p0, u, v, z, 0), v0.Project(p0, u, v, z, 0)); } }
public override List <SubdividableEdgeLoop <CityEdge> > GetChildren(SubdividableEdgeLoop <CityEdge> parent) { Vector2[] parentPoints = parent.GetPoints(); Polygon parentPoly = parent.GetPolygon(); //generate points of interest List <RoadDestination> pointsOfInterest = new List <RoadDestination>(); Vector2 centroid = parent.GetCenter(); //parent.EnumerateEdges((EdgeLoopEdge edge) => //{ // pointsOfInterest.Add(new RoadDestination(Vector2.Lerp(edge.a.pt, edge.b.pt, Random.Range(0.2f, 0.8f)), 1, false, true)); //}); Rect bounds = parent.GetBounds(); bounds.width = bounds.width * 2; bounds.height = bounds.height * 2; int potentialRoadPointsRt = Mathf.CeilToInt(Mathf.Sqrt(potentialRoadPoints)); float approxDiameter = Mathf.Sqrt(parentPoly.area); float minimumPerimeterDistance = approxDiameter / 4f; for (int x = 0; x < potentialRoadPointsRt; x++) { for (int y = 0; y < potentialRoadPointsRt; y++) { Vector2 point = new Vector2((x / (float)potentialRoadPointsRt) * bounds.width + bounds.xMin, (y / (float)potentialRoadPointsRt) * bounds.height + bounds.yMin); float distBtwnPts = (bounds.width + bounds.height) / (potentialRoadPoints * 2); point = point + new Vector2(Random.Range(-1f, 1f), Random.Range(-1, 1f)) * distBtwnPts * 3f; if (parentPoly.ContainsPoint(point)) // && parent.DistToPerimeter(point) > minimumPerimeterDistance) { pointsOfInterest.Add(new RoadDestination(point, 0, false, false)); } } } pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(bounds.width * 100, bounds.height * 100), 0, false, false)); pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(bounds.width * 100, -bounds.height * 100), 0, false, false)); pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(-bounds.width * 100, -bounds.height * 100), 0, false, false)); pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(-bounds.width * 100, bounds.height * 100), 0, false, false)); //triangulate points of interest to get potential road segments TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon(); Dictionary <TriangleNet.Geometry.Vertex, RoadDestination> vertexDestMap = new Dictionary <TriangleNet.Geometry.Vertex, RoadDestination>(); foreach (RoadDestination dest in pointsOfInterest) { TriangleNet.Geometry.Vertex vert = new TriangleNet.Geometry.Vertex(dest.point.x, dest.point.y); vertexDestMap.Add(vert, dest); polygon.Add(vert); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; TriangleNet.Meshing.GenericMesher mesher = new TriangleNet.Meshing.GenericMesher(); TriangleNet.Meshing.IMesh mesh = mesher.Triangulate(polygon); TriangleNet.Voronoi.StandardVoronoi voronoi = new TriangleNet.Voronoi.StandardVoronoi((TriangleNet.Mesh)mesh); IEnumerable <TriangleNet.Geometry.IEdge> voronoiEdges = voronoi.Edges; List <TriangleNet.Topology.DCEL.Vertex> voronoiVerts = voronoi.Vertices; List <DividingEdge> dividingEdges = new List <DividingEdge>(); ILinkedGraphEdgeFactory <CityEdge> factory = new CityEdgeFactory(); foreach (TriangleNet.Geometry.IEdge edge in voronoiEdges) { Vector2 a = new Vector2((float)voronoiVerts[edge.P0].X, (float)voronoiVerts[edge.P0].Y); Vector2 b = new Vector2((float)voronoiVerts[edge.P1].X, (float)voronoiVerts[edge.P1].Y); dividingEdges.Add(new DividingEdge(a, b, factory, factoryParams)); } //get vertices as list //ICollection<TriangleNet.Geometry.Vertex> vertices = mesh.Vertices; //TriangleNet.Geometry.Vertex[] vertexList = new TriangleNet.Geometry.Vertex[vertices.Count]; //vertices.CopyTo(vertexList, 0); //IEnumerable<TriangleNet.Geometry.Edge> meshEdges = mesh.Edges; //build a list of dividing edges and pass it to the child collector //foreach (TriangleNet.Geometry.Edge edge in meshEdges) { // //if (vertConnections[edge.P0] > 4) // //{ // // vertConnections[edge.P0]--; // // continue; // //} // //if (vertConnections[edge.P1] > 4) // //{ // // vertConnections[edge.P1]--; // // continue; // //} // Vector2 a = new Vector2((float)vertexList[edge.P0].X, (float)vertexList[edge.P0].Y); // Vector2 b = new Vector2((float)vertexList[edge.P1].X, (float)vertexList[edge.P1].Y); // dividingEdges.Add(new DividingEdge(a, b, factory, CityEdgeType.LandPath)); //} return(CollectChildren(parent, dividingEdges)); }
public static Mesh GetTriangulationMesh(Vector3[] verts, HashSet <int> borderVerts, Polygon boundary) { TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon(); //Dictionary<TriangleNet.Geometry.Vertex, float> vertexElevMap = new Dictionary<TriangleNet.Geometry.Vertex, float>(); foreach (Vector3 vert in verts) { TriangleNet.Geometry.Vertex triangulationVert = new TriangleNet.Geometry.Vertex(vert.x, vert.z); //vertexElevMap.Add(triangulationVert, vert.y); polygon.Add(triangulationVert); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; TriangleNet.Meshing.GenericMesher mesher = new TriangleNet.Meshing.GenericMesher(); TriangleNet.Meshing.IMesh mesh = mesher.Triangulate(polygon); Vector3[] meshVerts = new Vector3[mesh.Vertices.Count]; List <int> meshTriangles = new List <int>(); Dictionary <TriangleNet.Geometry.Vertex, int> vertexIndexMap = new Dictionary <TriangleNet.Geometry.Vertex, int>(); int v = 0; foreach (TriangleNet.Geometry.Vertex triangulatorVert in mesh.Vertices) { meshVerts[v] = new Vector3((float)triangulatorVert.X, verts[v].y, (float)triangulatorVert.Y); vertexIndexMap[triangulatorVert] = v; v++; } //for (int i = 0; i < vertexList.Length; i ++) //{ // TriangleNet.Geometry.Vertex triangulatorVert = vertexList[i]; // meshVerts[i] = new Vector3((float)triangulatorVert.X, vertexElevMap[triangulatorVert], (float)triangulatorVert.Y); // vertexIndexMap[triangulatorVert] = i; //} foreach (TriangleNet.Topology.Triangle tri in mesh.Triangles) { int ind1 = vertexIndexMap[tri.GetVertex(0)]; int ind2 = vertexIndexMap[tri.GetVertex(2)]; int ind3 = vertexIndexMap[tri.GetVertex(1)]; Vector2 center = new Vector2((float)(tri.GetVertex(0).X + tri.GetVertex(1).X + tri.GetVertex(2).X) / 3f, (float)(tri.GetVertex(0).Y + tri.GetVertex(1).Y + tri.GetVertex(2).Y) / 3f); if (!(borderVerts.Contains(ind1) && borderVerts.Contains(ind2) && borderVerts.Contains(ind3)) || (boundary.ContainsPoint(center) && !boundary.PermiterContainsPoint(center))) { meshTriangles.Add(ind1); meshTriangles.Add(ind2); meshTriangles.Add(ind3); } } Mesh unityMesh = new Mesh(); unityMesh.vertices = meshVerts; unityMesh.triangles = meshTriangles.ToArray(); unityMesh.RecalculateBounds(); unityMesh.RecalculateNormals(); return(unityMesh); }