public Section(float[] points, int[] tri, int xyz, float value, Vector3 maxVer, Vector3 minVer) { //xyz截面方向,value截面值 direction = xyz; sectionValue = value; vMax = maxVer; vMin = minVer; if (vMax.x - vMin.x > vMax.y - vMin.y) { if (vMax.x - vMin.x > vMax.z - vMin.z) { Max = vMax.x; Min = vMin.x; } else { Max = vMax.z; Min = vMin.z; } } else { if (vMax.y - vMin.y > vMax.z - vMin.z) { Max = vMax.y; Min = vMin.y; } else { Max = vMax.z; Min = vMin.z; } } int pointNum = points.Length / 3; int triNum = tri.Length / 3; //int[] mark = new int[pointNum * pointNum]; List <long> mark = new List <long>(); List <int> n0 = new List <int>(); List <int> n1 = new List <int>(); List <float> frac = new List <float>(); List <Vector2> v2 = new List <Vector2>(); List <Vector3> v3 = new List <Vector3>(); int[] pointIndex = new int[] { 0, 1, 1, 2, 2, 0 }; int ni0 = 0, ni1 = 0; float f = 0; for (int i = 0; i < triNum; ++i) { for (int pointIndexI = 0; pointIndexI < 3; ++pointIndexI) { int triPoint0 = tri[3 * i + pointIndex[2 * pointIndexI]]; int triPoint1 = tri[3 * i + pointIndex[2 * pointIndexI + 1]]; bool isSection = false; if (points[3 * triPoint0 + xyz] < value) { if (points[3 * triPoint1 + xyz] > value) { ni0 = triPoint0; ni1 = triPoint1; f = (value - points[3 * ni0 + xyz]) / (points[3 * ni1 + xyz] - points[3 * ni0 + xyz]); isSection = true; } else if (points[3 * triPoint1 + xyz] == value) { ni0 = triPoint1; ni1 = triPoint1; f = 0; isSection = true; } } else if (points[3 * triPoint0 + xyz] > value) { if (points[3 * triPoint1 + xyz] < value) { ni0 = triPoint1; ni1 = triPoint0; f = (value - points[3 * ni0 + xyz]) / (points[3 * ni1 + xyz] - points[3 * ni0 + xyz]); isSection = true; } else if (points[3 * triPoint1 + xyz] == value) { ni0 = triPoint1; ni1 = triPoint1; f = 0; isSection = true; } } else if (points[3 * triPoint0 + xyz] == value) { if (points[3 * triPoint1 + xyz] < value) { ni0 = triPoint0; ni1 = triPoint0; f = 0; isSection = true; } else if (points[3 * triPoint1 + xyz] > value) { ni0 = triPoint0; ni1 = triPoint0; f = 0; isSection = true; } } if (isSection && !mark.Contains(ni0 * pointNum + ni1)) { n0.Add(ni0); n1.Add(ni1); frac.Add(f); float xx, yy; switch (xyz) { case 0: xx = points[3 * ni0 + 1] + f * (points[3 * ni1 + 1] - points[3 * ni0 + 1]); yy = points[3 * ni0 + 2] + f * (points[3 * ni1 + 2] - points[3 * ni0 + 2]); v2.Add(new Vector2(xx, yy)); v3.Add(new Vector3(10 * (value - vMin.x) / (Max - Min) - 5 , 5 - 10 * (xx - vMin.y) / (Max - Min), 10 * (yy - vMin.z) / (Max - Min) - 5)); break; case 1: xx = points[3 * ni0] + f * (points[3 * ni1] - points[3 * ni0]); yy = points[3 * ni0 + 2] + f * (points[3 * ni1 + 2] - points[3 * ni0 + 2]); v2.Add(new Vector2(xx, yy)); v3.Add(new Vector3(10 * (xx - vMin.x) / (Max - Min) - 5 , 5 - 10 * (value - vMin.y) / (Max - Min), 10 * (yy - vMin.z) / (Max - Min) - 5)); break; case 2: xx = points[3 * ni0] + f * (points[3 * ni1] - points[3 * ni0]); yy = points[3 * ni0 + 1] + f * (points[3 * ni1 + 1] - points[3 * ni0 + 1]); v2.Add(new Vector2(xx, yy)); v3.Add(new Vector3(10 * (xx - vMin.x) / (Max - Min) - 5 , 5 - 10 * (yy - vMin.y) / (Max - Min), 10 * (value - vMin.z) / (Max - Min) - 5)); break; } mark.Add(ni0 * pointNum + ni1); } } } node0 = n0.ToArray(); node1 = n1.ToArray(); nodeNum = node0.Length; fraction = frac.ToArray(); vertices = v3.ToArray(); // Delaunay 三角剖分 DelaunayTriangulation delaunayTriangulation = null; DelaunayCalculator delaunayCalculator = new DelaunayCalculator(); if (vertices.Length > 0) { delaunayCalculator.CalculateTriangulation(v2, ref delaunayTriangulation); triangles = delaunayTriangulation.Triangles.ToArray(); } }
public VolumeticMesh2D generateMesh() { var mesh = new VolumeticMesh2D(); Mesh rawMesh = GetComponent <MeshFilter>().mesh; var vertices = rawMesh.vertices; foreach (var vertex in vertices) { mesh.nodes.Add(new Vector2(vertex.x, vertex.y)); } var calculator = new GK.DelaunayCalculator(); var result = calculator.CalculateTriangulation(mesh.nodes); var triangles = result.Triangles; for (int i = 0; i < triangles.Count; i += 3) { var edgeA = new Edge2D(triangles[i], triangles[i + 2]); var edgeB = new Edge2D(triangles[i + 2], triangles[i + 1]); var edgeC = new Edge2D(triangles[i + 1], triangles[i]); int edgeIndexA, edgeIndexB, edgeIndexC; if (!mesh.edges.Contains(edgeA)) { mesh.edges.Add(edgeA); edgeIndexA = mesh.edges.Count - 1; } else { edgeIndexA = mesh.edges.FindIndex(edge => edge == edgeA); } if (!mesh.edges.Contains(edgeB)) { mesh.edges.Add(edgeB); edgeIndexB = mesh.edges.Count - 1; } else { edgeIndexB = mesh.edges.FindIndex(edge => edge == edgeB); } if (!mesh.edges.Contains(edgeC)) { mesh.edges.Add(edgeC); edgeIndexC = mesh.edges.Count - 1; } else { edgeIndexC = mesh.edges.FindIndex(edge => edge == edgeC); } mesh.nodeJointIndexes.Add(new TriangleNodes2D(triangles[i], triangles[i + 2], triangles[i + 1])); mesh.edgeJointIndexes.Add(new TriangleEdges2D(edgeIndexA, edgeIndexB, edgeIndexC)); } return(mesh); }
/// <summary> /// Create new Voronoi calculator. /// </summary> public VoronoiCalculator() { pts = new List <PointTriangle>(); delCalc = new DelaunayCalculator(); cmp = new PTComparer(); }
//subdivide our suburb into blocks public void GenerateBlocks(float spacing, float deviation = 0, float alignmentRotation = 0) { //set our seed for the suburb Random.State currentRNGState = Random.state; Random.InitState(seed); float minX = float.MaxValue, maxX = float.MinValue, minY = float.MaxValue, maxY = float.MinValue; Vector2 rotationPivot = new Vector2(0, 0); List <Vector2> shrunkBorders = new List <Vector2>(borders); List <Vector2> sites = new List <Vector2>(); // shrink our borders so our points arnt created to close to the edge, this will result in blocks that are to small shrunkBorders = CityTest.Shrink(shrunkBorders, spacing / 2); if (shrunkBorders.Count >= 3) { for (int i = 0; i < shrunkBorders.Count; i++)//find anchorPoint { if (shrunkBorders[i].x < rotationPivot.x) { rotationPivot.x = shrunkBorders[i].x; } if (shrunkBorders[i].y < rotationPivot.y) { rotationPivot.y = shrunkBorders[i].y; } } //find rotate boarders for alignment and find bounding volume for (int i = 0; i < shrunkBorders.Count; i++) { shrunkBorders[i] = shrunkBorders[i].RotateAroundPoint(rotationPivot, alignmentRotation);// Vector2.MoveTowards(shrunkBorders[i].RotateAroundPoint(rotationPivot, alignmentRotation), borderCenter, spacing/2);// spacing/2); if (shrunkBorders[i].x > maxX) { maxX = shrunkBorders[i].x; } else if (shrunkBorders[i].x < minX) { minX = shrunkBorders[i].x; } if (shrunkBorders[i].y > maxY) { maxY = shrunkBorders[i].y; } else if (shrunkBorders[i].y < minY) { minY = shrunkBorders[i].y; } } //triangulate out polygon so we can check if created points are within our poly GK.DelaunayTriangulation triangulation = new GK.DelaunayCalculator().CalculateTriangulation(shrunkBorders); float xCenterOffset = ((maxX - minX) % spacing) / 2; float yCenterOffset = ((maxY - minY) % spacing) / 2; for (float x = minX - xCenterOffset; x < maxX; x += spacing) { for (float y = minY - yCenterOffset; y < maxY; y += spacing) { Vector2 newPoint = new Vector2(x + Random.Range(-deviation, deviation), y + Random.Range(-deviation, deviation)); // generate a points i a grid for (int i = 0; i < triangulation.Triangles.Count; i += 3) // if the point is contained within our polygon { if (GK.Geom.PointInTriangle(newPoint, triangulation.Vertices[triangulation.Triangles[i]], triangulation.Vertices[triangulation.Triangles[i + 1]], triangulation.Vertices[triangulation.Triangles[i + 2]])) { Vector2 rotatedPoint = newPoint.RotateAroundPoint(rotationPivot, -alignmentRotation); sites.Add(rotatedPoint);// rotate our aligned point to its original rotation and add it to the block site list break; } } } } } if (sites.Count >= 3) // we can only create a diagram if we have more then 2 verts { GK.VoronoiDiagram blockVoronoiDiagram = new GK.VoronoiCalculator().CalculateDiagram(sites); // generate our streets and blocks in our suburb for (int i = 0; i < blockVoronoiDiagram.Sites.Count; i++) { List <Vector2> clippedSite = null; if (blockVoronoiDiagram.FirstEdgeBySite.Count > 0) ////THIS IS NEEDED BECAUSE THE DIAGRAM CAN BE INVALID SOMETIMES { new GK.VoronoiClipper().ClipSite(blockVoronoiDiagram, borders, i, ref clippedSite); // clip our block by our suburb if (clippedSite.Count > 0) { Block newBlock = new Block();// create and assign the block newBlock.borders = new List <Vector2>(clippedSite); newBlock.parentSuburb = this; newBlock.seed = Random.Range(int.MinValue, int.MaxValue); newBlock.blockPosition = blockVoronoiDiagram.Sites[i]; newBlock.thisBlock = new GameObject("Block"); newBlock.thisBlock.transform.SetParent(thisSuburb.transform); newBlock.thisBlock.transform.localPosition = new Vector3(newBlock.blockPosition.x, 0, newBlock.blockPosition.y); myBlocks.Add(newBlock); } else { Debug.LogError("SUBURB SITE AFTER CLIPPED WASNT VALID"); } } else////THIS IS NEEDED BECAUSE THE DIAGRAM CAN BE INVALID SOMETIMES if its not valid make the entire subrb a block { Debug.LogWarning("SITE COULTNT BE CREATED BECASUE DIAGRAM DOESNT HAVE STARTING EDGES"); Block newBlock = new Block(); newBlock.borders = new List <Vector2>(borders); newBlock.parentSuburb = this; newBlock.seed = Random.Range(int.MinValue, int.MaxValue); newBlock.blockPosition = sitePosition; newBlock.thisBlock = new GameObject("Block"); newBlock.thisBlock.transform.SetParent(thisSuburb.transform); newBlock.thisBlock.transform.localPosition = new Vector3(newBlock.blockPosition.x, 0, newBlock.blockPosition.y); myBlocks.Add(newBlock); break; } } } else// if the suburb has less then 3 verts it cant be split so we make the entire suburb a block { Block newBlock = new Block(); newBlock.borders = new List <Vector2>(borders); newBlock.parentSuburb = this; newBlock.seed = Random.Range(int.MinValue, int.MaxValue); newBlock.blockPosition = sitePosition; newBlock.thisBlock = new GameObject("Block"); newBlock.thisBlock.transform.SetParent(thisSuburb.transform); newBlock.thisBlock.transform.localPosition = new Vector3(newBlock.blockPosition.x, 0, newBlock.blockPosition.y); myBlocks.Add(newBlock); } Random.state = currentRNGState; }