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; }
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); }
public static List <Polygon> concaveToConvex(Polygon concave) { List <Polygon> result = new List <Polygon>(); IVector3d normal = concave.vertices[0].normal.clone(); bool cw = !Extrude.isCCW(concave); Poly2Tri.Polygon p = fromCSGPolygon(concave); Poly2Tri.Poly2Tri.triangulate(p); List <Poly2Tri.DelaunayTriangle> triangles = p.getTriangles(); List <Vertex> triPoints = new List <Vertex>(); foreach (Poly2Tri.DelaunayTriangle t in triangles) { int counter = 0; foreach (Poly2Tri.TriangulationPoint tp in t.points) { triPoints.Add(new Vertex( Vector3d.xyz(tp.getX(), tp.getY(), tp.getZ()), normal)); if (counter == 2) { if (!cw) { triPoints.Reverse(); } Polygon poly = new Polygon( triPoints, concave.getStorage()); result.Add(poly); counter = 0; triPoints = new List <Vertex>(); } else { counter++; } } } return(result); }
void DrawSimpleRectExample(Painter painter) { Poly2Tri.TriangulationPoint[] points = 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(points); Poly2Tri.P2T.Triangulate(polygon); painter.StrokeColor = Color.Black; DrawPoly2TriPolygon(painter, new List <Poly2Tri.Polygon>() { polygon }); }
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 Poly2Tri.Polygon GetTriangles(PolygonClosedD2D polygons) { var mainPolygon = new Poly2Tri.Polygon(polygons.Points.Select(pt => new Poly2Tri.PolygonPoint(pt.X, pt.Y))); Poly2Tri.P2T.Triangulate(mainPolygon); return mainPolygon; }
/// <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 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); }
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 static Mesh Retriangulate(VoxelizationInput input, Mesh mesh, out List <List <Edge> > debugLoops) { debugLoops = new List <List <Edge> >(); try { Triangle[] triangles = Triangle.ToTriangleArray(mesh.Indicies, mesh.Vertices); Debug.WriteLine("Sorting triangles based on plane."); List <PolygonTriangles> planeLookup = SortTrianglesIntoPlanes(triangles); Debug.WriteLine("Triangles sorted by planes: Done."); List <Vector4> processedVerticies = new List <Vector4>(); List <int> processedIndicies = new List <int>(); foreach (PolygonTriangles polygon in planeLookup) { #if DEBUGGING_TJUNCTIONS if (!Vector3Ex.AlmostEquals(polygon.Plane.Normal, Vector3.UnitY)) { continue; } #endif // Before we can begin margining edges we need to ensure that all shared collinear edges // have a mate, one thing that can prevent this is the presence of T-Junctions, so first // we need to fix them by splitting polygons that produce them. polygon.Triangles = FindAndFixTJuntions(input, polygon.Triangles); // We build a list of distinctive edges because a distinctive edge is either part of the inner loop // or the outer loop of a group of polygons, because if two polygons share an edge that are co-planer // that edge can't be on the inside or the outside of the plane. List <Edge> distinctEdges = FindDistinctiveEdges(input, polygon.Triangles); debugLoops.Add(distinctEdges.ToList()); // Merge the edges together that are collinear. List <List <Edge> > outterLoops = FindOuterLoops(distinctEdges); //allLoops.AddRange(outterLoops); Vector3 right = Vector3Ex.GetRight(polygon.Plane.Normal); Vector3 U, V; Vector3Ex.GetBasisVectors(polygon.Plane.Normal, right, out U, out V); Vector3 planeOrigin = polygon.Plane.PointOnPlane; foreach (List <Edge> outterEdgeLoop in outterLoops) { List <Vector2> outerLoopTransformed = new List <Vector2>(); for (int i = 0; i < outterEdgeLoop.Count; i++) { Edge e = outterEdgeLoop[i]; Vector2 uv = Vector3Ex.Calc2DPoint(e.v0, U, V); outerLoopTransformed.Add(uv); } //Debug.Assert(outerLoopTransformed.Count > 2); if (outerLoopTransformed.Count > 2) { List <Poly2Tri.PolygonPoint> polyPoints = new List <Poly2Tri.PolygonPoint>(); foreach (var pt in outerLoopTransformed) { polyPoints.Add(new Poly2Tri.PolygonPoint(pt.X, pt.Y)); } Poly2Tri.Polygon p = new Poly2Tri.Polygon(polyPoints); Poly2Tri.P2T.Triangulate(Poly2Tri.TriangulationAlgorithm.DTSweep, p); int currentVerticies = processedVerticies.Count; foreach (var dt in p.Triangles) { processedIndicies.Add((currentVerticies + 0)); processedIndicies.Add((currentVerticies + 1)); processedIndicies.Add((currentVerticies + 2)); Vector3 pt0 = (((float)dt.Points._0.X * U) + ((float)dt.Points._0.Y * V)) - planeOrigin; Vector3 pt1 = (((float)dt.Points._1.X * U) + ((float)dt.Points._1.Y * V)) - planeOrigin; Vector3 pt2 = (((float)dt.Points._2.X * U) + ((float)dt.Points._2.Y * V)) - planeOrigin; processedVerticies.Add(new Vector4(pt0, 1)); processedVerticies.Add(new Vector4(pt1, 1)); processedVerticies.Add(new Vector4(pt2, 1)); currentVerticies += 3; } } else { Debug.WriteLine("outer loop problem!"); } } Debug.WriteLine("Distinct Edges " + processedIndicies.Count / 3); } Mesh retriangulatedMesh = new Mesh(); retriangulatedMesh.Vertices = processedVerticies.ToArray(); retriangulatedMesh.Indicies = processedIndicies.ToArray(); return(retriangulatedMesh); } catch (Exception) { return(null); } }
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++; } } } }
void DrawOutput() { if (_g == null) { return; } //----------- //for GDI+ only bool drawInvert = chkInvert.Checked; int viewHeight = this.panel1.Height; //----------- //show tess _g.Clear(Color.White); int[] contourEndIndices; float[] polygon1 = GetPolygonData(out contourEndIndices); if (polygon1 == null) { return; } // if (drawInvert) { var transformMat = new System.Drawing.Drawing2D.Matrix(); transformMat.Scale(1, -1); transformMat.Translate(0, -viewHeight); // polygon1 = TransformPoints(polygon1, transformMat); } using (Pen pen1 = new Pen(Color.LightGray, 6)) { int nn = polygon1.Length; int a = 0; PointF p0; PointF p1; int contourCount = contourEndIndices.Length; int startAt = 3; for (int cnt_index = 0; cnt_index < contourCount; ++cnt_index) { int endAt = contourEndIndices[cnt_index]; for (int m = startAt; m <= endAt;) { p0 = new PointF(polygon1[m - 3], polygon1[m - 2]); p1 = new PointF(polygon1[m - 1], polygon1[m]); _g.DrawLine(pen1, p0, p1); _g.DrawString(a.ToString(), this.Font, Brushes.Black, p0); m += 2; a++; } //close contour p0 = new PointF(polygon1[endAt - 1], polygon1[endAt]); p1 = new PointF(polygon1[startAt - 3], polygon1[startAt - 2]); _g.DrawLine(pen1, p0, p1); _g.DrawString(a.ToString(), this.Font, Brushes.Black, p0); // startAt = (endAt + 1) + 3; } } //---------------------------------------------------------------------------- //tess if (rdoTessSGI.Checked) { //SGI Tess Lib if (!_tessTool.TessPolygon(polygon1, _contourEnds)) { return; } //1. List <ushort> indexList = _tessTool.TessIndexList; //2. List <TessVertex2d> tempVertexList = _tessTool.TempVertexList; //3. int vertexCount = indexList.Count; //----------------------------- int orgVertexCount = polygon1.Length / 2; float[] vtx = new float[vertexCount * 2];//*** int n = 0; for (int p = 0; p < vertexCount; ++p) { ushort index = indexList[p]; if (index >= orgVertexCount) { //extra coord (newly created) TessVertex2d extraVertex = tempVertexList[index - orgVertexCount]; vtx[n] = (float)extraVertex.x; vtx[n + 1] = (float)extraVertex.y; } else { //original corrd vtx[n] = (float)polygon1[index * 2]; vtx[n + 1] = (float)polygon1[(index * 2) + 1]; } n += 2; } //----------------------------- //draw tess result int j = vtx.Length; for (int i = 0; i < j;) { var p0 = new PointF(vtx[i], vtx[i + 1]); var p1 = new PointF(vtx[i + 2], vtx[i + 3]); var p2 = new PointF(vtx[i + 4], vtx[i + 5]); _g.DrawLine(Pens.Red, p0, p1); _g.DrawLine(Pens.Red, p1, p2); _g.DrawLine(Pens.Red, p2, p0); i += 6; } } else { Poly2Tri.Polygon mainPolygon = Poly2TriExampleHelper.Triangulate(polygon1, contourEndIndices); foreach (Poly2Tri.DelaunayTriangle tri in mainPolygon.Triangles) { Poly2Tri.TriangulationPoint p0 = tri.P0; Poly2Tri.TriangulationPoint p1 = tri.P1; Poly2Tri.TriangulationPoint p2 = tri.P2; _g.DrawLine(Pens.Red, (float)p0.X, (float)p0.Y, (float)p1.X, (float)p1.Y); _g.DrawLine(Pens.Red, (float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y); _g.DrawLine(Pens.Red, (float)p2.X, (float)p2.Y, (float)p0.X, (float)p0.Y); } } }
public static GameObject GenerateShapeUVedWithWalls_Balanced(this Poly2Tri.Polygon shape, OSMType type, string Id, string other, string tag, string MaterialName = "Building", float WallHeight = 5, float MaximumHeight = 12, bool GenerateColliders = true) { GameObject gameObject = new GameObject(type + "|" + ((int)type) + "|" + Id + (!string.IsNullOrEmpty(other) ? "|" + other : "")); gameObject.tag = tag; if (shape.Triangles == null) { return(gameObject); } if (shape.Triangles.Count == 0) { return(gameObject); } List <Vector3> vertices = new List <Vector3>(); for (int i = 0; i < shape.Triangles.Count; i++) { vertices.AddRange(shape.Triangles[i].Points.Select(s => new Vector3((float)s.X, WallHeight, (float)s.Y)).Reverse()); } // This is the starting index in the vertex list that belongs to the walls. // We use this to distinguish between roof UVs and wall UVs. int WallStartIndex = vertices.Count; List <Vector2> UVs = new List <Vector2>(); var minXRoof = vertices.GetRange(0, WallStartIndex).Select(i => i.x).Min(); var minZRoof = vertices.GetRange(0, WallStartIndex).Select(i => i.z).Min(); var maxXRoof = vertices.GetRange(0, WallStartIndex).Select(i => i.x).Max(); var maxZRoof = vertices.GetRange(0, WallStartIndex).Select(i => i.z).Max(); // for (int i = 0; i < UVs.Length; i++) for (int i = 0; i < WallStartIndex; i++) { UVs.Add(new Vector2( linear(vertices[i].x, minXRoof, maxXRoof, 0, 1), linear(vertices[i].z, minZRoof, maxZRoof, 0, 0.5f) )); } Vector2[] UVRef = new Vector2[] { new Vector2(0, 0.5f), // top left new Vector2(1, 0.5f), // top right new Vector2(0, 0.5f + 0.5f * WallHeight / MaximumHeight), // bottom left new Vector2(1, 0.5f + 0.5f * WallHeight / MaximumHeight) // bottom right // new Vector2(0,1), // bottom left // new Vector2(1,1) // bottom right }; #region Outer wall Vector3 HeightVector = new Vector3(0, WallHeight, 0); Vector3[] OriginalVertices = shape.Points.Select(s => new Vector3((float)s.X, WallHeight, (float)s.Y)).ToArray(); // Generating Walls - Total: (OriginalVertices.Length)*4*3 for (int i = 0; i < OriginalVertices.Length - 1; i++) { Vector3 v1 = OriginalVertices[i]; Vector3 v2 = OriginalVertices[i + 1]; var dist = Vector3.Distance(v1, v2); //Debug.Log("Distance: "+dist); dist = dist.Clamp(0, 5); var UVratioTopRight = new Vector2(dist / 5, UVRef[1].y); var UVratioBottomRight = new Vector2(dist / 5, UVRef[3].y); Vector3 v3 = OriginalVertices[i] - HeightVector; Vector3 v4 = OriginalVertices[i + 1] - HeightVector; vertices.AddRange(new Vector3[] { v1, v2, v3 }); UVs.Add(UVRef[0]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); UVs.Add(UVRef[2]); vertices.AddRange(new Vector3[] { v3, v2, v4 }); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); UVs.Add(UVratioBottomRight); //UVs.Add(UVRef[3]); // Reverse vertices.AddRange(new Vector3[] { v1, v3, v2 }); UVs.Add(UVRef[0]); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); vertices.AddRange(new Vector3[] { v3, v4, v2 }); UVs.Add(UVRef[2]); UVs.Add(UVratioBottomRight); //UVs.Add(UVRef[3]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); } // Last Wall - Total: 4*3 Vector3 lv1 = OriginalVertices[OriginalVertices.Length - 1]; Vector3 lv2 = OriginalVertices[0]; var distlw = Vector3.Distance(lv1, lv2); //Debug.Log("Distance: "+distlw); distlw = distlw.Clamp(0, 5); var UVratioTopRightlw = new Vector2(distlw / 5, UVRef[1].y); var UVratioBottomRightlw = new Vector2(distlw / 5, UVRef[3].y); Vector3 lv3 = OriginalVertices[OriginalVertices.Length - 1] - HeightVector; Vector3 lv4 = OriginalVertices[0] - HeightVector; vertices.AddRange(new Vector3[] { lv1, lv2, lv3 }); UVs.Add(UVRef[0]); UVs.Add(UVratioTopRightlw); //UVs.Add(UVRef[1]); UVs.Add(UVRef[2]); vertices.AddRange(new Vector3[] { lv3, lv2, lv4 }); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRightlw); //UVs.Add(UVRef[1]); UVs.Add(UVratioBottomRightlw); //UVs.Add(UVRef[3]); // Reverse vertices.AddRange(new Vector3[] { lv1, lv3, lv2 }); UVs.Add(UVRef[0]); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRightlw); //UVs.Add(UVRef[1]); vertices.AddRange(new Vector3[] { lv3, lv4, lv2 }); UVs.Add(UVRef[2]); UVs.Add(UVratioBottomRightlw); //UVs.Add(UVRef[3]); UVs.Add(UVratioTopRightlw); //UVs.Add(UVRef[1]); #endregion #region Inner walls List <Vector3[]> OriginalInnerVertices = new List <Vector3[]>(); if (shape.Holes != null) { for (int i = 0; i < shape.Holes.Count; i++) { OriginalInnerVertices.Add(shape.Holes[i].Points.Select(s => new Vector3((float)s.X, WallHeight, (float)s.Y)).ToArray()); } for (int holeidx = 0; holeidx < shape.Holes.Count; holeidx++) { // Generating Walls - Total: (OriginalInnerVertices.Length)*4*3 for (int i = 0; i < OriginalInnerVertices[holeidx].Length - 1; i++) { Vector3 v1 = OriginalInnerVertices[holeidx][i]; Vector3 v2 = OriginalInnerVertices[holeidx][i + 1]; var dist = Vector3.Distance(v1, v2); //Debug.Log("Distance: "+dist); dist = dist.Clamp(0, 5); var UVratioTopRight = new Vector2(dist / 5, UVRef[1].y); var UVratioBottomRight = new Vector2(dist / 5, UVRef[3].y); Vector3 v3 = OriginalInnerVertices[holeidx][i] - HeightVector; Vector3 v4 = OriginalInnerVertices[holeidx][i + 1] - HeightVector; vertices.AddRange(new Vector3[] { v1, v2, v3 }); UVs.Add(UVRef[0]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); UVs.Add(UVRef[2]); vertices.AddRange(new Vector3[] { v3, v2, v4 }); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); UVs.Add(UVratioBottomRight); //UVs.Add(UVRef[3]); // Reverse vertices.AddRange(new Vector3[] { v1, v3, v2 }); UVs.Add(UVRef[0]); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); vertices.AddRange(new Vector3[] { v3, v4, v2 }); UVs.Add(UVRef[2]); UVs.Add(UVratioBottomRight); //UVs.Add(UVRef[3]); UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]); } // Last Wall - Total: 4*3 Vector3 lv1_hole = OriginalInnerVertices[holeidx][OriginalInnerVertices[holeidx].Length - 1]; Vector3 lv2_hole = OriginalInnerVertices[holeidx][0]; var distlw_hole = Vector3.Distance(lv1_hole, lv2_hole); //Debug.Log("Distance: "+distlw_hole); distlw_hole = distlw_hole.Clamp(0, 5); var UVratioTopRightlw_hole = new Vector2(distlw_hole / 5, UVRef[1].y); var UVratioBottomRightlw_hole = new Vector2(distlw_hole / 5, UVRef[3].y); Vector3 lv3_hole = OriginalInnerVertices[holeidx][OriginalInnerVertices[holeidx].Length - 1] - HeightVector; Vector3 lv4_hole = OriginalInnerVertices[holeidx][0] - HeightVector; vertices.AddRange(new Vector3[] { lv1_hole, lv2_hole, lv3_hole }); UVs.Add(UVRef[0]); UVs.Add(UVratioTopRightlw_hole); //UVs.Add(UVRef[1]); UVs.Add(UVRef[2]); vertices.AddRange(new Vector3[] { lv3_hole, lv2_hole, lv4_hole }); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRightlw_hole); //UVs.Add(UVRef[1]); UVs.Add(UVratioBottomRightlw_hole); //UVs.Add(UVRef[3]); // Reverse vertices.AddRange(new Vector3[] { lv1_hole, lv3_hole, lv2_hole }); UVs.Add(UVRef[0]); UVs.Add(UVRef[2]); UVs.Add(UVratioTopRightlw_hole); //UVs.Add(UVRef[1]); vertices.AddRange(new Vector3[] { lv3_hole, lv4_hole, lv2_hole }); UVs.Add(UVRef[2]); UVs.Add(UVratioBottomRightlw_hole); //UVs.Add(UVRef[3]); UVs.Add(UVratioTopRightlw_hole); //UVs.Add(UVRef[1]); } } #endregion // int[] tris = new int[shape.Triangles.Count * 3 + (OriginalVertices.Length - 1) * 4 * 3 + 4 * 3]; int innerTriCount = 0; for (int i = 0; i < OriginalInnerVertices.Count; i++) { innerTriCount += (OriginalInnerVertices[i].Length - 1) * 4 * 3 + 4 * 3; } int[] tris = new int[shape.Triangles.Count * 3 + (OriginalVertices.Length - 1) * 4 * 3 + 4 * 3 + innerTriCount]; for (int i = 0; i < tris.Length; i++) { tris[i] = i; } gameObject.position = CoordinateConvertor.ChangePivot(ref vertices, CoordinateConvertor.PivotLocation.ZeroBottomCenter); gameObject.mesh = Rebuild(vertices.ToArray(), tris, UVs.ToArray()); gameObject.material = new Material(MaterialName); return(gameObject); }
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(); }
//------- 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(); }
/// <summary> /// create polygon from flatten curve outline point /// </summary> /// <param name="cnt"></param> /// <returns></returns> static Poly2Tri.Polygon CreatePolygon2(GlyphContour cnt) { List <Poly2Tri.TriangulationPoint> points = new List <Poly2Tri.TriangulationPoint>(); List <GlyphPart> allParts = cnt.parts; //--------------------------------------- //merge all generated points //also remove duplicated point too! List <GlyphPoint2D> mergedPoints = new List <GlyphPoint2D>(); cnt.mergedPoints = mergedPoints; //--------------------------------------- { int tt = 0; int j = allParts.Count; for (int i = 0; i < j; ++i) { GlyphPart p = allParts[i]; List <GlyphPoint2D> fpoints = p.GetFlattenPoints(); if (tt == 0) { int n = fpoints.Count; for (int m = 0; m < n; ++m) { //GlyphPoint2D fp = fpoints[m]; mergedPoints.Add(fpoints[m]); //allPoints.Add((float)fp.x); //allPoints.Add((float)fp.y); } tt++; } else { //except first point int n = fpoints.Count; for (int m = 1; m < n; ++m) { //GlyphPoint2D fp = fpoints[m]; mergedPoints.Add(fpoints[m]); //allPoints.Add((float)fp.x); //allPoints.Add((float)fp.y); } } } } //--------------------------------------- { //check last (x,y) and first (x,y) int lim = mergedPoints.Count - 1; { if (mergedPoints[lim].IsEqualValues(mergedPoints[0])) { //remove last (x,y) mergedPoints.RemoveAt(lim); lim -= 1; } } //limitation: poly tri not accept duplicated points! double prevX = 0; double prevY = 0; Dictionary <TmpPoint, bool> tmpPoints = new Dictionary <TmpPoint, bool>(); lim = mergedPoints.Count; for (int i = 0; i < lim; ++i) { GlyphPoint2D p = mergedPoints[i]; double x = p.x; double y = p.y; if (x == prevX && y == prevY) { if (i > 0) { throw new NotSupportedException(); } } else { TmpPoint tmp_point = new TmpPoint(x, y); if (!tmpPoints.ContainsKey(tmp_point)) { //ensure no duplicated point tmpPoints.Add(tmp_point, true); var userTriangulationPoint = new Poly2Tri.TriangulationPoint(x, y) { userData = p }; p.triangulationPoint = userTriangulationPoint; points.Add(userTriangulationPoint); } else { throw new NotSupportedException(); } prevX = x; prevY = y; } } Poly2Tri.Polygon polygon = new Poly2Tri.Polygon(points.ToArray()); return(polygon); } }
/// <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; }
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++; } } } }
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 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); }