private void DrawFill(List <Vector> fillVertices) { if (m_mesh.Vertices.Count <= 2 || m_mesh.FillMode == FillMode.None || m_mesh.UvMapping.FillTexture == null) { return; } if (!m_mesh.IsClosed) { fillVertices.Add(m_mesh.FillMode != FillMode.Inverted ? m_mesh.Vertices.Last().Position : m_mesh.Vertices.First().Position); } var polygon = new Polygon(fillVertices.Select(v => new PolygonPoint(v.X, v.Y))); if (IsInverted) { var center = polygon.GetCentroid(); var size = new Size(polygon.BoundingBox.Width, polygon.BoundingBox.Height); var topLeft = new Point(center.X - size.Width, center.Y + size.Height); var topRight = new Point(center.X + size.Width, center.Y + size.Height); var bottomLeft = new Point(center.X - size.Width, center.Y - size.Height); var bottomRight = new Point(center.X + size.Width, center.Y - size.Height); var invertedPolygon = new Polygon( new PolygonPoint(bottomLeft.X, bottomLeft.Y), new PolygonPoint(topLeft.X, topLeft.Y), new PolygonPoint(topRight.X, topRight.Y), new PolygonPoint(bottomRight.X, bottomRight.Y)); invertedPolygon.AddHole(polygon); polygon = invertedPolygon; } try { P2T.Triangulate(polygon); } catch (Exception) { return; } var unitsPerFill = CalculateUnitsPerFillUv(); foreach (var triangle in polygon.Triangles) { MeshFillData.AddTriangle( new Point3D(triangle.Points._0.X, triangle.Points._0.Y, 0.0), new Point3D(triangle.Points._1.X, triangle.Points._1.Y, 0.0), new Point3D(triangle.Points._2.X, triangle.Points._2.Y, 0.0), new Point(triangle.Points._0.X / unitsPerFill.X, triangle.Points._0.Y / unitsPerFill.Y), new Point(triangle.Points._1.X / unitsPerFill.X, triangle.Points._1.Y / unitsPerFill.Y), new Point(triangle.Points._2.X / unitsPerFill.X, triangle.Points._2.Y / unitsPerFill.Y)); } }
static Polygon CleanClone(Polygon polygon) { var n = new Polygon(polygon.Points.Select(p => new PolygonPoint(p.X, p.Y))); if (polygon.Holes != null) { foreach (var hole in polygon.Holes) { n.AddHole(CleanClone(hole)); } } return n; }
public void Triangulate() { var start = DateTime.Now; try { LastTriangulationException = null; var newpoly = CleanClone(Polygon); P2T.Triangulate(newpoly); Polygon = newpoly; } catch ( Exception e ) { LastTriangulationException = e; } var stop = DateTime.Now; LastTriangulationDuration = (stop-start); }
/// <summary> /// Creates a <see cref="PrimitiveType.TriangleList"/> of vertices which cover the interior of the /// specified <paramref name="points"/>. The path must be closed and describe a simple polygon. /// </summary> /// <param name="points">Points describing the border of a simple polygon.</param> /// <param name="zCoord">Z coordinate of the created vertices.</param> /// <param name="verts">Returns a <see cref="PrimitiveType.TriangleList"/> of vertices.</param> public static void Triangulate(PointF[] points, float zCoord, out PositionColoredTextured[] verts) { PointF[] pathPoints = AdjustPoints(points); if (pathPoints.Length < 3) { verts = null; return; } if (pathPoints.Length == 3) { verts = new PositionColoredTextured[3]; verts[0].Position = new Vector3(pathPoints[0].X, pathPoints[0].Y, zCoord); verts[1].Position = new Vector3(pathPoints[1].X, pathPoints[1].Y, zCoord); verts[2].Position = new Vector3(pathPoints[2].X, pathPoints[2].Y, zCoord); return; } IList <DelaunayTriangle> polygons; try { // Triangulation can fail (i.e. polygon is self-intersecting) var poly = new Poly2Tri.Polygon(pathPoints.Select(p => new PolygonPoint(p.X, p.Y))); P2T.Triangulate(poly); polygons = poly.Triangles; } catch (Exception) { verts = null; return; } verts = new PositionColoredTextured[polygons.Count * 3]; int offset = 0; foreach (DelaunayTriangle triangle in polygons) { verts[offset++].Position = new Vector3((float)triangle.Points[0].X, (float)triangle.Points[0].Y, zCoord); verts[offset++].Position = new Vector3((float)triangle.Points[1].X, (float)triangle.Points[1].Y, zCoord); verts[offset++].Position = new Vector3((float)triangle.Points[2].X, (float)triangle.Points[2].Y, zCoord); } }
protected override void Initialize() { // Define polygon _points = new List<PolygonPoint>(); _points.Add(new PolygonPoint(-8.485714f, -1.914286f)); _points.Add(new PolygonPoint(-6.514286f, -4.914286f)); _points.Add(new PolygonPoint(-4.514286f, -3.914286f)); _points.Add(new PolygonPoint(-1.514286f, -6.914286f)); _points.Add(new PolygonPoint(1.485714f, -4.914286f)); _points.Add(new PolygonPoint(2.485714f, -5.885714f)); _points.Add(new PolygonPoint(7.457143f, -4.914286f)); _points.Add(new PolygonPoint(8.457143f, -0.9428571f)); _points.Add(new PolygonPoint(6.485714f, 1f)); _points.Add(new PolygonPoint(4.457143f, 6.028572f)); _points.Add(new PolygonPoint(0.4857143f, 7.057143f)); _points.Add(new PolygonPoint(-1.485714f, 3.028571f)); _points.Add(new PolygonPoint(-6.485714f, 1.028571f)); _polygon = new Polygon(_points); // Decompose polygon P2T.Triangulate(_polygon); // Define bounding box _lowerBound = new Vector2((float)_polygon.MinX, (float)_polygon.MinY); _upperBound = new Vector2((float)_polygon.MaxX, (float)_polygon.MaxY); // Create vertices createVertices(); // Create lines createLineVertices(); // Load content base.Initialize(); // Set window size _graphics.PreferredBackBufferWidth = _texture.Width + 64; _graphics.PreferredBackBufferHeight = _texture.Height + 64; _graphics.ApplyChanges(); }
public List<DelaunayTriangle> TriangulateComplex( PolyTree polyTree, bool ignoreFills = false, bool ignoreHoles = true) { PolyNode rootNode; if (polyTree.Total == 0) { Console.WriteLine(0); rootNode = new PolyNode(); } else { rootNode = polyTree.GetFirst().Parent; } // Equivalent to rootNode.Contour = bounds; var contourField = rootNode.GetType().GetField("m_polygon", BindingFlags.Instance | BindingFlags.NonPublic); if (contourField == null) { throw new Exception("Could not find field contour backing field."); } contourField.SetValue(rootNode, kTriangulatorBounds); var result = new List<DelaunayTriangle>(); int i = 0; for (var currentNode = rootNode; currentNode != null; currentNode = currentNode.GetNext()) { if ((ignoreHoles && currentNode.IsHole) || (ignoreFills && !currentNode.IsHole)) continue; var polyline = DownscalePolygon(currentNode.Contour); var finalPolygon = new Polygon(polyline); foreach (var child in currentNode.Childs) { var shrunkContour = EdgeShrink(child.Contour); var holePoints = DownscalePolygon(shrunkContour); var holePoly = new Polygon(holePoints); finalPolygon.AddHole(holePoly); } P2T.Triangulate(finalPolygon); result.AddRange(finalPolygon.Triangles); } return result; }
protected override Polygon GetPolygon() { Polygon poly = new Polygon( GetPoints() ); if( thickness > 0 ) { List<PolygonPoint> holePoints = new List<PolygonPoint>(); float x; float y; float radAngle; float degreeStep = 360f / sides; float r = radius - thickness; for( int i = 0; i < sides; i++ ) { radAngle = MathUtil.DegreesToRadians( degreeStep * i ); x = (float)( Math.Cos( radAngle ) * r ); y = (float)( Math.Sin( radAngle ) * r ); holePoints.Add( new PolygonPoint( x, y ) ); } Polygon hole = new Polygon( holePoints ); poly.AddHole( hole ); } return poly; }
public static Polygon LoadDat(string filename, bool xflip, bool yflip, bool displayFlipX, bool displayFlipY, float rotateAngleInDegrees) { var points = new List<PolygonPoint>(); int lineNum = 0; double precision = TriangulationPoint.kVertexCodeDefaultPrecision; bool skipLine = false; foreach (var line_ in File.ReadAllLines(filename)) { ++lineNum; string line = line_.Trim(); if (string.IsNullOrEmpty(line) || line.StartsWith("//") || line.StartsWith("#") || line.StartsWith(";")) { continue; } if (!skipLine && line.StartsWith("/*")) { skipLine = true; continue; } else if (skipLine) { if (line.StartsWith("*/")) { skipLine = false; } continue; } if (line.StartsWith("Precision", StringComparison.InvariantCultureIgnoreCase)) { if( line.Length> 9) { string ps = line.Substring(9).Trim(); if (!double.TryParse(ps, NumberStyles.Float, CultureInfo.InvariantCulture, out precision)) { Console.WriteLine("Invalid Precision '" + ps + "' in file " + filename + ", line " + lineNum.ToString() +". Setting to " + TriangulationPoint.kVertexCodeDefaultPrecision.ToString()); precision = TriangulationPoint.kVertexCodeDefaultPrecision; } } } else { var xy = line.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); double x, y; if (xy != null && xy.Length >= 2 && double.TryParse(xy[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y)) { points.Add(new PolygonPoint((xflip ? -1.0 : 1.0) * x, (yflip ? -1.0 : 1.0) * y)); } else { Console.WriteLine("Invalid Input '" + line + "' in file " + filename + ", line " + lineNum.ToString()); } } } Polygon p = new Polygon(points); p.FileName = filename; p.DisplayFlipX = displayFlipX; p.DisplayFlipY = displayFlipY; p.DisplayRotate = rotateAngleInDegrees; p.Precision = precision; return p; }
protected virtual Polygon GetPolygon() { Polygon poly = new Polygon(GetPoints()); if (thickness > 0) { Polygon hole = new Polygon(GetPoints(thickness)); poly.AddHole(hole); } return poly; }
public void Add(Polygon p) { _polygons.Add(p); }
/// <summary> /// triangulate polygon, algorithm from wiki is fast enough /// http://wiki.unity3d.com/index.php?title=Triangulator /// </summary> /// <returns></returns> public List <int> Triangulate() { // no holes supported if (holes.Count == 0) { var indices = new List <int>(Points.Length); int n = Points.Length; if (n < 3) { return(indices); } var V = new int[n]; if (Area > 0) { for (int v = 0; v < n; v++) { V[v] = v; } } else { for (int v = 0; v < n; v++) { V[v] = (n - 1) - v; } } int nv = n; int count = 2 * nv; for (int m = 0, v = nv - 1; nv > 2;) { if ((count--) <= 0) { return(indices); } int u = v; if (nv <= u) { u = 0; } v = u + 1; if (nv <= v) { v = 0; } int w = v + 1; if (nv <= w) { w = 0; } if (Snip(u, v, w, nv, V)) { int a, b, c, s, t; a = V[u]; b = V[v]; c = V[w]; indices.Add(a); indices.Add(b); indices.Add(c); m++; for (s = v, t = v + 1; t < nv; s++, t++) { V[s] = V[t]; } nv--; count = 2 * nv; } } indices.Reverse(); return(indices); } else { // use poly2tri library to triangulate mesh with holes var p2tPoints = new List <Poly2Tri.PolygonPoint>(Points.Length); foreach (var point in Points) { p2tPoints.Add(new Poly2Tri.PolygonPoint(point.x, point.y)); } // create p2t polygon var p2tPolygon = new Poly2Tri.Polygon(p2tPoints); // add holes foreach (var polygonHole in holes) { var p2tHolePoints = new List <Poly2Tri.PolygonPoint>(polygonHole.Points.Length); foreach (var polygonPoint in polygonHole.Points) { p2tHolePoints.Add(new Poly2Tri.PolygonPoint(polygonPoint.x, polygonPoint.y)); } p2tPolygon.AddHole(new Poly2Tri.Polygon(p2tHolePoints)); } try { Poly2Tri.P2T.Triangulate(p2tPolygon); } catch (Exception ex) { ExploderUtils.Log("P2T Exception: " + ex); return(null); } var triangles = p2tPolygon.Triangles.Count; var indices = new List <int>(triangles * 3); Points = new Vector2[triangles * 3]; var j = 0; // recalc min max Min.x = float.MaxValue; Min.y = float.MaxValue; Max.x = float.MinValue; Max.y = float.MinValue; for (int i = 0; i < triangles; i++) { indices.Add((j + 0)); indices.Add((j + 1)); indices.Add((j + 2)); Points[j + 2].x = (float)p2tPolygon.Triangles[i].Points._0.X; Points[j + 2].y = (float)p2tPolygon.Triangles[i].Points._0.Y; Points[j + 1].x = (float)p2tPolygon.Triangles[i].Points._1.X; Points[j + 1].y = (float)p2tPolygon.Triangles[i].Points._1.Y; Points[j + 0].x = (float)p2tPolygon.Triangles[i].Points._2.X; Points[j + 0].y = (float)p2tPolygon.Triangles[i].Points._2.Y; // recalc min max for (int k = 0; k < 3; k++) { if (Points[j + k].x < Min.x) { Min.x = Points[j + k].x; } if (Points[j + k].y < Min.y) { Min.y = Points[j + k].y; } if (Points[j + k].x > Max.x) { Max.x = Points[j + k].x; } if (Points[j + k].y > Max.y) { Max.y = Points[j + k].y; } } j += 3; } return(indices); } }
public void UpdateNavigationMesh() { var visitedBlockedCells = new HashSet<NavigationGridletCell>(); var blobs = new List<List<NavigationGridletCell>>(); foreach (var cell in Cells) { if (!cell.Flags.HasFlag(CellFlags.Blocked)) { continue; } if (visitedBlockedCells.Contains(cell)) { continue; } var s = new Stack<NavigationGridletCell>(); s.Push(cell); var blob = new List<NavigationGridletCell>(); while (s.Any()) { var node = s.Pop(); blob.Add(node); visitedBlockedCells.Add(node); var derps = new List<NavigationGridletCell>(); if (node.X > 0) { derps.Add(node.Gridlet.Cells[node.Index - 1]); } if (node.X < node.Gridlet.XLength - 1) { derps.Add(node.Gridlet.Cells[node.Index + 1]); } if (node.Y > 0) { derps.Add(node.Gridlet.Cells[node.Index - node.Gridlet.XLength]); } if (node.Y < node.Gridlet.YLength - 1) { derps.Add(node.Gridlet.Cells[node.Index + node.Gridlet.XLength]); } var blockedNeighbors = derps.Where(n => n.Flags.HasFlag(CellFlags.Blocked)).ToArray(); blockedNeighbors.Where(n => !visitedBlockedCells.Contains(n)).ForEach(s.Push); } blobs.Add(blob); } // derp var cps = new Polygon(new List<PolygonPoint> { new PolygonPoint(-XLength / 2.0f - 5, -YLength / 2.0f - 5), new PolygonPoint(XLength / 2.0f + 5, -YLength / 2.0f - 5), new PolygonPoint(XLength / 2.0f + 5, YLength / 2.0f + 5), new PolygonPoint(-XLength / 2.0f - 5, YLength / 2.0f + 5) }); foreach (var blob in blobs) { var chull = GeometryUtilities.ConvexHull(blob.SelectMany(x => new[] { new ItzWarty.Geometry.Point2D(x.X, x.Y), new ItzWarty.Geometry.Point2D(x.X + 1, x.Y), new ItzWarty.Geometry.Point2D(x.X + 1, x.Y + 1), new ItzWarty.Geometry.Point2D(x.X, x.Y + 1) }).ToArray()); cps.AddHole( new Polygon( chull.Select(p => new PolygonPoint(p.X - XLength / 2.0f, p.Y - YLength / 2.0f)).ToArray() ) ); } var handledNeighborCells = new HashSet<NavigationGridletCell>(); foreach (var edgeCell in EdgeCells.Where(x => x.Flags.HasFlag(CellFlags.Connector))) { var thisObb = this.OrientedBoundingBox; foreach (var neighbor in edgeCell.Neighbors) { if (handledNeighborCells.Contains(neighbor)) { continue; } else { handledNeighborCells.Add(neighbor); } // var neighborObb = neighbor.OrientedBoundingBox; // var neighborToLocal = OrientedBoundingBox.GetBoxToBoxMatrix(ref thisObb, ref neighborObb); // Vector3 zero = new Vector3(0, 0, 0); // Vector3 neighborRelativePosition; // Vector3.Transform(ref zero, ref neighborToLocal, out neighborRelativePosition); // var p = new PolygonPoint((neighborRelativePosition.X), (neighborRelativePosition.Y)); // var q = new PolygonPoint((neighborRelativePosition.X + 0.05), (neighborRelativePosition.Y + 0.05)); // cps.AddConstraint(new TriangulationConstraint(p, q)); } // var p = new PolygonPoint((edgeCell.X + 0.45) * 0.998f - XLength / 2.0f, (edgeCell.Y + 0.45f) * 0.98f - YLength / 2.0f); // var q = new PolygonPoint((edgeCell.X + 0.55) * 0.999f - XLength / 2.0f, (edgeCell.Y + 0.55f) * 0.99f - YLength / 2.0f); // cps.AddConstraint(new TriangulationConstraint(p, q)); } // cps.AddHole( // new List<TriangulationPoint> { // new TriangulationPoint(-XLength / 2 + 2, -YLength / 2 + 2), // new TriangulationPoint(XLength / 2 - 2, -YLength / 2 + 2), // new TriangulationPoint(XLength / 2 - 2, YLength / 2 - 2), // new TriangulationPoint(-XLength / 2 + 2, YLength / 2 - 2) // }, "hole"); P2T.Triangulate(cps); Console.WriteLine(cps.Triangles.Count); Mesh = cps.Triangles; // for (var x = 0; x < XLength; x++) { // for (var y = 0; y < YLength; y++) { // var cellIndex = x + y * XLength; // if (Cells[cellIndex].Flags.HasFlag(CellFlags.Connector)) { // // } // } // } }
private void ConstructPolygon() { List<PolygonPoint> p2 = new List<PolygonPoint>(); int i = 0, l = _points.Count; for (; i < l; i += 1) { p2.Add(new PolygonPoint(_points [i].x, _points [i].y)); } _polygon = new Polygon(p2); _polygon.Simplify(); P2T.Triangulate(_polygon); ContinueCreatingShape(); }
public static Mesh CreateXYMesh(Polygon polygon) { //AML Maybe pass this as arg and reduce coords to XY float z = polygon.outside[0].z; // Check for the easy case (a triangle) if (polygon.holes.Count == 0 && (polygon.outside.Count == 3 || (polygon.outside.Count == 4 && polygon.outside[3] == polygon.outside[0]))) { return(CreateTriangle(polygon)); } // Convert the outside points (throwing out Z at this point) Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ConvertPoints(polygon.outside)); // Convert each of the holes foreach (List <Vector3> hole in polygon.holes) { poly.AddHole(new Poly2Tri.Polygon(ConvertPoints(hole))); } // Triangulate it! Note that this may throw an exception if the data is bogus. try { DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly); DTSweep.Triangulate(tcx); tcx = null; } catch (System.Exception e) { //Profiler.Exit(profileID); throw e; } // Create the indices array Dictionary <uint, int> codeToIndex = new Dictionary <uint, int>(); List <Vector3> vertexList = new List <Vector3>(); foreach (DelaunayTriangle t in poly.Triangles) { foreach (var p in t.Points) { if (codeToIndex.ContainsKey(p.VertexCode)) { continue; } codeToIndex[p.VertexCode] = vertexList.Count; vertexList.Add(new Vector3(p.Xf, p.Yf, z)); } } int[] indices = new int[poly.Triangles.Count * 3]; { int i = 0; foreach (DelaunayTriangle t in poly.Triangles) { indices[i++] = codeToIndex[t.Points[0].VertexCode]; indices[i++] = codeToIndex[t.Points[1].VertexCode]; indices[i++] = codeToIndex[t.Points[2].VertexCode]; } } // Create the UV list, by looking up the closest point for each in our poly Vector2[] uv = null; if (polygon.outsideUVs != null) { uv = new Vector2[vertexList.Count]; for (int i = 0; i < vertexList.Count; i++) { uv[i] = polygon.ClosestUV(vertexList[i]); } } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertexList.ToArray(); msh.triangles = indices; msh.uv = uv; msh.RecalculateNormals(); msh.RecalculateBounds(); return(msh); }
private VertexPositionTexture[] createVerticesFromPoints(List<Vector2> points, out int primitiveCount) { List<PolygonPoint> p2tPoints = new List<PolygonPoint>(); Polygon polygon; Vector2 topLeft = points[0]; Vector2 bottomRight = points[0]; VertexPositionTexture[] vertices; int index = 0; foreach (Vector2 v in points) { p2tPoints.Add(new PolygonPoint(v.X, v.Y)); topLeft = Vector2.Min(v, topLeft); bottomRight = Vector2.Max(v, bottomRight); } polygon = new Polygon(p2tPoints); P2T.Triangulate(polygon); primitiveCount = polygon.Triangles.Count; vertices = new VertexPositionTexture[primitiveCount * 3]; foreach (DelaunayTriangle triangle in polygon.Triangles) { Vector2 p1 = new Vector2(triangle.Points[0].Xf, triangle.Points[0].Yf); Vector2 p2 = new Vector2(triangle.Points[1].Xf, triangle.Points[1].Yf); Vector2 p3 = new Vector2(triangle.Points[2].Xf, triangle.Points[2].Yf); vertices[index++] = new VertexPositionTexture( new Vector3(p1, 0), (p1 - topLeft) / (bottomRight - topLeft)); vertices[index++] = new VertexPositionTexture( new Vector3(p2, 0), (p2 - topLeft) / (bottomRight - topLeft)); vertices[index++] = new VertexPositionTexture( new Vector3(p3, 0), (p3 - topLeft) / (bottomRight - topLeft)); } return vertices; }
private List<Polygon> TriangulatePolyTree(PolyTree tree) { List<Polygon> polygonsGenerated = new List<Polygon>(); List<PolygonPoint> AllPoints = new List<PolygonPoint>(); foreach (PolyNode islands in tree.Childs) { List<PolygonPoint> floorPoints = new List<PolygonPoint>(); foreach (IntPoint point in SubdividePolygon(islands.Contour)) { floorPoints.Add(new PolygonPoint(point.X / GenerationInformation.CalculationScaleFactor, point.Y / GenerationInformation.CalculationScaleFactor)); } AllPoints.AddRange(floorPoints); Polygon floorPolygon = new Polygon(floorPoints); foreach (PolyNode nextNode in islands.Childs) { if (nextNode.IsHole) { List<PolygonPoint> holePoints = new List<PolygonPoint>(); foreach (IntPoint point in SubdividePolygon(nextNode.Contour)) { holePoints.Add(new PolygonPoint(point.X / GenerationInformation.CalculationScaleFactor, point.Y / GenerationInformation.CalculationScaleFactor)); } AllPoints.AddRange(holePoints); floorPolygon.AddHole(new Polygon(holePoints)); } } if (GenerationInformation.UseGrid) { List<TriangulationPoint> steinerPoints = new List<TriangulationPoint>(); for (float x = (float)floorPolygon.BoundingBox.MinX - ((float)floorPolygon.BoundingBox.MinX % GenerationInformation.GridSize.x); x < floorPolygon.BoundingBox.MaxX; x += GenerationInformation.GridSize.x) { for (float y = (float)floorPolygon.BoundingBox.MinY - ((float)floorPolygon.BoundingBox.MinY % GenerationInformation.GridSize.y); y < floorPolygon.BoundingBox.MaxY; y += GenerationInformation.GridSize.y) { TriangulationPoint p = new TriangulationPoint(x, y); if (floorPolygon.IsPointInside(p)) steinerPoints.Add(p); } } CullSteinerPoints(ref steinerPoints, AllPoints, 0.1f); floorPolygon.AddSteinerPoints(steinerPoints); } floorPolygon.Prepare(P2T.CreateContext(TriangulationAlgorithm.DTSweep)); P2T.Triangulate(floorPolygon); polygonsGenerated.Add(floorPolygon); } return polygonsGenerated; }
private static void AddPathToBuffers(Path path, BufferGenerator vertexBufferGenerator, BufferGenerator indexBufferGenerator, ref int indexCount) { List<PolygonPoint> points = new List<PolygonPoint>(); float r; float g; float b; if (path.CompositMode == CompositMode.Subtract) { r = 1f; g = 0f; b = 0f; } else { r = 1f; g = 1f; b = 1f; } foreach (var segment in path.Segments) { if (segment is QuadraticCurveSegment) { var quadraticCurveSegment = segment as QuadraticCurveSegment; AddQuadraticCurveSegment(quadraticCurveSegment, points, vertexBufferGenerator, indexBufferGenerator, ref indexCount, r, g, b); } else if(segment is LineSegment) { var lineSegment = segment as LineSegment; points.Add(new PolygonPoint(lineSegment.End.X, lineSegment.End.Y)); var ext = 0.01; var normal = path.CompositMode == CompositMode.Subtract ? lineSegment.RightNormal : lineSegment.LeftNormal; var p1 = (normal * ext) + lineSegment.Start; var p2 = (normal * ext) + lineSegment.End; AddVertex(vertexBufferGenerator, (float)lineSegment.Start.X, (float)lineSegment.Start.Y, 0f, 1f, r, g, b, 1f); AddVertex(vertexBufferGenerator, (float)lineSegment.End.X, (float)lineSegment.End.Y, 0f, 1f, r, g, b, 1f); AddVertex(vertexBufferGenerator, (float)p1.X, (float)p1.Y, 1f, 1f, r, g, b, 1f); indexBufferGenerator.WriteUInt((uint)indexCount++, (uint)indexCount++, (uint)indexCount++); AddVertex(vertexBufferGenerator, (float)lineSegment.Start.X, (float)lineSegment.Start.Y, 0f, 1f, r, g, b, 1f); AddVertex(vertexBufferGenerator, (float)p1.X, (float)p1.Y, 0f, 0f, r, g, b, 1f); AddVertex(vertexBufferGenerator, (float)p2.X, (float)p2.Y, 1f, 1f, r, g, b, 1f); indexBufferGenerator.WriteUInt((uint)indexCount++, (uint)indexCount++, (uint)indexCount++); } else { throw new NotImplementedException(); } } Polygon polygon; try { polygon = new Polygon(points); P2T.Triangulate(polygon); } catch(Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); return; } foreach (var triangle in polygon.Triangles) { AddVertex(vertexBufferGenerator, (float)triangle.Points[0].X, (float)triangle.Points[0].Y, 0f, 1f, r, g, b, 1f); AddVertex(vertexBufferGenerator, (float)triangle.Points[1].X, (float)triangle.Points[1].Y, 0f, 1f, r, g, b, 1f); AddVertex(vertexBufferGenerator, (float)triangle.Points[2].X, (float)triangle.Points[2].Y, 0f, 1f, r, g, b, 1f); indexBufferGenerator.WriteUInt((uint)indexCount++, (uint)indexCount++, (uint)indexCount++); } }
public void Remove(Polygon p) { _polygons.Remove(p); }
public static MeshProperties[] CreateMesh(List <BoundaryPoint> genPoly, Transform objTrans, float spriteSquareSize) { const int _FRONTOFFSET = 3; const float _BACKFACE_OFFSET = 0.5f; const float _SCALE_FACTOR = 1.1f; MeshProperties _generatedMesh; MeshProperties _frontFaceMesh; Vector2[] _genPolyArrFront = new Vector2[genPoly.Count]; List <VertexProperties> _verts = new List <VertexProperties>(); List <VertexProperties> _frontFaceVerticies = new List <VertexProperties>(); List <int> _indicies = new List <int>(); List <int> _frontFaceIndicies = new List <int>(); //ConvertingToArray for (int i = 0; i < genPoly.Count; i++) { _genPolyArrFront[i] = objTrans.TransformPoint(genPoly[i].Pos); } Vector3 vecSum = Vector3.zero; //VerticiesFront for (int i = 0; i < genPoly.Count; i++) { Vector3 _position = new Vector3(_genPolyArrFront[i].x, _genPolyArrFront[i].y, 0.0f); vecSum += _position; _verts.Add(new VertexProperties { position = _position }); _verts.Add(new VertexProperties { position = _position }); _verts.Add(new VertexProperties { position = _position }); _frontFaceVerticies.Add(new VertexProperties { position = _position }); } //Calculating the center of the unscaled polygon Vector3 polygonCenter = vecSum / genPoly.Count; polygonCenter.z = objTrans.position.z; Matrix4x4 scaleMatrix = BlastProof.Mathematics.ScaleMatrix(_SCALE_FACTOR); Vector3 vecSum2 = Vector3.zero; //VerticiesBack for (int i = 0; i < genPoly.Count; i++) { Vector3 _position = scaleMatrix.MultiplyPoint(new Vector3(_genPolyArrFront[i].x, _genPolyArrFront[i].y, _BACKFACE_OFFSET)); vecSum2 += _position; _verts.Add(new VertexProperties { position = _position }); _verts.Add(new VertexProperties { position = _position }); _verts.Add(new VertexProperties { position = _position }); } Vector3 scaledPolyCenter = vecSum2 / genPoly.Count; scaledPolyCenter.z = objTrans.position.z; //Caching how much should the polygon move on axis so it matches the original scale polygon Vector3 translVec = polygonCenter - scaledPolyCenter; Matrix4x4 transMatrix = BlastProof.Mathematics.TranslateMatrix(translVec); //Multiplying each backface polygon position with the translation matrix so the center of backface polygon and frontface polygon matches for (int i = _verts.Count / 2; i < _verts.Count; i++) { _verts[i].position = transMatrix.MultiplyPoint(_verts[i].position); } var newGenPolyArrFront = new List <Poly2Tri.PolygonPoint>(); for (int i = 0; i < _genPolyArrFront.Length; i++) { var point = new Poly2Tri.PolygonPoint(_genPolyArrFront[i].x, _genPolyArrFront[i].y); point.index = i; newGenPolyArrFront.Add(point); } Poly2Tri.Polygon poly = new Poly2Tri.Polygon(newGenPolyArrFront); DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly); DTSweep.Triangulate(tcx); List <int> indiciesFromTriangulator = new List <int>(); foreach (var triangle in poly.Triangles) { foreach (var point in triangle.Points) { indiciesFromTriangulator.Add(point.index); } } indiciesFromTriangulator.Reverse(); Triangulator tri = new Triangulator(_genPolyArrFront); int[] triangledPoly = indiciesFromTriangulator.ToArray(); //FrontFaceIndicies for (int i = 0; i < triangledPoly.Length; i++) { _indicies.Add(triangledPoly[i] * _FRONTOFFSET); _frontFaceIndicies.Add(triangledPoly[i]); } //BackFaceIndicies for (int i = triangledPoly.Length - 1; i >= 0; i--) { _indicies.Add(triangledPoly[i] * _FRONTOFFSET + (_verts.Count / 2)); } //Front-Back Faces normals for (int i = 0; i < _indicies.Count / 2; i += 3) { int[] v1 = { _indicies[i], _indicies[(i + 1) % (_indicies.Count / 2)], _indicies[(i + 2) % (_indicies.Count / 2)] }; int[] v2 = { _indicies[i + (_indicies.Count / 2)], _indicies[(i + 1) % (_indicies.Count / 2) + (_indicies.Count / 2)], _indicies[(i + 2) % (_indicies.Count / 2) + (_indicies.Count / 2)] }; GetNormalsForVerts(_verts, v1); GetNormalsForVerts(_verts, v2); GetUVsWithSize(_verts, v1, Faces.forward, spriteSquareSize); GetUVsWithSize(_verts, v2, Faces.forward, spriteSquareSize); } //Generating Side Triangles for (int i = 1; i < _verts.Count / 2; i += 6) { int[] frontFaceVerts = { i, (i + 3) % (_verts.Count / 2) }; int[] backFaceVerts = { (i + (_verts.Count / 2)), (i + 3) % (_verts.Count / 2) + (_verts.Count / 2) }; //verts pos are used as uvs int[] uvCoord = { i, (i + 3) % (_verts.Count / 2), (i + (_verts.Count / 2)), (i + 3) % (_verts.Count / 2) + (_verts.Count / 2) }; GetQuadIndicies(frontFaceVerts, backFaceVerts, _indicies, _verts); GetUVsWithSize(_verts, uvCoord, Faces.left, spriteSquareSize); } //Generate Up-Down Verts for (int i = 5; i < _verts.Count / 2; i += 6) { int[] frontFaceVerts = { i % (_verts.Count / 2), (i + 3) % (_verts.Count / 2) }; int[] backFaceVerts = { (i % (_verts.Count / 2) + (_verts.Count / 2)), (i + 3) % (_verts.Count / 2) + (_verts.Count / 2) }; //verts pos are used as uvs int[] uvCoord = { i % (_verts.Count / 2), (i + 3) % (_verts.Count / 2), (i % (_verts.Count / 2) + (_verts.Count / 2)), (i + 3) % (_verts.Count / 2) + (_verts.Count / 2) }; GetQuadIndicies(frontFaceVerts, backFaceVerts, _indicies, _verts); GetUVsWithSize(_verts, uvCoord, Faces.up, spriteSquareSize); } _generatedMesh = new MeshProperties(_verts); _generatedMesh.mesh_center = polygonCenter; _generatedMesh.SetIndicies(_indicies.ToArray()); _frontFaceMesh = new MeshProperties(_frontFaceVerticies); _frontFaceMesh.mesh_center = polygonCenter; _frontFaceMesh.SetIndicies(_frontFaceIndicies.ToArray()); return(new MeshProperties[] { _generatedMesh, _frontFaceMesh }); }
GameObject GenerateCellRegionSurface(int cellIndex, Material material) { if (cellIndex<0 || cellIndex>=cells.Count) return null; Region region = cells [cellIndex].region; // Calculate region's surface points int numSegments = region.segments.Count; Connector connector = new Connector(); if (_terrain==null) { connector.AddRange(region.segments); } else { for (int i = 0; i<numSegments; i++) { Segment s = region.segments[i]; SurfaceSegmentForSurface(s, connector); } } Geom.Polygon surfacedPolygon = connector.ToPolygonFromLargestLineStrip(); List<Point> surfacedPoints = surfacedPolygon.contours[0].points; List<PolygonPoint> ppoints = new List<PolygonPoint>(surfacedPoints.Count); for (int k=0;k<surfacedPoints.Count;k++) { double x = surfacedPoints[k].x+2; double y = surfacedPoints[k].y+2; if (!IsTooNearPolygon(x, y, ppoints)) { float h = _terrain!=null ? _terrain.SampleHeight(transform.TransformPoint((float)x-2, (float)y-2,0)): 0; ppoints.Add (new PolygonPoint(x, y, h)); } } Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ppoints); if (_terrain!=null) { if (steinerPoints==null) { steinerPoints = new List<TriangulationPoint>(6000); } else { steinerPoints.Clear(); } float stepX = 1.0f / heightMapWidth; float smallStep = 1.0f / heightMapWidth; float y = region.rect2D.yMin + smallStep; float ymax = region.rect2D.yMax - smallStep; float[] acumY = new float[terrainRoughnessMapWidth]; while(y<ymax) { int j = (int)((y + 0.5f) * terrainRoughnessMapHeight); // * heightMapHeight)) / TERRAIN_CHUNK_SIZE; if (j>=0) { if (j>=terrainRoughnessMapHeight) j=terrainRoughnessMapHeight-1; float sy = y + 2; float xin = GetFirstPointInRow(sy, ppoints) + smallStep; float xout = GetLastPointInRow(sy, ppoints) - smallStep; int k0 = -1; for (float x = xin; x<xout; x+=stepX) { int k = (int)((x + 0.5f) * terrainRoughnessMapWidth); //)) / TERRAIN_CHUNK_SIZE; if (k>=terrainRoughnessMapWidth) k=terrainRoughnessMapWidth-1; if (k0!=k) { k0=k; stepX = terrainRoughnessMap[j,k]; if (acumY[k] >= stepX) acumY[k] = 0; acumY[k] += smallStep; } if (acumY[k] >= stepX) { // Gather precision height float h = _terrain.SampleHeight (transform.TransformPoint(x,y,0)); float htl = _terrain.SampleHeight (transform.TransformPoint (x-smallStep, y+smallStep, 0)); if (htl>h) h = htl; float htr = _terrain.SampleHeight (transform.TransformPoint (x+smallStep, y+smallStep, 0)); if (htr>h) h = htr; float hbr = _terrain.SampleHeight (transform.TransformPoint (x+smallStep, y-smallStep, 0)); if (hbr>h) h = hbr; float hbl = _terrain.SampleHeight (transform.TransformPoint (x-smallStep, y-smallStep, 0)); if (hbl>h) h = hbl; steinerPoints.Add (new PolygonPoint (x+2, sy, h)); } } } y += smallStep; if (steinerPoints.Count>80000) { break; } } poly.AddSteinerPoints(steinerPoints); } P2T.Triangulate(poly); // Calculate & optimize mesh data int pointCount = poly.Triangles.Count*3; List<Vector3> meshPoints = new List<Vector3> (pointCount); int[] triNew = new int[pointCount]; if (surfaceMeshHit == null) surfaceMeshHit = new Dictionary<TriangulationPoint, int> (2000); else surfaceMeshHit.Clear (); int triNewIndex =-1; int newPointsCount = -1; if (_gridNormalOffset>0) { for (int k=0;k<poly.Triangles.Count;k++) { DelaunayTriangle dt = poly.Triangles[k]; TriangulationPoint p = dt.Points [0]; if (surfaceMeshHit.ContainsKey (p)) { triNew [++triNewIndex] = surfaceMeshHit [p]; } else { Vector3 np = new Vector3(p.Xf-2, p.Yf-2, -p.Zf); np += transform.InverseTransformVector(_terrain.terrainData.GetInterpolatedNormal(np.x+0.5f,np.y+0.5f)) * _gridNormalOffset; meshPoints.Add (np); surfaceMeshHit.Add (p, ++newPointsCount); triNew [++triNewIndex] = newPointsCount; } p = dt.Points [2]; if (surfaceMeshHit.ContainsKey (p)) { triNew [++triNewIndex] = surfaceMeshHit [p]; } else { Vector3 np = new Vector3(p.Xf-2, p.Yf-2, -p.Zf); np += transform.InverseTransformVector(_terrain.terrainData.GetInterpolatedNormal(np.x+0.5f,np.y+0.5f)) * _gridNormalOffset; meshPoints.Add (np); surfaceMeshHit.Add (p, ++newPointsCount); triNew [++triNewIndex] = newPointsCount; } p = dt.Points [1]; if (surfaceMeshHit.ContainsKey (p)) { triNew [++triNewIndex] = surfaceMeshHit [p]; } else { Vector3 np = new Vector3(p.Xf-2, p.Yf-2, -p.Zf); np += transform.InverseTransformVector(_terrain.terrainData.GetInterpolatedNormal(np.x+0.5f,np.y+0.5f)) * _gridNormalOffset; meshPoints.Add (np); surfaceMeshHit.Add (p, ++newPointsCount); triNew [++triNewIndex] = newPointsCount; } } } else { for (int k=0;k<poly.Triangles.Count;k++) { DelaunayTriangle dt = poly.Triangles[k]; TriangulationPoint p = dt.Points [0]; if (surfaceMeshHit.ContainsKey (p)) { triNew [++triNewIndex] = surfaceMeshHit [p]; } else { Vector3 np = new Vector3(p.Xf-2, p.Yf-2, -p.Zf); meshPoints.Add (np); surfaceMeshHit.Add (p, ++newPointsCount); triNew [++triNewIndex] = newPointsCount; } p = dt.Points [2]; if (surfaceMeshHit.ContainsKey (p)) { triNew [++triNewIndex] = surfaceMeshHit [p]; } else { Vector3 np = new Vector3(p.Xf-2, p.Yf-2, -p.Zf); meshPoints.Add (np); surfaceMeshHit.Add (p, ++newPointsCount); triNew [++triNewIndex] = newPointsCount; } p = dt.Points [1]; if (surfaceMeshHit.ContainsKey (p)) { triNew [++triNewIndex] = surfaceMeshHit [p]; } else { Vector3 np = new Vector3(p.Xf-2, p.Yf-2, -p.Zf); meshPoints.Add (np); surfaceMeshHit.Add (p, ++newPointsCount); triNew [++triNewIndex] = newPointsCount; } } } int cacheIndex = GetCacheIndexForCellRegion (cellIndex); string cacheIndexSTR = cacheIndex.ToString(); // Deletes potential residual surface Transform t = surfacesLayer.transform.FindChild(cacheIndexSTR); if (t!=null) DestroyImmediate(t.gameObject); GameObject surf = Drawing.CreateSurface (cacheIndexSTR, meshPoints.ToArray(), triNew, material); _lastVertexCount += surf.GetComponent<MeshFilter>().sharedMesh.vertexCount; surf.transform.SetParent (surfacesLayer.transform, false); surf.transform.localPosition = Vector3.zero; surf.layer = gameObject.layer; if (surfaces.ContainsKey(cacheIndex)) surfaces.Remove(cacheIndex); surfaces.Add (cacheIndex, surf); return surf; }
public PolygonInfo(string name, Polygon polygon) { Name = name; Polygon = polygon; Triangulate(); }
// createFluidBody public void createFluidBody(List<Vector2> polygonPoints) { List<PolygonPoint> P2TPoints = new List<PolygonPoint>(); Polygon polygon; Vector2 topLeft = polygonPoints[0]; Vector2 bottomRight = polygonPoints[0]; float spacing = RADIUS / 3.7f; Random random = new Random(); foreach (Vector2 point in polygonPoints) { topLeft = Vector2.Min(topLeft, point); bottomRight = Vector2.Max(bottomRight, point); P2TPoints.Add(new PolygonPoint(point.X, point.Y)); } polygon = new Polygon(P2TPoints); for (float i = topLeft.X; i < bottomRight.X; i += spacing) { for (float j = topLeft.Y; j < bottomRight.Y; j += spacing) { Vector2 jitter = new Vector2(-1 + (float)random.NextDouble() * 2, -1 + (float)random.NextDouble() * 2) * (spacing * 0.2f); Vector2 point = new Vector2(i, j) + jitter; if (polygon.IsPointInside(new PolygonPoint(point.X, point.Y))) createParticle(point, Vector2.Zero); } } }
/// <summary> /// triangulate polygon, algorithm from wiki is fast enough /// http://wiki.unity3d.com/index.php?title=Triangulator /// </summary> /// <returns></returns> public List<int> Triangulate() { // no holes supported if (holes.Count == 0) { var indices = new List<int>(Points.Length); int n = Points.Length; if (n < 3) return indices; var V = new int[n]; if (Area > 0) { for (int v = 0; v < n; v++) V[v] = v; } else { for (int v = 0; v < n; v++) V[v] = (n - 1) - v; } int nv = n; int count = 2*nv; for (int m = 0, v = nv - 1; nv > 2;) { if ((count--) <= 0) return indices; int u = v; if (nv <= u) u = 0; v = u + 1; if (nv <= v) v = 0; int w = v + 1; if (nv <= w) w = 0; if (Snip(u, v, w, nv, V)) { int a, b, c, s, t; a = V[u]; b = V[v]; c = V[w]; indices.Add(a); indices.Add(b); indices.Add(c); m++; for (s = v, t = v + 1; t < nv; s++, t++) V[s] = V[t]; nv--; count = 2*nv; } } indices.Reverse(); return indices; } else { // use poly2tri library to triangulate mesh with holes var p2tPoints = new List<Poly2Tri.PolygonPoint>(Points.Length); foreach (var point in Points) { p2tPoints.Add(new Poly2Tri.PolygonPoint(point.x, point.y)); } // create p2t polygon var p2tPolygon = new Poly2Tri.Polygon(p2tPoints); // add holes foreach (var polygonHole in holes) { var p2tHolePoints = new List<Poly2Tri.PolygonPoint>(polygonHole.Points.Length); foreach (var polygonPoint in polygonHole.Points) { p2tHolePoints.Add(new Poly2Tri.PolygonPoint(polygonPoint.x, polygonPoint.y)); } p2tPolygon.AddHole(new Poly2Tri.Polygon(p2tHolePoints)); } try { Poly2Tri.P2T.Triangulate(p2tPolygon); } catch (Exception ex) { ExploderUtils.Log("P2T Exception: " + ex); return null; } var triangles = p2tPolygon.Triangles.Count; var indices = new List<int>(triangles*3); Points = new Vector2[triangles*3]; var j = 0; // recalc min max Min.x = float.MaxValue; Min.y = float.MaxValue; Max.x = float.MinValue; Max.y = float.MinValue; for (int i = 0; i < triangles; i++) { indices.Add((j + 0)); indices.Add((j + 1)); indices.Add((j + 2)); Points[j + 2].x = (float)p2tPolygon.Triangles[i].Points._0.X; Points[j + 2].y = (float)p2tPolygon.Triangles[i].Points._0.Y; Points[j + 1].x = (float)p2tPolygon.Triangles[i].Points._1.X; Points[j + 1].y = (float)p2tPolygon.Triangles[i].Points._1.Y; Points[j + 0].x = (float)p2tPolygon.Triangles[i].Points._2.X; Points[j + 0].y = (float)p2tPolygon.Triangles[i].Points._2.Y; // recalc min max for (int k = 0; k < 3; k++) { if (Points[j + k].x < Min.x) { Min.x = Points[j + k].x; } if (Points[j + k].y < Min.y) { Min.y = Points[j + k].y; } if (Points[j + k].x > Max.x) { Max.x = Points[j + k].x; } if (Points[j + k].y > Max.y) { Max.y = Points[j + k].y; } } j += 3; } return indices; } }
public static void Triangulate(Polygon p) { Triangulate(_defaultAlgorithm, p); }
/// <summary> /// Create a Mesh from a given Polygon. /// </summary> /// <returns>The freshly minted mesh.</returns> /// <param name="polygon">Polygon you want to triangulate.</param> public static Mesh CreateMesh(Polygon polygon) { // Ensure we have the rotation properly calculated if (polygon.rotation == Quaternion.identity) polygon.CalcRotation(); // Rotate 1 point and note where it ends up in Z float z = (polygon.rotation * polygon.outside[0]).z; // Convert the outside points (throwing out Z at this point) Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ConvertPoints(polygon.outside, polygon.rotation)); // Convert each of the holes foreach (List<Vector3> hole in polygon.holes) { poly.AddHole(new Poly2Tri.Polygon(ConvertPoints(hole, polygon.rotation))); } // Triangulate it! Note that this may throw an exception if the data is bogus. DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly); DTSweep.Triangulate(tcx); tcx = null; // Create the Vector3 vertices (undoing the rotation), // and also build a map of vertex codes to indices Quaternion invRot = Quaternion.Inverse(polygon.rotation); Dictionary<uint, int> codeToIndex = new Dictionary<uint, int>(); List<Vector3> vertexList = new List<Vector3>(); foreach (DelaunayTriangle t in poly.Triangles) { foreach (var p in t.Points) { if (codeToIndex.ContainsKey(p.VertexCode)) continue; codeToIndex[p.VertexCode] = vertexList.Count; Vector3 pos = new Vector3(p.Xf, p.Yf, z); // (restore the Z we saved earlier) vertexList.Add(invRot * pos); } } // Create the indices array int[] indices = new int[poly.Triangles.Count * 3]; { int i = 0; foreach (DelaunayTriangle t in poly.Triangles) { indices[i++] = codeToIndex[t.Points[0].VertexCode]; indices[i++] = codeToIndex[t.Points[1].VertexCode]; indices[i++] = codeToIndex[t.Points[2].VertexCode]; } } // Create the UV list, by looking up the closest point for each in our poly Mesh msh = new Mesh(); msh.vertices = vertexList.ToArray(); Vector2[] uvs = new Vector2[msh.vertices.Length]; for (int i=0; i < uvs.Length; i++) { uvs[i] = new Vector2(msh.vertices[i].x, msh.vertices[i].y); } msh.uv = uvs; /*if (polygon.OutsideUVs != null) { uv = new Vector2[vertexList.Count]; for (int i=0; i<vertexList.Count; i++) { uv[i] = polygon.ClosestUV(vertexList[i]); } }*/ // Create the mesh msh.triangles = indices; msh.RecalculateNormals(); msh.RecalculateBounds(); return msh; }
public PolygonSet(Polygon poly) { _polygons.Add(poly); }
/// <summary> /// Create a Mesh from a given Polygon. /// </summary> /// <returns>The freshly minted mesh.</returns> /// <param name="polygon">Polygon you want to triangulate.</param> public static Mesh CreateMesh(Polygon polygon) { // Ensure we have the rotation properly calculated if (polygon.rotation == Quaternion.identity) { polygon.CalcRotation(); } // Rotate 1 point and note where it ends up in Z float z = (polygon.rotation * polygon.outside[0]).z; // Convert the outside points (throwing out Z at this point) Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ConvertPoints(polygon.outside, polygon.rotation)); // Convert each of the holes foreach (List <Vector3> hole in polygon.holes) { poly.AddHole(new Poly2Tri.Polygon(ConvertPoints(hole, polygon.rotation))); } // Triangulate it! Note that this may throw an exception if the data is bogus. DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly); DTSweep.Triangulate(tcx); tcx = null; // Create the Vector3 vertices (undoing the rotation), // and also build a map of vertex codes to indices Quaternion invRot = Quaternion.Inverse(polygon.rotation); Dictionary <uint, int> codeToIndex = new Dictionary <uint, int>(); List <Vector3> vertexList = new List <Vector3>(); foreach (DelaunayTriangle t in poly.Triangles) { foreach (var p in t.Points) { if (codeToIndex.ContainsKey(p.VertexCode)) { continue; } codeToIndex[p.VertexCode] = vertexList.Count; Vector3 pos = new Vector3(p.Xf, p.Yf, z); // (restore the Z we saved earlier) vertexList.Add(invRot * pos); } } // Create the indices array int[] indices = new int[poly.Triangles.Count * 3]; { int i = 0; foreach (DelaunayTriangle t in poly.Triangles) { indices[i++] = codeToIndex[t.Points[0].VertexCode]; indices[i++] = codeToIndex[t.Points[1].VertexCode]; indices[i++] = codeToIndex[t.Points[2].VertexCode]; } } // Create the UV list, by looking up the closest point for each in our poly Vector2[] uv = null; // if (polygon.outsideUVs != null) { // uv = new Vector2[vertexList.Count]; // for (int i=0; i<vertexList.Count; i++) { // uv[i] = polygon.ClosestUV(vertexList[i]); // } // } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertexList.ToArray(); msh.triangles = indices; msh.uv = uv; msh.RecalculateNormals(); msh.RecalculateBounds(); return(msh); }
/// <summary> /// Add a hole to the polygon. /// </summary> /// <param name="poly">A subtraction polygon fully contained inside this polygon.</param> public void AddHole(Polygon poly) { if (_holes == null) _holes = new List<Polygon>(); _holes.Add(poly); // XXX: tests could be made here to be sure it is fully inside // addSubtraction( poly.getPoints() ); }
/// <summary> /// Create a Mesh from a given Polygon. /// </summary> /// <returns>The freshly minted mesh.</returns> /// <param name="polygon">Polygon you want to triangulate.</param> public static bool CreateMesh(List <Poly2Mesh.Polygon> polygons, ref Mesh dstMesh) { // TODO: use vertex indices instead of actual vertices to find original vertices var poly2TriPolygons = new List <Poly2Tri.Polygon>(); var codeToPositions = new List <Dictionary <uint, Vector3> >(); var zs = new List <float>(); // Ensure we have the rotation properly calculated, and have a valid normal for (int p = 0; p < polygons.Count; p++) { if (polygons[p].rotation == Quaternion.identity) { polygons[p].CalcRotation(); } if (polygons[p].planeNormal == Vector3.zero) { Debug.Log("polygons[p].planeNormal == Vector3.zero"); return(false); // bad data } // Rotate 1 point and note where it ends up in Z float z = (polygons[p].rotation * polygons[p].outside[0]).z; // Prepare a map from vertex codes to 3D positions. Dictionary <uint, Vector3> codeToPosition = new Dictionary <uint, Vector3>(); // Convert the outside points (throwing out Z at this point) Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ConvertPoints(polygons[p].outside, polygons[p].rotation, codeToPosition)); // Convert each of the holes if (polygons[p].holes != null) { foreach (List <Vector3> hole in polygons[p].holes) { poly.AddHole(new Poly2Tri.Polygon(ConvertPoints(hole, polygons[p].rotation, codeToPosition))); } } codeToPositions.Add(codeToPosition); poly2TriPolygons.Add(poly); zs.Add(z); } // Triangulate it! Note that this may throw an exception if the data is bogus. for (int p = 0; p < poly2TriPolygons.Count; p++) { try { DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly2TriPolygons[p]); DTSweep.Triangulate(tcx); tcx = null; } catch (System.Exception e) { //Profiler.Exit(profileID); Debug.LogException(e); //throw e; } } // Now, to get back to our original positions, use our code-to-position map. We do // this instead of un-rotating to be a little more robust about noncoplanar polygons. // Create the Vector3 vertices (undoing the rotation), // and also build a map of vertex codes to indices Quaternion? invRot = null; Dictionary <uint, int> codeToIndex = new Dictionary <uint, int>(); List <Vector3> vertexList = new List <Vector3>(); List <int> indexList = new List <int>(); int triangleCount = 0; for (int p = 0; p < polygons.Count; p++) { var poly = poly2TriPolygons[p]; var polygon = polygons[p]; var z = zs[p]; var codeToPosition = codeToPositions[p]; triangleCount += poly.Triangles.Count; codeToIndex.Clear(); foreach (DelaunayTriangle t in poly.Triangles) { foreach (var point in t.Points) { if (codeToIndex.ContainsKey(point.VertexCode)) { continue; } codeToIndex[point.VertexCode] = vertexList.Count; Vector3 pos; if (!codeToPosition.TryGetValue(point.VertexCode, out pos)) { // This can happen in rare cases when we're hitting limits of floating-point precision. // Rather than fail, let's just do the inverse rotation. Debug.LogWarning("Vertex code lookup failed; using inverse rotation."); if (!invRot.HasValue) { invRot = Quaternion.Inverse(polygon.rotation); } pos = invRot.Value * new Vector3(point.Xf, point.Yf, z); } vertexList.Add(pos); } } if (polygon.inverse) { foreach (DelaunayTriangle t in poly.Triangles) { indexList.Add(codeToIndex[t.Points[2].VertexCode]); indexList.Add(codeToIndex[t.Points[1].VertexCode]); indexList.Add(codeToIndex[t.Points[0].VertexCode]); } } else { foreach (DelaunayTriangle t in poly.Triangles) { indexList.Add(codeToIndex[t.Points[0].VertexCode]); indexList.Add(codeToIndex[t.Points[1].VertexCode]); indexList.Add(codeToIndex[t.Points[2].VertexCode]); } } } // Create the indices array var indices = indexList.ToArray(); // Create the mesh dstMesh.vertices = vertexList.ToArray(); dstMesh.triangles = indices; dstMesh.RecalculateNormals(); return(true); }
protected override Polygon GetPolygon() { Polygon poly = new Polygon(GetPoints()); if (thickness > 1) { List<PolygonPoint> points = GetPoints(); Vector2 center = GetCentroid(points); float[] angles = { AngleA(a, b, c), AngleB(a, b, c), AngleC(a, b, c) }; int count = points.Count; for (int i = count; --i >= 0;) { PolygonPoint point = points[i]; double vecX = center.X - point.X; double vecY = center.Y - point.Y; double invLen = 1d / Math.Sqrt((vecX * vecX) + (vecY * vecY)); vecX = vecX * invLen; vecY = vecY * invLen; float ratio = 1 - (angles[i] / 180); float angleThickness = ratio * thickness; point.X += vecX * angleThickness; point.Y += vecY * angleThickness; } Polygon hole = new Polygon(points); poly.AddHole(hole); } return poly; }
/// <summary> /// Creates a <see cref="PrimitiveType.TriangleList"/> of vertices which cover the interior of the /// specified <paramref name="points"/>. The path must be closed and describe a simple polygon. /// </summary> /// <param name="points">Points describing the border of a simple polygon.</param> /// <param name="zCoord">Z coordinate of the created vertices.</param> /// <param name="verts">Returns a <see cref="PrimitiveType.TriangleList"/> of vertices.</param> public static void Triangulate(PointF[] points, float zCoord, out PositionColoredTextured[] verts) { PointF[] pathPoints = AdjustPoints(points); if (pathPoints.Length < 3) { verts = null; return; } if (pathPoints.Length == 3) { verts = new PositionColoredTextured[3]; verts[0].Position = new Vector3(pathPoints[0].X, pathPoints[0].Y, zCoord); verts[1].Position = new Vector3(pathPoints[1].X, pathPoints[1].Y, zCoord); verts[2].Position = new Vector3(pathPoints[2].X, pathPoints[2].Y, zCoord); return; } IList<DelaunayTriangle> polygons; try { // Triangulation can fail (i.e. polygon is self-intersecting) var poly = new Poly2Tri.Polygon(pathPoints.Select(p => new PolygonPoint(p.X, p.Y))); P2T.Triangulate(poly); polygons = poly.Triangles; } catch (Exception) { verts = null; return; } verts = new PositionColoredTextured[polygons.Count * 3]; int offset = 0; foreach (DelaunayTriangle triangle in polygons) { verts[offset++].Position = new Vector3((float)triangle.Points[0].X, (float)triangle.Points[0].Y, zCoord); verts[offset++].Position = new Vector3((float)triangle.Points[1].X, (float)triangle.Points[1].Y, zCoord); verts[offset++].Position = new Vector3((float)triangle.Points[2].X, (float)triangle.Points[2].Y, zCoord); } }
public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var width = box.Width; var length = Math.Max(1, Math.Abs((int)box.Length)); var height = box.Height; var flatten = (float)_flattenFactor.Value; var text = _text.GetValue(); var family = _fontChooser.GetFontFamily(); var style = Enum.GetValues(typeof(FontStyle)).OfType <FontStyle>().FirstOrDefault(fs => family.IsStyleAvailable(fs)); if (!family.IsStyleAvailable(style)) { family = FontFamily.GenericSansSerif; } var set = new PolygonSet(); var sizes = new List <RectangleF>(); using (var bmp = new Bitmap(1, 1)) { using (var g = System.Drawing.Graphics.FromImage(bmp)) { using (var font = new Font(family, length, style, GraphicsUnit.Pixel)) { for (var i = 0; i < text.Length; i += 32) { using (var sf = new StringFormat(StringFormat.GenericTypographic)) { var rem = Math.Min(text.Length, i + 32) - i; var range = Enumerable.Range(0, rem).Select(x => new CharacterRange(x, 1)).ToArray(); sf.SetMeasurableCharacterRanges(range); var reg = g.MeasureCharacterRanges(text.Substring(i, rem), font, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf); sizes.AddRange(reg.Select(x => x.GetBounds(g))); } } } } } var xOffset = box.Start.DX; var yOffset = box.End.DY; for (var ci = 0; ci < text.Length; ci++) { var c = text[ci]; var size = sizes[ci]; var gp = new GraphicsPath(); gp.AddString(c.ToString(CultureInfo.InvariantCulture), family, (int)style, length, new PointF(0, 0), StringFormat.GenericTypographic); gp.Flatten(new System.Drawing.Drawing2D.Matrix(), flatten); var polygons = new List <Polygon>(); var poly = new List <PolygonPoint>(); for (var i = 0; i < gp.PointCount; i++) { var type = gp.PathTypes[i]; var point = gp.PathPoints[i]; poly.Add(new PolygonPoint(point.X + xOffset, -point.Y + yOffset)); if ((type & 0x80) == 0x80) { polygons.Add(new Polygon(poly)); poly.Clear(); } } var tri = new List <Polygon>(); Polygon polygon = null; foreach (var p in polygons) { if (polygon == null) { polygon = p; tri.Add(p); } else if (p.CalculateWindingOrder() != polygon.CalculateWindingOrder()) { polygon.AddHole(p); } else { polygon = null; tri.Add(p); } } foreach (var pp in tri) { try { P2T.Triangulate(pp); set.Add(pp); } catch { // Ignore } } xOffset += size.Width; } var zOffset = box.Start.Z; foreach (var polygon in set.Polygons) { foreach (var t in polygon.Triangles) { var points = t.Points.Select(x => new Coordinate((decimal)x.X, (decimal)x.Y, zOffset).Round(roundDecimals)).ToList(); var faces = new List <Coordinate[]>(); // Add the vertical faces var z = new Coordinate(0, 0, height).Round(roundDecimals); for (var j = 0; j < points.Count; j++) { var next = (j + 1) % points.Count; faces.Add(new[] { points[j], points[j] + z, points[next] + z, points[next] }); } // Add the top and bottom faces faces.Add(points.ToArray()); faces.Add(points.Select(x => x + z).Reverse().ToArray()); // Nothing new here, move along var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return(solid); } } }
GameObject GenerateTerritoryRegionSurface(int territoryIndex, Material material, Vector2 textureScale, Vector2 textureOffset, float textureRotation) { if (territoryIndex<0 || territoryIndex>=territories.Count) return null; Region region = territories [territoryIndex].region; // Calculate region's surface points int numSegments = region.segments.Count; Connector connector = new Connector(); if (_terrain==null) { connector.AddRange(region.segments); } else { for (int i = 0; i<numSegments; i++) { Segment s = region.segments[i]; SurfaceSegmentForSurface(s, connector); } } Geom.Polygon surfacedPolygon = connector.ToPolygonFromLargestLineStrip(); List<Point> surfacedPoints = surfacedPolygon.contours[0].points; List<PolygonPoint> ppoints = new List<PolygonPoint>(surfacedPoints.Count); for (int k=0;k<surfacedPoints.Count;k++) { double x = surfacedPoints[k].x+2; double y = surfacedPoints[k].y+2; if (!IsTooNearPolygon(x, y, ppoints)) { float h = _terrain!=null ? _terrain.SampleHeight(transform.TransformPoint((float)x-2, (float)y-2,0)): 0; ppoints.Add (new PolygonPoint(x, y, h)); } } Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ppoints); if (_terrain!=null) { if (steinerPoints==null) { steinerPoints = new List<TriangulationPoint>(6000); } else { steinerPoints.Clear(); } float stepX = 1.0f / heightMapWidth; float smallStep = 1.0f / heightMapWidth; float y = region.rect2D.yMin + smallStep; float ymax = region.rect2D.yMax - smallStep; float[] acumY = new float[terrainRoughnessMapWidth]; while(y<ymax) { int j = (int)((y + 0.5f) * terrainRoughnessMapHeight); // * heightMapHeight)) / TERRAIN_CHUNK_SIZE; if (j>=terrainRoughnessMapHeight) j=terrainRoughnessMapHeight-1; float sy = y + 2; float xin = GetFirstPointInRow(sy, ppoints) + smallStep; float xout = GetLastPointInRow(sy, ppoints) - smallStep; int k0 = -1; for (float x = xin; x<xout; x+=stepX) { int k = (int)((x + 0.5f) * terrainRoughnessMapWidth); //)) / TERRAIN_CHUNK_SIZE; if (k>=terrainRoughnessMapWidth) k=terrainRoughnessMapWidth-1; if (k0!=k) { k0=k; stepX = terrainRoughnessMap[j,k]; if (acumY[k] >= stepX) acumY[k] = 0; acumY[k] += smallStep; } if (acumY[k] >= stepX) { // Gather precision height float h = _terrain.SampleHeight (transform.TransformPoint(x,y,0)); float htl = _terrain.SampleHeight (transform.TransformPoint (x-smallStep, y+smallStep, 0)); if (htl>h) h = htl; float htr = _terrain.SampleHeight (transform.TransformPoint (x+smallStep, y+smallStep, 0)); if (htr>h) h = htr; float hbr = _terrain.SampleHeight (transform.TransformPoint (x+smallStep, y-smallStep, 0)); if (hbr>h) h = hbr; float hbl = _terrain.SampleHeight (transform.TransformPoint (x-smallStep, y-smallStep, 0)); if (hbl>h) h = hbl; steinerPoints.Add (new PolygonPoint (x+2, sy, h)); } } y += smallStep; if (steinerPoints.Count>80000) { break; } } poly.AddSteinerPoints(steinerPoints); } P2T.Triangulate(poly); Vector3[] revisedSurfPoints = new Vector3[poly.Triangles.Count*3]; if (_gridNormalOffset>0) { for (int k=0;k<poly.Triangles.Count;k++) { DelaunayTriangle dt = poly.Triangles[k]; float x = dt.Points[0].Xf-2; float y = dt.Points[0].Yf-2; float z = -dt.Points[0].Zf; Vector3 nd = transform.InverseTransformVector(_terrain.terrainData.GetInterpolatedNormal(x+0.5f,y+0.5f)) * _gridNormalOffset; revisedSurfPoints[k*3].x = x + nd.x; revisedSurfPoints[k*3].y = y + nd.y; revisedSurfPoints[k*3].z = z + nd.z; x = dt.Points[2].Xf-2; y = dt.Points[2].Yf-2; z = -dt.Points[2].Zf; nd = transform.InverseTransformVector(_terrain.terrainData.GetInterpolatedNormal(x+0.5f,y+0.5f)) * _gridNormalOffset; revisedSurfPoints[k*3+1].x = x + nd.x; revisedSurfPoints[k*3+1].y = y + nd.y; revisedSurfPoints[k*3+1].z = z + nd.z; x = dt.Points[1].Xf-2; y = dt.Points[1].Yf-2; z = -dt.Points[1].Zf; nd = transform.InverseTransformVector(_terrain.terrainData.GetInterpolatedNormal(x+0.5f,y+0.5f)) * _gridNormalOffset; revisedSurfPoints[k*3+2].x = x + nd.x; revisedSurfPoints[k*3+2].y = y + nd.y; revisedSurfPoints[k*3+2].z = z + nd.z; } } else { for (int k=0;k<poly.Triangles.Count;k++) { DelaunayTriangle dt = poly.Triangles[k]; revisedSurfPoints[k*3].x = dt.Points[0].Xf-2; revisedSurfPoints[k*3].y = dt.Points[0].Yf-2; revisedSurfPoints[k*3].z = -dt.Points[0].Zf; revisedSurfPoints[k*3+1].x = dt.Points[2].Xf-2; revisedSurfPoints[k*3+1].y = dt.Points[2].Yf-2; revisedSurfPoints[k*3+1].z = -dt.Points[2].Zf; revisedSurfPoints[k*3+2].x = dt.Points[1].Xf-2; revisedSurfPoints[k*3+2].y = dt.Points[1].Yf-2; revisedSurfPoints[k*3+2].z = -dt.Points[1].Zf; } } int cacheIndex = GetCacheIndexForTerritoryRegion (territoryIndex); string cacheIndexSTR = cacheIndex.ToString(); // Deletes potential residual surface Transform t = surfacesLayer.transform.FindChild(cacheIndexSTR); if (t!=null) DestroyImmediate(t.gameObject); GameObject surf = Drawing.CreateSurface (cacheIndexSTR, revisedSurfPoints, material); surf.transform.SetParent (surfacesLayer.transform, false); surf.transform.localPosition = Vector3.zero; surf.layer = gameObject.layer; if (surfaces.ContainsKey(cacheIndex)) surfaces.Remove(cacheIndex); surfaces.Add (cacheIndex, surf); return surf; }
/// <summary> /// Create a Mesh from a given Polygon. /// </summary> /// <returns>The freshly minted mesh.</returns> /// <param name="polygon">Polygon you want to triangulate.</param> public static Mesh CreateMesh(Polygon polygon) { // Check for the easy case (a triangle) if (polygon.holes.Count == 0 && (polygon.outside.Count == 3 || (polygon.outside.Count == 4 && polygon.outside[3] == polygon.outside[0]))) { return(CreateTriangle(polygon)); } // Ensure we have the rotation properly calculated, and have a valid normal if (polygon.rotation == Quaternion.identity) { polygon.CalcRotation(); } if (polygon.planeNormal == Vector3.zero) { return(null); // bad data } // Rotate 1 point and note where it ends up in Z float z = (polygon.rotation * polygon.outside[0]).z; // Prepare a map from vertex codes to 3D positions. Dictionary <uint, Vector3> codeToPosition = new Dictionary <uint, Vector3>(); // Convert the outside points (throwing out Z at this point) Poly2Tri.Polygon poly = new Poly2Tri.Polygon(ConvertPoints(polygon.outside, polygon.rotation, codeToPosition)); // Convert each of the holes foreach (List <Vector3> hole in polygon.holes) { poly.AddHole(new Poly2Tri.Polygon(ConvertPoints(hole, polygon.rotation, codeToPosition))); } // Triangulate it! Note that this may throw an exception if the data is bogus. try { DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly); DTSweep.Triangulate(tcx); tcx = null; } catch (System.Exception e) { throw e; } // Now, to get back to our original positions, use our code-to-position map. We do // this instead of un-rotating to be a little more robust about noncoplanar polygons. // Create the Vector3 vertices (undoing the rotation), // and also build a map of vertex codes to indices Quaternion? invRot = null; Dictionary <uint, int> codeToIndex = new Dictionary <uint, int>(); List <Vector3> vertexList = new List <Vector3>(); foreach (DelaunayTriangle t in poly.Triangles) { foreach (var p in t.Points) { if (codeToIndex.ContainsKey(p.VertexCode)) { continue; } codeToIndex[p.VertexCode] = vertexList.Count; Vector3 pos; if (!codeToPosition.TryGetValue(p.VertexCode, out pos)) { // This can happen in rare cases when we're hitting limits of floating-point precision. // Rather than fail, let's just do the inverse rotation. if (!invRot.HasValue) { invRot = Quaternion.Inverse(polygon.rotation); } pos = invRot.Value * new Vector3(p.Xf, p.Yf, z); } vertexList.Add(pos); } } // Create the indices array int[] indices = new int[poly.Triangles.Count * 3]; { int i = 0; foreach (DelaunayTriangle t in poly.Triangles) { indices[i++] = codeToIndex[t.Points[0].VertexCode]; indices[i++] = codeToIndex[t.Points[1].VertexCode]; indices[i++] = codeToIndex[t.Points[2].VertexCode]; } } // Create the UV list, by looking up the closest point for each in our poly Vector2[] uv = null; if (polygon.outsideUVs != null) { uv = new Vector2[vertexList.Count]; for (int i = 0; i < vertexList.Count; i++) { uv[i] = polygon.ClosestUV(vertexList[i]); } } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertexList.ToArray(); msh.triangles = indices; msh.uv = uv; msh.RecalculateNormals(); msh.RecalculateBounds(); return(msh); }
/// <summary>Triangulate a polygon and return whether it was successful.</summary> private static bool Triangulate(Polygon polygon) { TextWriter console = Console.Out; Console.SetOut(Controller.TrashLog); try { P2T.Triangulate(polygon); Console.SetOut(console); return true; } catch (Exception ex) { if (ex.Message != "Error marking neighbors -- t doesn't contain edge p1-p2!") { Console.SetOut(console); Trace.TraceWarning("Polygon failed to triangulate."); } return false; } }