public static List <Poly2Tri.Polygon> GetTriangles(IList <PolygonClosedD2D> polygons) { var result = new List <Poly2Tri.Polygon>(); for (int i = 0; i < polygons.Count; ++i) { if (polygons[i].IsHole) { continue; } var mainPolygon = new Poly2Tri.Polygon(polygons[i].Points.Select(pt => new Poly2Tri.PolygonPoint(pt.X, pt.Y))); // find all holes in mainPolygon for (int j = 0; j < polygons.Count; ++j) { if (polygons[j].IsHole && object.ReferenceEquals(polygons[j].Parent, polygons[i])) { var holePolygon = new Poly2Tri.Polygon(polygons[j].Points.Select(pt => new Poly2Tri.PolygonPoint(pt.X, pt.Y))); mainPolygon.AddHole(holePolygon); } } result.Add(mainPolygon); } foreach (var p in result) { Poly2Tri.P2T.Triangulate(p); } return(result); }
void DrawSimpleRectWithHoleExample(Painter painter) { Poly2Tri.TriangulationPoint[] box = new Poly2Tri.TriangulationPoint[] { new Poly2Tri.TriangulationPoint(5, 5), new Poly2Tri.TriangulationPoint(45, 5), new Poly2Tri.TriangulationPoint(45, 45), new Poly2Tri.TriangulationPoint(5, 45) }; Poly2Tri.TriangulationPoint[] hole = new Poly2Tri.TriangulationPoint[] { new Poly2Tri.TriangulationPoint(10, 10), new Poly2Tri.TriangulationPoint(40, 10), new Poly2Tri.TriangulationPoint(40, 40), new Poly2Tri.TriangulationPoint(10, 40) }; Poly2Tri.Polygon polygon = new Poly2Tri.Polygon(box); polygon.AddHole(new Poly2Tri.Polygon(hole)); Poly2Tri.P2T.Triangulate(polygon); painter.StrokeColor = Color.Black; DrawPoly2TriPolygon(painter, new List <Poly2Tri.Polygon>() { polygon }); }
static GlyphFitOutline TessWithPolyTri(List <GlyphContour> contours) { List <Poly2Tri.TriangulationPoint> points = new List <Poly2Tri.TriangulationPoint>(); int cntCount = contours.Count; GlyphContour cnt = contours[0]; Poly2Tri.Polygon polygon = CreatePolygon2(contours[0]);//first contour bool isHoleIf = !cnt.IsClockwise; //if (cntCount > 0) //{ // //debug only for (int n = 1; n < cntCount; ++n) { cnt = contours[n]; //IsHole is correct after we Analyze() the glyph contour polygon.AddHole(CreatePolygon2(cnt)); //if (cnt.IsClockwise == isHoleIf) //{ // polygon.AddHole(CreatePolygon2(cnt)); //} //else //{ // //eg i // //the is a complete separate dot (i head) over i body //} } //} //------------------------------------------ Poly2Tri.P2T.Triangulate(polygon); //that poly is triangulated GlyphFitOutline glyphFitOutline = new GlyphFitOutline(polygon, contours); glyphFitOutline.Analyze(); //------------------------------------------ #if DEBUG List <GlyphTriangle> triAngles = glyphFitOutline.dbugGetTriangles(); int triangleCount = triAngles.Count; for (int i = 0; i < triangleCount; ++i) { //--------------- GlyphTriangle tri = triAngles[i]; AssignPointEdgeInvolvement(tri.e0); AssignPointEdgeInvolvement(tri.e1); AssignPointEdgeInvolvement(tri.e2); } #endif return(glyphFitOutline); }
private List <Poly2Tri.DelaunayTriangle> GetTriangleListFromClipperSolution(ClipperLib.PolyTree solution) { Func <ClipperLib.IntPoint, Poly2Tri.PolygonPoint> xfToPolygonPoint = (p) => new Poly2Tri.PolygonPoint(p.X, p.Y); Poly2Tri.PolygonSet polygonSet = new Poly2Tri.PolygonSet(); ClipperLib.PolyNode node = solution.GetFirst(); while (node != null) { // Only interested in closed paths if (!node.IsOpen) { if (node.IsHole) { if (polygonSet.Polygons.Count() > 0) { // Add hole to last polygon entered var polyPoints = node.Contour.Select(xfToPolygonPoint).ToArray(); Poly2Tri.Polygon hole = new Poly2Tri.Polygon(polyPoints); Poly2Tri.Polygon polygon = polygonSet.Polygons.Last(); polygon.AddHole(hole); } } else { // Add a new polygon to the set var polyPoints = node.Contour.Select(xfToPolygonPoint).ToList(); Poly2Tri.Polygon polygon = new Poly2Tri.Polygon(polyPoints); polygonSet.Add(polygon); } } node = node.GetNext(); } // Now triangulate the whole set Poly2Tri.P2T.Triangulate(polygonSet); // Combine all the triangles into one list List <Poly2Tri.DelaunayTriangle> triangles = new List <Poly2Tri.DelaunayTriangle>(); foreach (var polygon in polygonSet.Polygons) { triangles.AddRange(polygon.Triangles); } return(triangles); }
void DrawVxsArrowHoleExample(Painter painter) { //1. background box Poly2Tri.TriangulationPoint[] box = new Poly2Tri.TriangulationPoint[] { new Poly2Tri.TriangulationPoint(5, 5), new Poly2Tri.TriangulationPoint(200, 5), new Poly2Tri.TriangulationPoint(200, 200), new Poly2Tri.TriangulationPoint(5, 200) }; Poly2Tri.Polygon bgBoxPolygon = new Poly2Tri.Polygon(box); //2. arrow-shape hole VertexStore vxs = BuildArrow(true); using (Poly2TriTool.Borrow(out var p23tool)) { p23tool.YAxisPointDown = true; //since our vxs is create from Y axis point down world List <Poly2Tri.Polygon> polygons = new List <Poly2Tri.Polygon>(); p23tool.PreparePolygons(vxs, polygons); foreach (Poly2Tri.Polygon polygon in polygons) { //arrow-shape hole bgBoxPolygon.AddHole(polygon); } Poly2Tri.P2T.Triangulate(bgBoxPolygon); painter.StrokeColor = Color.Black; DrawPoly2TriPolygon(painter, new List <Poly2Tri.Polygon>() { bgBoxPolygon }); } }
public static List<Poly2Tri.Polygon> GetTriangles(IList<PolygonClosedD2D> polygons) { var result = new List<Poly2Tri.Polygon>(); for (int i = 0; i < polygons.Count; ++i) { if (polygons[i].IsHole) continue; var mainPolygon = new Poly2Tri.Polygon(polygons[i].Points.Select(pt => new Poly2Tri.PolygonPoint(pt.X, pt.Y))); // find all holes in mainPolygon for (int j = 0; j < polygons.Count; ++j) { if (polygons[j].IsHole && object.ReferenceEquals(polygons[j].Parent, polygons[i])) { var holePolygon = new Poly2Tri.Polygon(polygons[j].Points.Select(pt => new Poly2Tri.PolygonPoint(pt.X, pt.Y))); mainPolygon.AddHole(holePolygon); } } result.Add(mainPolygon); } foreach (var p in result) { Poly2Tri.P2T.Triangulate(p); } return result; }
public static Poly2Tri.Polygon Triangulate(float[] polygon1, int[] contourEndIndices) { //create List <GlyphContour> flattenContours = CreateGlyphContours(polygon1, contourEndIndices); //-------------------------- //TODO: review here, add hole or not // more than 1 contours, no hole => eg. i, j, ;, etc // more than 1 contours, with hole => eg. a,e , etc //clockwise => not hole _waitingHoles.Clear(); int cntCount = flattenContours.Count; Poly2Tri.Polygon mainPolygon = null; // //this version if it is a hole=> we add it to main polygon //TODO: add to more proper polygon *** //eg i //-------------------------- List <Poly2Tri.Polygon> otherPolygons = null; for (int n = 0; n < cntCount; ++n) { GlyphContour cnt = flattenContours[n]; if (cnt.IsClockwise()) { //not a hole if (mainPolygon == null) { //if we don't have mainPolygon before //this is main polygon mainPolygon = CreatePolygon(cnt.flattenPoints); if (_waitingHoles.Count > 0) { //flush all waiting holes to the main polygon int j = _waitingHoles.Count; for (int i = 0; i < j; ++i) { mainPolygon.AddHole(_waitingHoles[i]); } _waitingHoles.Clear(); } } else { //if we already have a main polygon //then this is another sub polygon //IsHole is correct after we Analyze() the glyph contour Poly2Tri.Polygon subPolygon = CreatePolygon(cnt.flattenPoints); if (otherPolygons == null) { otherPolygons = new List <Poly2Tri.Polygon>(); } otherPolygons.Add(subPolygon); } } else { //this is a hole Poly2Tri.Polygon subPolygon = CreatePolygon(cnt.flattenPoints); if (mainPolygon == null) { //add to waiting polygon _waitingHoles.Add(subPolygon); } else { //add to mainPolygon mainPolygon.AddHole(subPolygon); } } } if (_waitingHoles.Count > 0) { throw new NotSupportedException(); } //------------------------------------------ //2. tri angulate Poly2Tri.P2T.Triangulate(mainPolygon); //that poly is triangulated Poly2Tri.Polygon[] subPolygons = (otherPolygons != null) ? otherPolygons.ToArray() : null; if (subPolygons != null) { for (int i = subPolygons.Length - 1; i >= 0; --i) { Poly2Tri.P2T.Triangulate(subPolygons[i]); } } if (mainPolygon == null) { } return(mainPolygon); }
/// <summary> /// triangulate polygon using Poly2Tri library /// http://code.google.com/p/poly2tri/ /// </summary> /// <returns>index list of triangle points</returns> public List<int> Triangulate() { 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)); } Poly2Tri.P2T.Triangulate(p2tPolygon); var triangles = p2tPolygon.Triangles.Count; var indices = new List<int>(triangles*3); Points = new Vector2[triangles*3]; var j = 0; 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; j += 3; } return indices; }
private void CutPoly(List <NavmeshCut> InNavmeshCuts, Int3[] verts, int[] tris, ref Int3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, Int3[] extraShape, Int3 cuttingOffset, Bounds realBounds, MyTileHandler.CutMode mode, int perturbate = 0) { if (verts.Length == 0 || tris.Length == 0) { outVCount = 0; outTCount = 0; outTrisArr = new int[0]; outVertsArr = new Int3[0]; return; } List <IntPoint> list = null; if (extraShape == null && (mode & MyTileHandler.CutMode.CutExtra) != 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & MyTileHandler.CutMode.CutExtra) != 0) { list = new List <IntPoint>(extraShape.Length); for (int i = 0; i < extraShape.Length; i++) { list.Add(new IntPoint((long)(extraShape[i].x + cuttingOffset.x), (long)(extraShape[i].z + cuttingOffset.z))); } } List <IntPoint> list2 = new List <IntPoint>(5); Dictionary <TriangulationPoint, int> dictionary = new Dictionary <TriangulationPoint, int>(); List <PolygonPoint> list3 = new List <PolygonPoint>(); IntRect b = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z); for (int j = 0; j < verts.Length; j++) { b = b.ExpandToContain(verts[j].x, verts[j].z); } List <Int3> list4 = ListPool <Int3> .Claim(verts.Length * 2); List <int> list5 = ListPool <int> .Claim(tris.Length); PolyTree polyTree = new PolyTree(); List <List <IntPoint> > list6 = new List <List <IntPoint> >(); Stack <Poly2Tri.Polygon> stack = new Stack <Poly2Tri.Polygon>(); if (this.clipper == null) { this.clipper = new Clipper(0); } this.clipper.ReverseSolution = true; this.clipper.StrictlySimple = true; List <NavmeshCut> listView; if (mode == MyTileHandler.CutMode.CutExtra) { listView = new List <NavmeshCut>(); } else { listView = new List <NavmeshCut>(InNavmeshCuts); } List <int> list7 = ListPool <int> .Claim(); List <IntRect> list8 = ListPool <IntRect> .Claim(); List <Int2> list9 = ListPool <Int2> .Claim(); List <List <IntPoint> > list10 = new List <List <IntPoint> >(); List <bool> list11 = ListPool <bool> .Claim(); List <bool> list12 = ListPool <bool> .Claim(); if (perturbate > 10) { Debug.LogError("Too many perturbations aborting : " + mode); Debug.Break(); outVCount = verts.Length; outTCount = tris.Length; outTrisArr = tris; outVertsArr = verts; return; } System.Random random = null; if (perturbate > 0) { random = new System.Random(); } for (int k = 0; k < listView.Count; k++) { Bounds bounds = listView[k].GetBounds(); Int3 vInt = (Int3)bounds.min + cuttingOffset; Int3 vInt2 = (Int3)bounds.max + cuttingOffset; IntRect a = new IntRect(vInt.x, vInt.z, vInt2.x, vInt2.z); if (IntRect.Intersects(a, b)) { Int2 vInt3 = new Int2(0, 0); if (perturbate > 0) { vInt3.x = random.Next() % 6 * perturbate - 3 * perturbate; if (vInt3.x >= 0) { vInt3.x++; } vInt3.y = random.Next() % 6 * perturbate - 3 * perturbate; if (vInt3.y >= 0) { vInt3.y++; } } int count = list10.Count; listView[k].GetContour(list10); for (int l = count; l < list10.Count; l++) { List <IntPoint> list13 = list10[l]; if (list13.Count == 0) { Debug.LogError("Zero Length Contour"); list8.Add(default(IntRect)); list9.Add(new Int2(0, 0)); } else { IntRect intRect = new IntRect((int)list13[0].X + cuttingOffset.x, (int)list13[0].Y + cuttingOffset.y, (int)list13[0].X + cuttingOffset.x, (int)list13[0].Y + cuttingOffset.y); for (int m = 0; m < list13.Count; m++) { IntPoint intPoint = list13[m]; intPoint.X += (long)cuttingOffset.x; intPoint.Y += (long)cuttingOffset.z; if (perturbate > 0) { intPoint.X += (long)vInt3.x; intPoint.Y += (long)vInt3.y; } list13[m] = intPoint; intRect = intRect.ExpandToContain((int)intPoint.X, (int)intPoint.Y); } list9.Add(new Int2(vInt.y, vInt2.y)); list8.Add(intRect); list11.Add(listView[k].isDual); list12.Add(listView[k].cutsAddedGeom); } } } } List <NavmeshAdd> listView2 = new List <NavmeshAdd>(); Int3[] array = verts; int[] array2 = tris; int num = -1; int n = -3; Int3[] array3 = null; Int3[] array4 = null; Int3 vInt4 = Int3.zero; if (listView2.Count > 0) { array3 = new Int3[7]; array4 = new Int3[7]; vInt4 = (Int3)realBounds.extents; } while (true) { n += 3; while (n >= array2.Length) { num++; n = 0; if (num >= listView2.Count) { array = null; break; } if (array == verts) { array = null; } listView2[num].GetMesh(cuttingOffset, ref array, out array2); } if (array == null) { break; } Int3 vInt5 = array[array2[n]]; Int3 vInt6 = array[array2[n + 1]]; Int3 vInt7 = array[array2[n + 2]]; IntRect a2 = new IntRect(vInt5.x, vInt5.z, vInt5.x, vInt5.z); a2 = a2.ExpandToContain(vInt6.x, vInt6.z); a2 = a2.ExpandToContain(vInt7.x, vInt7.z); int num2 = Math.Min(vInt5.y, Math.Min(vInt6.y, vInt7.y)); int num3 = Math.Max(vInt5.y, Math.Max(vInt6.y, vInt7.y)); list7.Clear(); bool flag = false; for (int num4 = 0; num4 < list10.Count; num4++) { int x = list9[num4].x; int y = list9[num4].y; if (IntRect.Intersects(a2, list8[num4]) && y >= num2 && x <= num3 && (list12[num4] || num == -1)) { Int3 vInt8 = vInt5; vInt8.y = x; Int3 vInt9 = vInt5; vInt9.y = y; list7.Add(num4); flag |= list11[num4]; } } if (list7.Count == 0 && (mode & MyTileHandler.CutMode.CutExtra) == 0 && (mode & MyTileHandler.CutMode.CutAll) != 0 && num == -1) { list5.Add(list4.Count); list5.Add(list4.Count + 1); list5.Add(list4.Count + 2); list4.Add(vInt5); list4.Add(vInt6); list4.Add(vInt7); } else { list2.Clear(); if (num == -1) { list2.Add(new IntPoint((long)vInt5.x, (long)vInt5.z)); list2.Add(new IntPoint((long)vInt6.x, (long)vInt6.z)); list2.Add(new IntPoint((long)vInt7.x, (long)vInt7.z)); } else { array3[0] = vInt5; array3[1] = vInt6; array3[2] = vInt7; int num5 = Utility.ClipPolygon(array3, 3, array4, 1, 0, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * vInt4.x, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array3, num5, array4, 1, 0, 2); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * vInt4.z, 2); if (num5 == 0) { continue; } for (int num6 = 0; num6 < num5; num6++) { list2.Add(new IntPoint((long)array3[num6].x, (long)array3[num6].z)); } } dictionary.Clear(); Int3 vInt10 = vInt6 - vInt5; Int3 vInt11 = vInt7 - vInt5; Int3 vInt12 = vInt10; Int3 vInt13 = vInt11; vInt12.y = 0; vInt13.y = 0; for (int num7 = 0; num7 < 16; num7++) { if (((int)mode >> (num7 & 31) & (int)MyTileHandler.CutMode.CutAll) != 0) { if (1 << num7 == 1) { this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num8 = 0; num8 < list7.Count; num8++) { this.clipper.AddPolygon(list10[list7[num8]], PolyType.ptClip); } polyTree.Clear(); this.clipper.Execute(ClipType.ctDifference, polyTree, 0, PolyFillType.pftNonZero); } else if (1 << num7 == 2) { if (!flag) { goto IL_1173; } this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num9 = 0; num9 < list7.Count; num9++) { if (list11[list7[num9]]) { this.clipper.AddPolygon(list10[list7[num9]], PolyType.ptClip); } } list6.Clear(); this.clipper.Execute(0, list6, 0, PolyFillType.pftNonZero); this.clipper.Clear(); for (int num10 = 0; num10 < list6.Count; num10++) { this.clipper.AddPolygon(list6[num10], (PolyType)((!Clipper.Orientation(list6[num10])) ? 0 : 1)); } for (int num11 = 0; num11 < list7.Count; num11++) { if (!list11[list7[num11]]) { this.clipper.AddPolygon(list10[list7[num11]], PolyType.ptClip); } } polyTree.Clear(); this.clipper.Execute(ClipType.ctDifference, polyTree, 0, PolyFillType.pftNonZero); } else if (1 << num7 == 4) { this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); this.clipper.AddPolygon(list, PolyType.ptClip); polyTree.Clear(); this.clipper.Execute(0, polyTree, 0, PolyFillType.pftNonZero); } for (int num12 = 0; num12 < polyTree.ChildCount; num12++) { PolyNode polyNode = polyTree.Childs[num12]; List <IntPoint> contour = polyNode.Contour; List <PolyNode> childs = polyNode.Childs; if (childs.Count == 0 && contour.Count == 3 && num == -1) { for (int num13 = 0; num13 < contour.Count; num13++) { Int3 vInt14 = new Int3((int)contour[num13].X, 0, (int)contour[num13].Y); double num14 = (double)(vInt6.z - vInt7.z) * (double)(vInt5.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt5.z - vInt7.z); if (num14 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num15 = ((double)(vInt6.z - vInt7.z) * (double)(vInt14.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt14.z - vInt7.z)) / num14; double num16 = ((double)(vInt7.z - vInt5.z) * (double)(vInt14.x - vInt7.x) + (double)(vInt5.x - vInt7.x) * (double)(vInt14.z - vInt7.z)) / num14; vInt14.y = (int)Math.Round(num15 * (double)vInt5.y + num16 * (double)vInt6.y + (1.0 - num15 - num16) * (double)vInt7.y); list5.Add(list4.Count); list4.Add(vInt14); } } } else { Poly2Tri.Polygon polygon = null; int num17 = -1; for (List <IntPoint> list14 = contour; list14 != null; list14 = ((num17 >= childs.Count) ? null : childs[num17].Contour)) { list3.Clear(); for (int num18 = 0; num18 < list14.Count; num18++) { PolygonPoint polygonPoint = new PolygonPoint((double)list14[num18].X, (double)list14[num18].Y); list3.Add(polygonPoint); Int3 vInt15 = new Int3((int)list14[num18].X, 0, (int)list14[num18].Y); double num19 = (double)(vInt6.z - vInt7.z) * (double)(vInt5.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt5.z - vInt7.z); if (num19 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num20 = ((double)(vInt6.z - vInt7.z) * (double)(vInt15.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt15.z - vInt7.z)) / num19; double num21 = ((double)(vInt7.z - vInt5.z) * (double)(vInt15.x - vInt7.x) + (double)(vInt5.x - vInt7.x) * (double)(vInt15.z - vInt7.z)) / num19; vInt15.y = (int)Math.Round(num20 * (double)vInt5.y + num21 * (double)vInt6.y + (1.0 - num20 - num21) * (double)vInt7.y); dictionary[polygonPoint] = list4.Count; list4.Add(vInt15); } } Poly2Tri.Polygon polygon2; if (stack.Count > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list3); } else { polygon2 = new Poly2Tri.Polygon(list3); } if (polygon == null) { polygon = polygon2; } else { polygon.AddHole(polygon2); } num17++; } try { P2T.Triangulate(polygon); } catch (PointOnEdgeException) { Debug.LogWarning(string.Concat(new object[] { "PointOnEdgeException, perturbating vertices slightly ( at ", num7, " in ", mode, ")" })); this.CutPoly(InNavmeshCuts, verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1); return; } for (int num22 = 0; num22 < polygon.Triangles.Count; num22++) { DelaunayTriangle delaunayTriangle = polygon.Triangles[num22]; list5.Add(dictionary[delaunayTriangle.Points._0]); list5.Add(dictionary[delaunayTriangle.Points._1]); list5.Add(dictionary[delaunayTriangle.Points._2]); } if (polygon.Holes != null) { for (int num23 = 0; num23 < polygon.Holes.Count; num23++) { polygon.Holes[num23].Points.Clear(); polygon.Holes[num23].ClearTriangles(); if (polygon.Holes[num23].Holes != null) { polygon.Holes[num23].Holes.Clear(); } stack.Push(polygon.Holes[num23]); } } polygon.ClearTriangles(); if (polygon.Holes != null) { polygon.Holes.Clear(); } polygon.Points.Clear(); stack.Push(polygon); } } } IL_1173 :; } } } Dictionary <Int3, int> dictionary2 = this.cached_Int3_int_dict; dictionary2.Clear(); if (this.cached_int_array.Length < list4.Count) { this.cached_int_array = new int[Math.Max(this.cached_int_array.Length * 2, list4.Count)]; } int[] array5 = this.cached_int_array; int num24 = 0; for (int num25 = 0; num25 < list4.Count; num25++) { int num26; if (!dictionary2.TryGetValue(list4[num25], out num26)) { dictionary2.Add(list4[num25], num24); array5[num25] = num24; list4[num24] = list4[num25]; num24++; } else { array5[num25] = num26; } } outTCount = list5.Count; if (outTrisArr == null || outTrisArr.Length < outTCount) { outTrisArr = new int[outTCount]; } for (int num27 = 0; num27 < outTCount; num27++) { outTrisArr[num27] = array5[list5[num27]]; } outVCount = num24; if (outVertsArr == null || outVertsArr.Length < outVCount) { outVertsArr = new Int3[outVCount]; } for (int num28 = 0; num28 < outVCount; num28++) { outVertsArr[num28] = list4[num28]; } for (int num29 = 0; num29 < listView.Count; num29++) { listView[num29].UsedForCut(); } ListPool <Int3> .Release(list4); ListPool <int> .Release(list5); ListPool <int> .Release(list7); ListPool <Int2> .Release(list9); ListPool <bool> .Release(list11); ListPool <bool> .Release(list12); ListPool <IntRect> .Release(list8); }
//------- public void Triangulate <T>(IList <T> contours, List <Poly2Tri.Polygon> outputPolygons) where T : IContour { _waitingHoles.Clear(); _flattenContours.Clear(); //-------------------------- //TODO: review here, add hole or not // more than 1 contours, no hole => eg. i, j, ;, etc // more than 1 contours, with hole => eg. a,e , etc //clockwise => not hole int cntCount = contours.Count; Poly2Tri.Polygon mainPolygon = null; // //this version if it is a hole=> we add it to main polygon //TODO: add to more proper polygon *** //eg i //-------------------------- List <Poly2Tri.Polygon> otherPolygons = null; for (int n = 0; n < cntCount; ++n) { IContour cnt = contours[n]; bool cntIsMainPolygon = cnt.IsClockwise; //if (yAxisFlipped) //{ // cntIsMainPolygon = !cntIsMainPolygon; //} if (cntIsMainPolygon) { //main polygon //not a hole if (mainPolygon == null) { //if we don't have mainPolygon before //this is main polygon mainPolygon = CreatePolygon(cnt); if (_waitingHoles.Count > 0) { //flush all waiting holes to the main polygon int j = _waitingHoles.Count; for (int i = 0; i < j; ++i) { mainPolygon.AddHole(_waitingHoles[i]); } _waitingHoles.Clear(); } } else { //if we already have a main polygon //then this is another sub polygon //IsHole is correct after we Analyze() the glyph contour Poly2Tri.Polygon subPolygon = CreatePolygon(cnt); if (otherPolygons == null) { otherPolygons = new List <Poly2Tri.Polygon>(); } otherPolygons.Add(subPolygon); } } else { //this is a hole Poly2Tri.Polygon subPolygon = CreatePolygon(cnt); if (mainPolygon == null) { //add to waiting polygon _waitingHoles.Add(subPolygon); } else { //add to mainPolygon mainPolygon.AddHole(subPolygon); } } } if (_waitingHoles.Count > 0) { throw new NotSupportedException(); } //------------------------------------------ //2. tri angulate Poly2Tri.P2T.Triangulate(mainPolygon); //that poly is triangulated outputPolygons.Add(mainPolygon); if (otherPolygons != null) { outputPolygons.AddRange(otherPolygons); for (int i = otherPolygons.Count - 1; i >= 0; --i) { Poly2Tri.P2T.Triangulate(otherPolygons[i]); } } //------------------------------------------ _waitingHoles.Clear(); _flattenContours.Clear(); }
public void PreparePolygons(float[] flattenPolygonXYs, int[] contourEndIndices, List <Poly2Tri.Polygon> outputPolygons) { _waitingHoles.Clear(); _flattenContours.Clear(); _otherPolygons.Clear(); // SeparateToFlattenContourList(flattenPolygonXYs, contourEndIndices, _flattenContours); //-------------------------- //TODO: review here, add hole or not // more than 1 contours, no hole => eg. i, j, ;, etc // more than 1 contours, with hole => eg. a,e , etc //clockwise => not hole int cntCount = _flattenContours.Count; Poly2Tri.Polygon mainPolygon = null; // //this version if it is a hole=> we add it to main polygon //TODO: add to more proper polygon *** //eg i //-------------------------- for (int n = 0; n < cntCount; ++n) { FlattenContour cnt = _flattenContours[n]; bool cntIsMainPolygon = YAxisPointDown ? !cnt.IsClockwise : cnt.IsClockwise; if (cntIsMainPolygon) { //main polygon //not a hole if (mainPolygon == null) { //if we don't have mainPolygon before //this is main polygon mainPolygon = CreatePolygon(cnt); if (_waitingHoles.Count > 0) { //flush all waiting holes to the main polygon int j = _waitingHoles.Count; for (int i = 0; i < j; ++i) { mainPolygon.AddHole(_waitingHoles[i]); } _waitingHoles.Clear(); } } else { //if we already have a main polygon //then this is another sub polygon //IsHole is correct after we Analyze() the glyph contour _otherPolygons.Add(CreatePolygon(cnt)); } } else { //this is a hole Poly2Tri.Polygon subPolygon = CreatePolygon(cnt); if (mainPolygon == null) { //add to waiting polygon _waitingHoles.Add(subPolygon); } else { //add to mainPolygon mainPolygon.AddHole(subPolygon); } } } if (_waitingHoles.Count > 0) { throw new NotSupportedException(); } outputPolygons.Add(mainPolygon); if (_otherPolygons.Count > 0) { outputPolygons.AddRange(_otherPolygons); } _waitingHoles.Clear(); _flattenContours.Clear(); _otherPolygons.Clear(); }
static void TriangulateConstrainedDelaunay(List <List <Vector3> > listlistPointsConstrainedDelaunay, List <List <int> > listlistHashValuesConstrainedDelaunay, bool bForceVertexSoup, FracturedObject fracturedComponent, bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash, int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg, List <int>[] aListIndicesPosInOut, List <VertexData> listVertexDataPosInOut, List <int>[] aListIndicesNegInOut, List <VertexData> listVertexDataNegInOut) { // Pass to two dimensional plane: Matrix4x4 mtxPlaneInverse = mtxPlane.inverse; List <List <Poly2Tri.Point2D> > listlistCapPoints = new List <List <Poly2Tri.Point2D> >(); List <List <Poly2Tri.PolygonPoint> > listlistCapPolygonPoints = new List <List <Poly2Tri.PolygonPoint> >(); List <Poly2Tri.Polygon> listCapPolygons = new List <Poly2Tri.Polygon>(); for (int i = 0; i < listlistPointsConstrainedDelaunay.Count; i++) { List <Poly2Tri.Point2D> listCapPoints = new List <Poly2Tri.Point2D>(); List <Poly2Tri.PolygonPoint> listCapPolygonsPoints = new List <Poly2Tri.PolygonPoint>(); foreach (Vector3 v3Vertex in listlistPointsConstrainedDelaunay[i]) { Vector3 v3VertexInPlane = mtxPlaneInverse.MultiplyPoint3x4(v3Vertex); listCapPoints.Add(new Poly2Tri.Point2D(v3VertexInPlane.x, v3VertexInPlane.z)); listCapPolygonsPoints.Add(new Poly2Tri.PolygonPoint(v3VertexInPlane.x, v3VertexInPlane.z)); } listlistCapPoints.Add(listCapPoints); listlistCapPolygonPoints.Add(listCapPolygonsPoints); listCapPolygons.Add(new Poly2Tri.Polygon(listCapPolygonsPoints)); } // Remove close vertices float fPrecisionFix = Mathf.Max(Parameters.EPSILONCAPPRECISIONMIN, fracturedComponent.CapPrecisionFix); if (fPrecisionFix > 0.0f) { for (int nCap = 0; nCap < listlistCapPolygonPoints.Count; nCap++) { double lastX = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].X; double lastY = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].Y; bool bDeleteCap = false; for (int nVertex = 0; nVertex < listlistCapPolygonPoints[nCap].Count; nVertex++) { double vecX = listlistCapPolygonPoints[nCap][nVertex].X - lastX; double vecY = listlistCapPolygonPoints[nCap][nVertex].Y - lastY; if (System.Math.Sqrt(vecX * vecX + vecY * vecY) < fPrecisionFix) { listlistCapPolygonPoints[nCap].RemoveAt(nVertex); nVertex--; if (listlistCapPolygonPoints[nCap].Count < 3) { bDeleteCap = true; break; } } else { lastX = listlistCapPolygonPoints[nCap][nVertex].X; lastY = listlistCapPolygonPoints[nCap][nVertex].Y; } } if (bDeleteCap) { listlistCapPolygonPoints.RemoveAt(nCap); nCap--; } } } if (listlistCapPolygonPoints.Count == 0) { return; } // Search if one of the caps is contained in the other. If this happens we will mark the big one as the polygon and the rest as holes int nSuperPolygon = -1; Poly2Tri.Polygon polygonContainer = null; if (bForceVertexSoup == false) { for (int i = 0; i < listlistCapPolygonPoints.Count; i++) { for (int j = 0; j < listlistCapPolygonPoints.Count; j++) { if (i != j && listlistCapPoints[i].Count >= 3 && listlistCapPoints[j].Count >= 3) { if (Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[i], listCapPolygons[i].Bounds, listlistCapPoints[j], listCapPolygons[j].Bounds, true)) { nSuperPolygon = i; break; } else if (Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[j], listCapPolygons[j].Bounds, listlistCapPoints[i], listCapPolygons[i].Bounds, true)) { nSuperPolygon = j; break; } } } } // Add holes if this is a cap with holes if (nSuperPolygon != -1) { polygonContainer = listCapPolygons[nSuperPolygon]; for (int i = 0; i < listlistCapPolygonPoints.Count; i++) { if (i != nSuperPolygon && listCapPolygons[i].Count >= 3) { polygonContainer.AddHole(listCapPolygons[i]); } } } } // Triangulate bool bTriangulatedWithHoles = false; if (polygonContainer != null && bForceVertexSoup == false) { // Polygon with holes try { Poly2Tri.P2T.Triangulate(polygonContainer); if (polygonContainer.Triangles != null) { List <Vector3> listMeshVertices = new List <Vector3>(); List <int> listMeshIndices = new List <int>(); CreateIndexedMesh(polygonContainer.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } bTriangulatedWithHoles = true; } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using hole triangulation (holes = " + listlistCapPolygonPoints.Count + "). Trying to use constrained delaunay."); } bTriangulatedWithHoles = false; } } if (bTriangulatedWithHoles == false) { if (bForceVertexSoup) { // Vertex soup List <Poly2Tri.TriangulationPoint> listPoints = new List <Poly2Tri.TriangulationPoint>(); if (listlistCapPolygonPoints.Count > 0) { foreach (Poly2Tri.PolygonPoint polyPoint in listlistCapPolygonPoints[0]) { listPoints.Add(polyPoint); } try { if (listPoints.Count >= 3) { Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints); Poly2Tri.P2T.Triangulate(ps); if (ps.Triangles != null) { List <Vector3> listMeshVertices = new List <Vector3>(); List <int> listMeshIndices = new List <int>(); CreateIndexedMesh(ps.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } } } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using vertex soup triangulation."); } } } } else { // Use constrained delaunay triangulation int nPoly = 0; foreach (List <Poly2Tri.PolygonPoint> listPolyPoints in listlistCapPolygonPoints) { IList <Poly2Tri.DelaunayTriangle> listTriangles = null; Poly2Tri.Polygon polygon = null; try { if (listPolyPoints.Count >= 3) { polygon = new Poly2Tri.Polygon(listPolyPoints); Poly2Tri.P2T.Triangulate(polygon); listTriangles = polygon.Triangles; } } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using polygon triangulation of cap polygon " + nPoly + ". Trying to use non constrained"); } listTriangles = null; } if (listTriangles == null) { List <Poly2Tri.TriangulationPoint> listPoints = new List <Poly2Tri.TriangulationPoint>(); foreach (Poly2Tri.PolygonPoint polyPoint in listPolyPoints) { listPoints.Add(polyPoint); } try { if (listPoints.Count >= 3) { Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints); Poly2Tri.P2T.Triangulate(ps); listTriangles = ps.Triangles; } } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using non constrained triangulation of cap polygon " + nPoly + ". Skipping"); } } } if (listTriangles != null) { List <Vector3> listMeshVertices = new List <Vector3>(); List <int> listMeshIndices = new List <int>(); CreateIndexedMesh(listTriangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } nPoly++; } } } }
/// <summary> /// create GlyphDynamicOutline from flatten contours /// </summary> /// <param name="flattenContours"></param> /// <returns></returns> GlyphDynamicOutline CreateDynamicOutline(List <GlyphContour> flattenContours) { //-------------------------- //TODO: review here, add hole or not // more than 1 contours, no hole => eg. i, j, ;, etc // more than 1 contours, with hole => eg. a,e , etc //closewise => not hole waitingHoles.Clear(); int cntCount = flattenContours.Count; Poly2Tri.Polygon mainPolygon = null; // //this version if it is a hole=> we add it to main polygon //TODO: add to more proper polygon *** //eg i //-------------------------- List <Poly2Tri.Polygon> otherPolygons = null; for (int n = 0; n < cntCount; ++n) { GlyphContour cnt = flattenContours[n]; if (cnt.IsClosewise()) { //not a hole if (mainPolygon == null) { //if we don't have mainPolygon before //this is main polygon mainPolygon = CreatePolygon(cnt.flattenPoints); if (waitingHoles.Count > 0) { //flush all waiting holes to the main polygon int j = waitingHoles.Count; for (int i = 0; i < j; ++i) { mainPolygon.AddHole(waitingHoles[i]); } waitingHoles.Clear(); } } else { //if we already have a main polygon //then this is another sub polygon //IsHole is correct after we Analyze() the glyph contour Poly2Tri.Polygon subPolygon = CreatePolygon(cnt.flattenPoints); if (otherPolygons == null) { otherPolygons = new List <Poly2Tri.Polygon>(); } otherPolygons.Add(subPolygon); } } else { //this is a hole Poly2Tri.Polygon subPolygon = CreatePolygon(cnt.flattenPoints); if (mainPolygon == null) { //add to waiting polygon waitingHoles.Add(subPolygon); } else { //add to mainPolygon mainPolygon.AddHole(subPolygon); } } } if (waitingHoles.Count > 0) { throw new NotSupportedException(); } //------------------------------------------ //2. tri angulate Poly2Tri.P2T.Triangulate(mainPolygon); //that poly is triangulated Poly2Tri.Polygon[] subPolygons = (otherPolygons != null) ? otherPolygons.ToArray() : null; if (subPolygons != null) { for (int i = subPolygons.Length - 1; i >= 0; --i) { Poly2Tri.P2T.Triangulate(subPolygons[i]); } } //3. intermediate outline is used inside this lib //and then convert intermediate outline to dynamic outline return(new GlyphDynamicOutline( new GlyphIntermediateOutline(flattenContours, mainPolygon, subPolygons))); }
public static GameObject OSMtoGameObject2(string OSMid, Vector3 MinPointOnMap, Bounds bounds, MapProperties properties, string connPostGreSql, OSMShape shape = OSMShape.Way) { if (rand == null) { rand = new Random((int)DateTime.Now.Ticks); } if (properties == null) { properties = Properties; } var minmaxX = properties.minMaxX; var minmaxY = properties.minMaxY; int direction = -1; float LineWidth = properties.RoadLineThickness; float BuildingWidth = properties.BuildingLineThickness; float height = properties.BuildingHeight; if (height < 4) { height = 4; } var FirstWay = OSMid; if (shape == OSMShape.Way) { var w = new Way(FirstWay); List <OsmNode> WayNodes; List <Tag> WayTags; using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql)) { con.Open(); WayNodes = w.GetNodesPostgreSQL(FirstWay, con); WayTags = w.GetTagsPostgreSQL(FirstWay, con); con.Close(); } if (WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "landuse" || i.KeyValueSQL[0].ToLower() == "building" || i.KeyValueSQL[0].ToLower() == "highway").Count() != 0) { var tempPoints = new Vector3[WayNodes.Count]; int counter = 0; foreach (var node in WayNodes) { var result = CoordinateConvertor.SimpleInterpolation((float)node.PositionSQL.Lat, (float)node.PositionSQL.Lon, bounds, minmaxX, minmaxY); // Testing the correct direction tempPoints[counter] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap; counter++; } WayNodes = null; var building = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "building"); var highwayType = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "highway"); WayTags = null; if (building.Count() != 0) { #region Buildings // Check if it has overlapping start and ending points. // NOTE: Replaced with the code to remove all the duplicates, not only the endpoints. // Checking for duplicates: tempPoints = tempPoints.ToArray().RemoveDuplicates(); var Skip = false; if (tempPoints.Length <= 2) { // Buildings that are too small to show such as 76844368 // http://www.openstreetmap.org/browse/way/76844368 // "A weird building were found and ignored. FirstWay \nRelated url: http://www.openstreetmap.org/browse/way/{0}" Skip = true; // continue; } if (!Skip) { var p2d = tempPoints.ToCPoint2D(); // TODO bug in the cpolygon, probably duplicates var shp = new PolygonCuttingEar.CPolygonShape(p2d); shp.CutEar(); p2d = null; GC.Collect(); // TODO: var randHeight = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height); var randMaterial = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building"; var resultedGameObject = shp.GenerateShapeUVedWithWalls_Balanced( CoordinateConvertor.OSMType.Polygon, FirstWay, "Building", "Building", randMaterial, height + randHeight, height + 7, true); return(resultedGameObject); } #endregion } else { if (highwayType.Count() != 0) { #region Roads var hwtype = highwayType.First(); //Console.WriteLine("Generating roads..id=" + FirstWay); switch (hwtype.KeyValueSQL[1]) { case "cycleway": { var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(2f), properties.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.CycleWayMaterial.Name, -0.01f); // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj")); return(resultedGameObject); } case "footway": case "path": case "pedestrian": { var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(4f), properties.FootwayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.FootWayMaterial.Name, -0.01f); // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj")); return(resultedGameObject); } case "steps": { var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(4f), properties.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.StepsMaterial.Name, -0.01f); return(resultedGameObject); } // Miguel R.C. commented these lines. // Reason: Why breaking in the case "motorway"? That results in some roads missing when generating scenarios. // With these lines commented, the motorways will be generated in the default case. //case "motorway": // { // break; // } default: { var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(0.5f), properties.RoadWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.RoadMaterial.Name, 0f); return(resultedGameObject); } } #endregion } } } } else if (shape == OSMShape.Relation) // It is probably a multi-polygon building defined in a relation. { List <OsmNode[]> OuterNodes; List <OsmNode> OuterWay; List <OsmNode[]> InnerNodes; List <Tag> tags; Relation r = new Relation(FirstWay); Way w = new Way(); using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql)) { con.Open(); tags = r.GetTagsPostgreSQL(con); var isMultiPolygon = tags.Exists(t => t.KeyValueSQL[0] == "type" && t.KeyValueSQL[1] == "multipolygon"); if (isMultiPolygon) { var Members = r.GetMembersPostgreSQLByType(r.id, 1, con); OuterNodes = Members .Where(m => m.Role.ToLower() == Member.RoleOuter) .OrderBy(o => o.order) .Select(m => w.GetNodesPostgreSQL(m.ReferenceId, connPostGreSql).ToArray()).ToList(); InnerNodes = Members .Where(m => m.Role.ToLower() == Member.RoleInner) .OrderBy(o => o.order) .Select(m => w.GetNodesPostgreSQL(m.ReferenceId, connPostGreSql).ToArray()).ToList(); OuterWay = new List <OsmNode>(); foreach (var nodelist in OuterNodes) { OuterWay.AddRange(nodelist); } var tempPointsOuterPoints = new Vector3[OuterWay.Count]; int counter = 0; foreach (var node in OuterWay) { var result = CoordinateConvertor.SimpleInterpolation((float)node.PositionSQL.Lat, (float)node.PositionSQL.Lon, bounds, minmaxX, minmaxY); // Testing the correct direction tempPointsOuterPoints[counter] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap; counter++; } List <Vector3[]> holes = new List <Vector3[]>(); for (int i = 0; i < InnerNodes.Count; i++) { holes.Add(new Vector3[InnerNodes[i].Length]); for (int j = 0; j < InnerNodes[i].Length; j++) { var result = CoordinateConvertor.SimpleInterpolation((float)InnerNodes[i][j].PositionSQL.Lat, (float)InnerNodes[i][j].PositionSQL.Lon, bounds, minmaxX, minmaxY); // Testing the correct direction holes[i][j] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap; } } var outerpolypoints = tempPointsOuterPoints.Select(s => new Poly2Tri.PolygonPoint(s.x, s.z)); Poly2Tri.Polygon poly = new Poly2Tri.Polygon(outerpolypoints); // TODO: poly.IsPointInside() check the holes against all pieces var innerspolypoints = new List <Poly2Tri.PolygonPoint[]>(); for (int i = 0; i < holes.Count; i++) { var currentInner = holes[i].Select(s => new Poly2Tri.PolygonPoint(s.x, s.z)).ToArray(); innerspolypoints.Add(currentInner); poly.AddHole(new Poly2Tri.Polygon(currentInner)); } Poly2Tri.P2T.Triangulate(poly); var randHeight = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height); var randMaterial = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building"; var resultedGameObject = poly.GenerateShapeUVedWithWalls_Balanced( CoordinateConvertor.OSMType.Relation, FirstWay, "Building", "Building", randMaterial, height + randHeight, height + 7, true); return(resultedGameObject); } con.Close(); } } return(null); }