private void MeshCleanReq( DelaunayTriangle triangle ) { if (triangle != null && !triangle.IsInterior) { triangle.IsInterior = true; Triangulatable.AddTriangle(triangle); for (int i = 0; i < 3; i++) if (!triangle.EdgeIsConstrained[i]) { MeshCleanReq(triangle.Neighbors[i]); } } }
public void RemoveFromList( DelaunayTriangle triangle ) { Triangles.Remove(triangle); // TODO: remove all neighbor pointers to this triangle // for( int i=0; i<3; i++ ) // { // if( triangle.neighbors[i] != null ) // { // triangle.neighbors[i].clearNeighbor( triangle ); // } // } // triangle.clearNeighbors(); }
public void MeshClean(DelaunayTriangle triangle) { MeshCleanReq(triangle); }
private static void FlipEdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle t, TriangulationPoint p) { TriangulationPoint op, newP; DelaunayTriangle ot; bool inScanArea; ot = t.NeighborAcross(p); op = ot.OppositePoint(t, p); if (ot == null) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here throw new InvalidOperationException("[BUG:FIXME] FLIP failed due to missing triangle"); } inScanArea = TriangulationUtil.InScanArea(p, t.PointCCW(p), t.PointCW(p), op); if (inScanArea) { // Lets rotate shared edge one vertex CW RotateTrianglePair(t, p, ot, op); tcx.MapTriangleToNodes(t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == tcx.EdgeEvent.ConstrainedEdge.Q && ep == tcx.EdgeEvent.ConstrainedEdge.P) { if (tcx.IsDebugEnabled) { #if NETFX_CORE Debug.WriteLine("[FLIP] - constrained edge done"); #else Console.WriteLine("[FLIP] - constrained edge done"); // TODO: remove #endif } t.MarkConstrainedEdge(ep, eq); ot.MarkConstrainedEdge(ep, eq); Legalize(tcx, t); Legalize(tcx, ot); } else { if (tcx.IsDebugEnabled) #if NETFX_CORE Debug.WriteLine("[FLIP] - subedge done"); // TODO: remove #else Console.WriteLine("[FLIP] - subedge done"); // TODO: remove #endif // XXX: I think one of the triangles should be legalized here? } } else { if (tcx.IsDebugEnabled) #if NETFX_CORE Debug.WriteLine("[FLIP] - flipping and continuing with triangle still crossing edge"); // TODO: remove #else Console.WriteLine("[FLIP] - flipping and continuing with triangle still crossing edge"); // TODO: remove #endif // TODO: remove Orientation o = TriangulationUtil.Orient2d(eq, op, ep); t = NextFlipTriangle(tcx, o, t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } }
/// <summary> /// After a flip we have two triangles and know that only one will still be /// intersecting the edge. So decide which to contiune with and legalize the other /// </summary> /// <param name="tcx"></param> /// <param name="o">should be the result of an TriangulationUtil.orient2d( eq, op, ep )</param> /// <param name="t">triangle 1</param> /// <param name="ot">triangle 2</param> /// <param name="p">a point shared by both triangles</param> /// <param name="op">another point shared by both triangles</param> /// <returns>returns the triangle still intersecting the edge</returns> private static DelaunayTriangle NextFlipTriangle(DTSweepContext tcx, Orientation o, DelaunayTriangle t, DelaunayTriangle ot, TriangulationPoint p, TriangulationPoint op) { int edgeIndex; if (o == Orientation.CCW) { // ot is not crossing edge after flip edgeIndex = ot.EdgeIndex(p, op); ot.EdgeIsDelaunay[edgeIndex] = true; Legalize(tcx, ot); ot.EdgeIsDelaunay.Clear(); return(t); } // t is not crossing edge after flip edgeIndex = t.EdgeIndex(p, op); t.EdgeIsDelaunay[edgeIndex] = true; Legalize(tcx, t); t.EdgeIsDelaunay.Clear(); return(ot); }
/// <summary> /// When we need to traverse from one triangle to the next we need /// the point in current triangle that is the opposite point to the next /// triangle. /// </summary> private static bool NextFlipPoint(TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle ot, TriangulationPoint op, out TriangulationPoint newP) { newP = null; Orientation o2d = TriangulationUtil.Orient2d(eq, op, ep); switch (o2d) { case Orientation.CW: newP = ot.PointCCWFrom(op); return(true); case Orientation.CCW: newP = ot.PointCWFrom(op); return(true); case Orientation.Collinear: // TODO: implement support for point on constraint edge //throw new PointOnEdgeException("Point on constrained edge not supported yet", eq, op, ep); return(false); default: throw new NotImplementedException("Orientation not handled"); } }
/// <summary> /// Returns true if triangle was legalized /// </summary> private static bool Legalize(DTSweepContext tcx, DelaunayTriangle t) { // To legalize a triangle we start by finding if any of the three edges // violate the Delaunay condition for (int i = 0; i < 3; i++) { // TODO: fix so that cEdge is always valid when creating new triangles then we can check it here // instead of below with ot if (t.EdgeIsDelaunay[i]) { continue; } DelaunayTriangle ot = t.Neighbors[i]; if (ot != null) { TriangulationPoint p = t.Points[i]; TriangulationPoint op = ot.OppositePoint(t, p); int oi = ot.IndexOf(op); // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) // then we should not try to legalize if (ot.EdgeIsConstrained[oi] || ot.EdgeIsDelaunay[oi]) { t.EdgeIsConstrained[i] = ot.EdgeIsConstrained[oi]; // XXX: have no good way of setting this property when creating new triangles so lets set it here continue; } bool inside = TriangulationUtil.SmartIncircle(p, t.PointCCW(p), t.PointCW(p), op); if (inside) { // Lets mark this shared edge as Delaunay t.EdgeIsDelaunay[i] = true; ot.EdgeIsDelaunay[oi] = true; // Lets rotate shared edge one vertex CW to legalize it RotateTrianglePair(t, p, ot, op); // We now got one valid Delaunay Edge shared by two triangles // This gives us 4 new edges to check for Delaunay // Make sure that triangle to node mapping is done only one time for a specific triangle bool notLegalized = !Legalize(tcx, t); if (notLegalized) { tcx.MapTriangleToNodes(t); } notLegalized = !Legalize(tcx, ot); if (notLegalized) { tcx.MapTriangleToNodes(ot); } // Reset the Delaunay edges, since they only are valid Delaunay edges // until we add a new triangle or point. // XXX: need to think about this. Can these edges be tried after we // return to previous recursive level? t.EdgeIsDelaunay[i] = false; ot.EdgeIsDelaunay[oi] = false; // If triangle have been legalized no need to check the other edges since // the recursive legalization will handles those so we can end here. return true; } } } return false; }
/// <summary> /// Adds a triangle to the advancing front to fill a hole. /// </summary> /// <param name="tcx"></param> /// <param name="node">middle node, that is the bottom of the hole</param> private static void Fill(DTSweepContext tcx, AdvancingFrontNode node) { DelaunayTriangle triangle = new DelaunayTriangle(node.Prev.Point, node.Point, node.Next.Point); // TODO: should copy the cEdge value from neighbor triangles // for now cEdge values are copied during the legalize triangle.MarkNeighbor(node.Prev.Triangle); triangle.MarkNeighbor(node.Triangle); tcx.Triangles.Add(triangle); // Update the advancing front node.Prev.Next = node.Next; node.Next.Prev = node.Prev; tcx.RemoveNode(node); // If it was legalized the triangle has already been mapped if (!Legalize(tcx, triangle)) { tcx.MapTriangleToNodes(triangle); } }
GameObject GenerateCountryRegionSurface(int countryIndex, int regionIndex, Material material, bool drawOutline) { Country country = countries[countryIndex]; Region region = country.regions [regionIndex]; Polygon poly = new Polygon(region.latlon); double maxTriangleSize = 10.0f; if (countryIndex == 6) // Antarctica { maxTriangleSize = 9.0f; } if (Mathf.Abs(region.minMaxLat.x - region.minMaxLat.y) > maxTriangleSize || Mathf.Abs(region.minMaxLon.x - region.minMaxLon.y) > maxTriangleSize) // special case; needs steiner points to reduce the size of triangles { double step = maxTriangleSize / 2; List <TriangulationPoint> steinerPoints = new List <TriangulationPoint>(); for (double x = region.minMaxLat.x + step / 2; x < region.minMaxLat.y - step / 2; x += step) { for (double y = region.minMaxLon.x + step / 2; y < region.minMaxLon.y - step / 2; y += step) { if (ContainsPoint2D(region.latlon, x, y)) { steinerPoints.Add(new TriangulationPoint(x, y)); } } } poly.AddSteinerPoints(steinerPoints); } P2T.Triangulate(poly); int flip1, flip2; flip1 = 1; flip2 = 2; Vector3[] revisedSurfPoints = new Vector3[poly.Triangles.Count * 3]; for (int k = 0; k < poly.Triangles.Count; k++) { DelaunayTriangle dt = poly.Triangles[k]; revisedSurfPoints[k * 3] = GetSpherePointFromLatLon2(dt.Points[0].X, dt.Points[0].Y); revisedSurfPoints[k * 3 + flip1] = GetSpherePointFromLatLon2(dt.Points[1].X, dt.Points[1].Y); revisedSurfPoints[k * 3 + flip2] = GetSpherePointFromLatLon2(dt.Points[2].X, dt.Points[2].Y); } int revIndex = revisedSurfPoints.Length - 1; // Generate surface mesh int cacheIndex = GetCacheIndexForCountryRegion(countryIndex, regionIndex); string cacheIndexSTR = cacheIndex.ToString(); Transform t = surfacesLayer.transform.FindChild(cacheIndexSTR); if (t != null) { DestroyImmediate(t.gameObject); } GameObject surf = Drawing.CreateSurface(cacheIndexSTR, revisedSurfPoints, revIndex, material); surf.transform.SetParent(surfacesLayer.transform, false); surf.transform.localPosition = MiscVector.Vector3zero; surf.transform.localRotation = Quaternion.Euler(MiscVector.Vector3zero); if (surfaces.ContainsKey(cacheIndex)) { surfaces.Remove(cacheIndex); } surfaces.Add(cacheIndex, surf); // draw outline if (drawOutline) { DrawCountryRegionOutline(region, surf); } return(surf); }
public void AddTriangle(DelaunayTriangle t) { throw new NotImplementedException("PolyHole.AddTriangle should never get called"); }
private void CutPoly(Int3[] verts, int[] tris, ref Int3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, Int3[] extraShape, Int3 cuttingOffset, Bounds realBounds, TileHandler.CutMode mode = TileHandler.CutMode.CutAll | TileHandler.CutMode.CutDual, int perturbate = -1) { if (verts.Length == 0 || tris.Length == 0) { outVCount = 0; outTCount = 0; outTrisArr = new int[0]; outVertsArr = new Int3[0]; return; } if (perturbate > 10) { Debug.LogError("Too many perturbations aborting.\nThis may cause a tile in the navmesh to become empty. Try to see see if any of your NavmeshCut or NavmeshAdd components use invalid custom meshes."); outVCount = verts.Length; outTCount = tris.Length; outTrisArr = tris; outVertsArr = verts; return; } List <IntPoint> list = null; if (extraShape == null && (mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { list = ListPool <IntPoint> .Claim(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))); } } IntRect bounds = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z); for (int j = 0; j < verts.Length; j++) { bounds = bounds.ExpandToContain(verts[j].x, verts[j].z); } List <NavmeshCut> list2; if (mode == TileHandler.CutMode.CutExtra) { list2 = ListPool <NavmeshCut> .Claim(); } else { list2 = NavmeshCut.GetAllInRange(realBounds); } List <NavmeshAdd> allInRange = NavmeshAdd.GetAllInRange(realBounds); List <int> list3 = ListPool <int> .Claim(); List <TileHandler.Cut> list4 = TileHandler.PrepareNavmeshCutsForCutting(list2, cuttingOffset, bounds, perturbate, allInRange.Count > 0); List <Int3> list5 = ListPool <Int3> .Claim(verts.Length * 2); List <int> list6 = ListPool <int> .Claim(tris.Length); Int3[] array = verts; int[] array2 = tris; if (list2.Count == 0 && allInRange.Count == 0 && (mode & ~(TileHandler.CutMode.CutAll | TileHandler.CutMode.CutDual)) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { this.CopyMesh(array, array2, list5, list6); } else { List <IntPoint> list7 = ListPool <IntPoint> .Claim(); Dictionary <TriangulationPoint, int> dictionary = new Dictionary <TriangulationPoint, int>(); List <PolygonPoint> list8 = ListPool <PolygonPoint> .Claim(); PolyTree polyTree = new PolyTree(); List <List <IntPoint> > intermediateResult = new List <List <IntPoint> >(); Stack <Polygon> stack = new Stack <Polygon>(); this.clipper.StrictlySimple = (perturbate > -1); this.clipper.ReverseSolution = true; Int3[] array3 = null; Int3[] clipOut = null; Int2 @int = default(Int2); if (allInRange.Count > 0) { array3 = new Int3[7]; clipOut = new Int3[7]; @int = new Int2(((Int3)realBounds.extents).x, ((Int3)realBounds.extents).z); } int num = -1; int k = -3; for (;;) { k += 3; while (k >= array2.Length) { num++; k = 0; if (num >= allInRange.Count) { array = null; break; } if (array == verts) { array = null; } allInRange[num].GetMesh(cuttingOffset, ref array, out array2); } if (array == null) { break; } Int3 int2 = array[array2[k]]; Int3 int3 = array[array2[k + 1]]; Int3 int4 = array[array2[k + 2]]; if (VectorMath.IsColinearXZ(int2, int3, int4)) { Debug.LogWarning("Skipping degenerate triangle."); } else { IntRect a = new IntRect(int2.x, int2.z, int2.x, int2.z); a = a.ExpandToContain(int3.x, int3.z); a = a.ExpandToContain(int4.x, int4.z); int num2 = Math.Min(int2.y, Math.Min(int3.y, int4.y)); int num3 = Math.Max(int2.y, Math.Max(int3.y, int4.y)); list3.Clear(); bool flag = false; for (int l = 0; l < list4.Count; l++) { int x = list4[l].boundsY.x; int y = list4[l].boundsY.y; if (IntRect.Intersects(a, list4[l].bounds) && y >= num2 && x <= num3 && (list4[l].cutsAddedGeom || num == -1)) { Int3 int5 = int2; int5.y = x; Int3 int6 = int2; int6.y = y; list3.Add(l); flag |= list4[l].isDual; } } if (list3.Count == 0 && (mode & TileHandler.CutMode.CutExtra) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0 && num == -1) { list6.Add(list5.Count); list6.Add(list5.Count + 1); list6.Add(list5.Count + 2); list5.Add(int2); list5.Add(int3); list5.Add(int4); } else { list7.Clear(); if (num == -1) { list7.Add(new IntPoint((long)int2.x, (long)int2.z)); list7.Add(new IntPoint((long)int3.x, (long)int3.z)); list7.Add(new IntPoint((long)int4.x, (long)int4.z)); } else { array3[0] = int2; array3[1] = int3; array3[2] = int4; int num4 = this.ClipAgainstRectangle(array3, clipOut, new Int2(@int.x * 2, @int.y * 2)); if (num4 == 0) { continue; } for (int m = 0; m < num4; m++) { list7.Add(new IntPoint((long)array3[m].x, (long)array3[m].z)); } } dictionary.Clear(); for (int n = 0; n < 16; n++) { if ((mode >> (n & 31) & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { if (1 << n == 1) { this.CutAll(list7, list3, list4, polyTree); } else if (1 << n == 2) { if (!flag) { goto IL_9A0; } this.CutDual(list7, list3, list4, flag, intermediateResult, polyTree); } else if (1 << n == 4) { this.CutExtra(list7, list, polyTree); } for (int num5 = 0; num5 < polyTree.ChildCount; num5++) { PolyNode polyNode = polyTree.Childs[num5]; List <IntPoint> contour = polyNode.Contour; List <PolyNode> childs = polyNode.Childs; if (childs.Count == 0 && contour.Count == 3 && num == -1) { for (int num6 = 0; num6 < 3; num6++) { Int3 int7 = new Int3((int)contour[num6].X, 0, (int)contour[num6].Y); int7.y = TileHandler.SampleYCoordinateInTriangle(int2, int3, int4, int7); list6.Add(list5.Count); list5.Add(int7); } } else { Polygon polygon = null; int num7 = -1; for (List <IntPoint> list9 = contour; list9 != null; list9 = ((num7 >= childs.Count) ? null : childs[num7].Contour)) { list8.Clear(); for (int num8 = 0; num8 < list9.Count; num8++) { PolygonPoint polygonPoint = new PolygonPoint((double)list9[num8].X, (double)list9[num8].Y); list8.Add(polygonPoint); Int3 int8 = new Int3((int)list9[num8].X, 0, (int)list9[num8].Y); int8.y = TileHandler.SampleYCoordinateInTriangle(int2, int3, int4, int8); dictionary[polygonPoint] = list5.Count; list5.Add(int8); } Polygon polygon2; if (stack.Count > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list8); } else { polygon2 = new Polygon(list8); } if (num7 == -1) { polygon = polygon2; } else { polygon.AddHole(polygon2); } num7++; } try { P2T.Triangulate(polygon); } catch (PointOnEdgeException) { Debug.LogWarning("PointOnEdgeException, perturbating vertices slightly.\nThis is usually fine. It happens sometimes because of rounding errors. Cutting will be retried a few more times."); this.CutPoly(verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1); return; } try { for (int num9 = 0; num9 < polygon.Triangles.Count; num9++) { DelaunayTriangle delaunayTriangle = polygon.Triangles[num9]; list6.Add(dictionary[delaunayTriangle.Points._0]); list6.Add(dictionary[delaunayTriangle.Points._1]); list6.Add(dictionary[delaunayTriangle.Points._2]); } } catch (KeyNotFoundException) { Debug.LogWarning("KeyNotFoundException, perturbating vertices slightly.\nThis is usually fine. It happens sometimes because of rounding errors. Cutting will be retried a few more times."); this.CutPoly(verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1); return; } TileHandler.PoolPolygon(polygon, stack); } } } IL_9A0 :; } } } } ListPool <IntPoint> .Release(list7); ListPool <PolygonPoint> .Release(list8); } this.CompressMesh(list5, list6, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount); for (int num10 = 0; num10 < list2.Count; num10++) { list2[num10].UsedForCut(); } ListPool <Int3> .Release(list5); ListPool <int> .Release(list6); ListPool <int> .Release(list3); for (int num11 = 0; num11 < list4.Count; num11++) { ListPool <IntPoint> .Release(list4[num11].contour); } ListPool <TileHandler.Cut> .Release(list4); ListPool <NavmeshCut> .Release(list2); }
GameObject GenerateProvinceRegionSurface(int provinceIndex, int regionIndex, Material material) { if (provinceIndex < 0 || provinceIndex >= provinces.Length) { return(null); } if (provinces[provinceIndex].regions == null) { ReadProvincePackedString(provinces[provinceIndex]); } if (provinces[provinceIndex].regions == null || regionIndex < 0 || regionIndex >= provinces[provinceIndex].regions.Count) { return(null); } Province province = provinces[provinceIndex]; Region region = province.regions [regionIndex]; // Triangulate to get the polygon vertex indices Poly2Tri.Polygon poly = new Poly2Tri.Polygon(region.latlon); if (_enableProvinceEnclaves && regionIndex == province.mainRegionIndex) { ProvinceSubstractProvinceEnclaves(provinceIndex, region, poly); } // Antarctica, Saskatchewan (Canada), British Columbia (Canada), Krasnoyarsk (Russia) - special cases due to its geometry float step = _frontiersDetail == FRONTIERS_DETAIL.High ? 2f: 5f; List <TriangulationPoint> steinerPoints = new List <TriangulationPoint>(); float x0 = region.latlonRect2D.min.x + step / 2f; float x1 = region.latlonRect2D.max.x - step / 2f; float y0 = region.latlonRect2D.min.y + step / 2f; float y1 = region.latlonRect2D.max.y - step / 2f; for (float x = x0; x < x1; x += step) { for (float y = y0; y < y1; y += step) { float xp = x + UnityEngine.Random.Range(-0.0001f, 0.0001f); float yp = y + UnityEngine.Random.Range(-0.0001f, 0.0001f); if (region.Contains(xp, yp)) { steinerPoints.Add(new TriangulationPoint(xp, yp)); // GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere); // obj.transform.SetParent(WorldMapGlobe.instance.transform, false); // obj.transform.localScale = Vector3.one * 0.01f; // obj.transform.localPosition = Conversion.GetSpherePointFromLatLon(new Vector2(x,y)) * 1.01f; } } } if (steinerPoints.Count > 0) { poly.AddSteinerPoints(steinerPoints); } P2T.Triangulate(poly); int flip1, flip2; if (_earthInvertedMode) { flip1 = 2; flip2 = 1; } else { flip1 = 1; flip2 = 2; } int triCount = poly.Triangles.Count; Vector3[] revisedSurfPoints = new Vector3[triCount * 3]; for (int k = 0; k < triCount; k++) { DelaunayTriangle dt = poly.Triangles[k]; revisedSurfPoints[k * 3] = Conversion.GetSpherePointFromLatLon(dt.Points[0].X, dt.Points[0].Y); revisedSurfPoints[k * 3 + flip1] = Conversion.GetSpherePointFromLatLon(dt.Points[1].X, dt.Points[1].Y); revisedSurfPoints[k * 3 + flip2] = Conversion.GetSpherePointFromLatLon(dt.Points[2].X, dt.Points[2].Y); } int revIndex = revisedSurfPoints.Length - 1; // Generate surface mesh int cacheIndex = GetCacheIndexForProvinceRegion(provinceIndex, regionIndex); string cacheIndexSTR = cacheIndex.ToString(); // Deletes potential residual surface Transform t = surfacesLayer.transform.Find(cacheIndexSTR); if (t != null) { DestroyImmediate(t.gameObject); } GameObject surf = Drawing.CreateSurface(cacheIndexSTR, revisedSurfPoints, revIndex, material); // Rect rect = new Rect(0,0,0,0); // GameObject surf = Drawing.CreateSurface (cacheIndexSTR, poly, material, rect, Vector2.zero, Vector2.zero, 0); surf.transform.SetParent(surfacesLayer.transform, false); surf.transform.localPosition = Misc.Vector3zero; if (_earthInvertedMode) { surf.transform.localScale = Misc.Vector3one * 0.998f; } if (surfaces.ContainsKey(cacheIndex)) { surfaces.Remove(cacheIndex); } surfaces.Add(cacheIndex, surf); return(surf); }
/// <summary> /// Generate a set of mesh faces that represent a delaunay triangulation in the XY plane of the /// specified set of vertices. /// Based on the algorithm described here: http://paulbourke.net/papers/triangulate/ /// </summary> /// <param name="vertices">The vertices to mesh between</param> /// <param name="faces">Optional. The face collection to which to add the triangles. /// If null or ommitted, a new MeshFaceCollection will be created.</param> /// <param name="bounds">The bounding box that contains the triangulation. Should encompass all vertices /// and, for later voronoi generation, any bounding geometry. If null, the bounding box of the vertices /// themselves will be used.</param> /// <param name="clean">Clean up construction Super Triangle. If true, any remaining fragments of the /// initial generating supertriangle will be removed from the output face list. Set this to false /// if planning on using this mesh for subsequent voronoi generation so that the edge cells can be extended.</param> /// <param name="outerVerts">Optional. If input and non-null, this collection will be populated with the exterior vertices - those connected /// to the original supertriangle. If 'clean' is false, this will instead return the supertriangle vertices.</param> public static MeshFaceCollection DelaunayTriangulationXY(VertexCollection vertices, MeshFaceCollection faces = null, BoundingBox bounds = null, bool clean = true, VertexCollection outerVerts = null) { List <Vertex> vertexList = vertices.ToList(); vertexList.Sort(); if (faces == null) { faces = new MeshFaceCollection(); } if (bounds == null) { bounds = new BoundingBox(vertexList); } else { bounds = new BoundingBox(bounds); } bounds.Scale(5); //Provide a little wriggle room! // Meshing starts with one 'super triangle' that encloses all vertices. // This will be removed at the end MeshFace superTriangle = DelaunayTriangle.GenerateSuperTriangleXY(bounds); faces.Add(superTriangle); // Include each vertex in the meshing one at a time foreach (Vertex v in vertexList) { //for (int k = 0; k < 8; k++) //{ // Vertex v = vertexList[k]; // if (k == 7) // { // bool bum = true; // } IList <MeshEdge> edges = new List <MeshEdge>(); //The edges of replaced triangles for (int i = faces.Count - 1; i >= 0; i--) { MeshFace face = faces[i]; if (face.XYCircumcircleContainmentQuickCheck(v)) //The vertex lies within the circumcircle of this face { //The edges of the triangle are added to the current edge set... for (int j = 0; j < face.Count; j++) { edges.Add(face.GetEdge(j)); } //...and the triangle is removed. faces.RemoveAt(i); } } //Remove duplicate edges to retain only the convex hull of edges. //edges.RemoveDuplicates(); //Replaced with bespoke version for (int i = edges.Count - 2; i >= 0; i--) { MeshEdge itemA = edges[i]; for (int j = edges.Count - 1; j > i; j--) { if (itemA.Equals(edges[j])) { edges.RemoveAt(j); edges.RemoveAt(i); j--; continue; } } } // Add triangle fan between all remaining edges and the new vertex foreach (MeshEdge edge in edges) { faces.Add(new DelaunayTriangle(edge, v)); } } // Extract outer vertices if (outerVerts != null) { if (clean) { var outerFaces = faces.AllWithVertices(new VertexCollection(superTriangle)); foreach (Vertex v in outerFaces.ExtractVertices()) { outerVerts.Add(v); } } else { foreach (Vertex v in superTriangle) { outerVerts.Add(v); } } } // Remove the super triangle and any triangles still attached to it if (clean) { faces.RemoveAllWithVertices(new VertexCollection(superTriangle)); } return(faces); }
/// <summary> /// Adds the triangle using the specified t /// </summary> /// <param name="t">The </param> public void AddTriangle(DelaunayTriangle t) { TrianglesPrivate.Add(t); }
public override void Clear() { this.PrimaryTriangle = null; this.SecondaryTriangle = null; this.ActivePoint = null; this.ActiveNode = null; this.ActiveConstraint = null; }
/// <summary> /// Rotates a triangle pair one vertex CW /// n2 n2 /// P +-----+ P +-----+ /// | t /| |\ t | /// | / | | \ | /// n1| / |n3 n1| \ |n3 /// | / | after CW | \ | /// |/ oT | | oT \| /// +-----+ oP +-----+ /// n4 n4 /// </summary> private static void RotateTrianglePair(DelaunayTriangle t, TriangulationPoint p, DelaunayTriangle ot, TriangulationPoint op) { DelaunayTriangle n1 = t.NeighborCCW(p); DelaunayTriangle n2 = t.NeighborCW(p); DelaunayTriangle n3 = ot.NeighborCCW(op); DelaunayTriangle n4 = ot.NeighborCW(op); bool ce1 = t.GetConstrainedEdgeCCW(p); bool ce2 = t.GetConstrainedEdgeCW(p); bool ce3 = ot.GetConstrainedEdgeCCW(op); bool ce4 = ot.GetConstrainedEdgeCW(op); bool de1 = t.GetDelaunayEdgeCCW(p); bool de2 = t.GetDelaunayEdgeCW(p); bool de3 = ot.GetDelaunayEdgeCCW(op); bool de4 = ot.GetDelaunayEdgeCW(op); t.Legalize(p, op); ot.Legalize(op, p); // Remap dEdge ot.SetDelaunayEdgeCCW(p, de1); t.SetDelaunayEdgeCW(p, de2); t.SetDelaunayEdgeCCW(op, de3); ot.SetDelaunayEdgeCW(op, de4); // Remap cEdge ot.SetConstrainedEdgeCCW(p, ce1); t.SetConstrainedEdgeCW(p, ce2); t.SetConstrainedEdgeCCW(op, ce3); ot.SetConstrainedEdgeCW(op, ce4); // Remap neighbors // XXX: might optimize the markNeighbor by keeping track of // what side should be assigned to what neighbor after the // rotation. Now mark neighbor does lots of testing to find // the right side. t.Neighbors.Clear(); ot.Neighbors.Clear(); if (n1 != null) ot.MarkNeighbor(n1); if (n2 != null) t.MarkNeighbor(n2); if (n3 != null) t.MarkNeighbor(n3); if (n4 != null) ot.MarkNeighbor(n4); t.MarkNeighbor(ot); }
// Token: 0x06002959 RID: 10585 RVA: 0x001BCF00 File Offset: 0x001BB100 private TileHandler.CuttingResult CutPoly(Int3[] verts, int[] tris, Int3[] extraShape, GraphTransform graphTransform, IntRect tiles, TileHandler.CutMode mode = TileHandler.CutMode.CutAll | TileHandler.CutMode.CutDual, int perturbate = -1) { if (verts.Length == 0 || tris.Length == 0) { TileHandler.CuttingResult result = new TileHandler.CuttingResult { verts = ArrayPool <Int3> .Claim(0), tris = ArrayPool <int> .Claim(0) }; return(result); } if (perturbate > 10) { Debug.LogError("Too many perturbations aborting.\nThis may cause a tile in the navmesh to become empty. Try to see see if any of your NavmeshCut or NavmeshAdd components use invalid custom meshes."); TileHandler.CuttingResult result = new TileHandler.CuttingResult { verts = verts, tris = tris }; return(result); } List <IntPoint> list = null; if (extraShape == null && (mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } Bounds tileBoundsInGraphSpace = this.graph.GetTileBoundsInGraphSpace(tiles); Vector3 min = tileBoundsInGraphSpace.min; GraphTransform graphTransform2 = graphTransform * Matrix4x4.TRS(min, Quaternion.identity, Vector3.one); Vector2 v = new Vector2(tileBoundsInGraphSpace.size.x, tileBoundsInGraphSpace.size.z); if ((mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { list = ListPool <IntPoint> .Claim(extraShape.Length); for (int i = 0; i < extraShape.Length; i++) { Int3 @int = graphTransform2.InverseTransform(extraShape[i]); list.Add(new IntPoint((long)@int.x, (long)@int.z)); } } IntRect cutSpaceBounds = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z); for (int j = 0; j < verts.Length; j++) { cutSpaceBounds = cutSpaceBounds.ExpandToContain(verts[j].x, verts[j].z); } List <NavmeshCut> list2; if (mode == TileHandler.CutMode.CutExtra) { list2 = ListPool <NavmeshCut> .Claim(); } else { list2 = this.cuts.QueryRect <NavmeshCut>(tiles); } List <NavmeshAdd> list3 = this.cuts.QueryRect <NavmeshAdd>(tiles); List <int> list4 = ListPool <int> .Claim(); List <TileHandler.Cut> list5 = TileHandler.PrepareNavmeshCutsForCutting(list2, graphTransform2, cutSpaceBounds, perturbate, list3.Count > 0); List <Int3> list6 = ListPool <Int3> .Claim(verts.Length * 2); List <int> list7 = ListPool <int> .Claim(tris.Length); if (list2.Count == 0 && list3.Count == 0 && (mode & ~(TileHandler.CutMode.CutAll | TileHandler.CutMode.CutDual)) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { TileHandler.CopyMesh(verts, tris, list6, list7); } else { List <IntPoint> list8 = ListPool <IntPoint> .Claim(); Dictionary <TriangulationPoint, int> dictionary = new Dictionary <TriangulationPoint, int>(); List <PolygonPoint> list9 = ListPool <PolygonPoint> .Claim(); PolyTree polyTree = new PolyTree(); List <List <IntPoint> > intermediateResult = ListPool <List <IntPoint> > .Claim(); Stack <Polygon> stack = StackPool <Polygon> .Claim(); this.clipper.StrictlySimple = (perturbate > -1); this.clipper.ReverseSolution = true; Int3[] array = null; Int3[] clipOut = null; Int2 size = default(Int2); if (list3.Count > 0) { array = new Int3[7]; clipOut = new Int3[7]; size = new Int2(((Int3)v).x, ((Int3)v).y); } Int3[] array2 = null; for (int k = -1; k < list3.Count; k++) { Int3[] array3; int[] array4; if (k == -1) { array3 = verts; array4 = tris; } else { list3[k].GetMesh(ref array2, out array4, graphTransform2); array3 = array2; } for (int l = 0; l < array4.Length; l += 3) { Int3 int2 = array3[array4[l]]; Int3 int3 = array3[array4[l + 1]]; Int3 int4 = array3[array4[l + 2]]; if (VectorMath.IsColinearXZ(int2, int3, int4)) { Debug.LogWarning("Skipping degenerate triangle."); } else { IntRect a = new IntRect(int2.x, int2.z, int2.x, int2.z); a = a.ExpandToContain(int3.x, int3.z); a = a.ExpandToContain(int4.x, int4.z); int num = Math.Min(int2.y, Math.Min(int3.y, int4.y)); int num2 = Math.Max(int2.y, Math.Max(int3.y, int4.y)); list4.Clear(); bool flag = false; for (int m = 0; m < list5.Count; m++) { int x = list5[m].boundsY.x; int y = list5[m].boundsY.y; if (IntRect.Intersects(a, list5[m].bounds) && y >= num && x <= num2 && (list5[m].cutsAddedGeom || k == -1)) { Int3 int5 = int2; int5.y = x; Int3 int6 = int2; int6.y = y; list4.Add(m); flag |= list5[m].isDual; } } if (list4.Count == 0 && (mode & TileHandler.CutMode.CutExtra) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0 && k == -1) { list7.Add(list6.Count); list7.Add(list6.Count + 1); list7.Add(list6.Count + 2); list6.Add(int2); list6.Add(int3); list6.Add(int4); } else { list8.Clear(); if (k == -1) { list8.Add(new IntPoint((long)int2.x, (long)int2.z)); list8.Add(new IntPoint((long)int3.x, (long)int3.z)); list8.Add(new IntPoint((long)int4.x, (long)int4.z)); } else { array[0] = int2; array[1] = int3; array[2] = int4; int num3 = this.ClipAgainstRectangle(array, clipOut, size); if (num3 == 0) { goto IL_8D1; } for (int n = 0; n < num3; n++) { list8.Add(new IntPoint((long)array[n].x, (long)array[n].z)); } } dictionary.Clear(); for (int num4 = 0; num4 < 16; num4++) { if ((mode >> (num4 & 31) & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { if (1 << num4 == 1) { this.CutAll(list8, list4, list5, polyTree); } else if (1 << num4 == 2) { if (!flag) { goto IL_8C2; } this.CutDual(list8, list4, list5, flag, intermediateResult, polyTree); } else if (1 << num4 == 4) { this.CutExtra(list8, list, polyTree); } for (int num5 = 0; num5 < polyTree.ChildCount; num5++) { PolyNode polyNode = polyTree.Childs[num5]; List <IntPoint> contour = polyNode.Contour; List <PolyNode> childs = polyNode.Childs; if (childs.Count == 0 && contour.Count == 3 && k == -1) { for (int num6 = 0; num6 < 3; num6++) { Int3 int7 = new Int3((int)contour[num6].X, 0, (int)contour[num6].Y); int7.y = Polygon.SampleYCoordinateInTriangle(int2, int3, int4, int7); list7.Add(list6.Count); list6.Add(int7); } } else { Polygon polygon = null; int num7 = -1; for (List <IntPoint> list10 = contour; list10 != null; list10 = ((num7 < childs.Count) ? childs[num7].Contour : null)) { list9.Clear(); for (int num8 = 0; num8 < list10.Count; num8++) { PolygonPoint polygonPoint = new PolygonPoint((double)list10[num8].X, (double)list10[num8].Y); list9.Add(polygonPoint); Int3 int8 = new Int3((int)list10[num8].X, 0, (int)list10[num8].Y); int8.y = Polygon.SampleYCoordinateInTriangle(int2, int3, int4, int8); dictionary[polygonPoint] = list6.Count; list6.Add(int8); } Polygon polygon2; if (stack.Count > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list9); } else { polygon2 = new Polygon(list9); } if (num7 == -1) { polygon = polygon2; } else { polygon.AddHole(polygon2); } num7++; } try { P2T.Triangulate(polygon); } catch (PointOnEdgeException) { Debug.LogWarning("PointOnEdgeException, perturbating vertices slightly.\nThis is usually fine. It happens sometimes because of rounding errors. Cutting will be retried a few more times."); return(this.CutPoly(verts, tris, extraShape, graphTransform, tiles, mode, perturbate + 1)); } try { for (int num9 = 0; num9 < polygon.Triangles.Count; num9++) { DelaunayTriangle delaunayTriangle = polygon.Triangles[num9]; list7.Add(dictionary[delaunayTriangle.Points._0]); list7.Add(dictionary[delaunayTriangle.Points._1]); list7.Add(dictionary[delaunayTriangle.Points._2]); } } catch (KeyNotFoundException) { Debug.LogWarning("KeyNotFoundException, perturbating vertices slightly.\nThis is usually fine. It happens sometimes because of rounding errors. Cutting will be retried a few more times."); return(this.CutPoly(verts, tris, extraShape, graphTransform, tiles, mode, perturbate + 1)); } TileHandler.PoolPolygon(polygon, stack); } } } IL_8C2 :; } } } IL_8D1 :; } } if (array2 != null) { ArrayPool <Int3> .Release(ref array2, false); } StackPool <Polygon> .Release(stack); ListPool <List <IntPoint> > .Release(ref intermediateResult); ListPool <IntPoint> .Release(ref list8); ListPool <PolygonPoint> .Release(ref list9); } TileHandler.CuttingResult result2 = default(TileHandler.CuttingResult); Polygon.CompressMesh(list6, list7, out result2.verts, out result2.tris); for (int num10 = 0; num10 < list2.Count; num10++) { list2[num10].UsedForCut(); } ListPool <Int3> .Release(ref list6); ListPool <int> .Release(ref list7); ListPool <int> .Release(ref list4); for (int num11 = 0; num11 < list5.Count; num11++) { ListPool <IntPoint> .Release(list5[num11].contour); } ListPool <TileHandler.Cut> .Release(ref list5); ListPool <NavmeshCut> .Release(ref list2); return(result2); }
/// <summary> /// Scan part of the FlipScan algorithm<br> /// When a triangle pair isn't flippable we will scan for the next /// point that is inside the flip triangle scan area. When found /// we generate a new flipEdgeEvent /// </summary> /// <param name="tcx"></param> /// <param name="ep">last point on the edge we are traversing</param> /// <param name="eq">first point on the edge we are traversing</param> /// <param name="flipTriangle">the current triangle sharing the point eq with edge</param> /// <param name="t"></param> /// <param name="p"></param> private static void FlipScanEdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle flipTriangle, DelaunayTriangle t, TriangulationPoint p) { DelaunayTriangle ot = t.NeighborAcross(p); TriangulationPoint op = ot.OppositePoint(t, p); if (ot == null) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here throw new Exception("[BUG:FIXME] FLIP failed due to missing triangle"); } bool inScanArea = TriangulationUtil.InScanArea(eq, flipTriangle.PointCCW(eq), flipTriangle.PointCW(eq), op); if (inScanArea) { // flip with new edge op->eq FlipEdgeEvent(tcx, eq, op, ot, op); // TODO: Actually I just figured out that it should be possible to // improve this by getting the next ot and op before the the above // flip and continue the flipScanEdgeEvent here // set new ot and op here and loop back to inScanArea test // also need to set a new flipTriangle first // Turns out at first glance that this is somewhat complicated // so it will have to wait. } else { TriangulationPoint newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, flipTriangle, ot, newP); } }
private void CutPoly(VInt3[] verts, int[] tris, ref VInt3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, VInt3[] extraShape, VInt3 cuttingOffset, Bounds realBounds, TileHandler.CutMode mode = TileHandler.CutMode.CutAll, int perturbate = 0) { if (verts.Length == 0 || tris.Length == 0) { outVCount = 0; outTCount = 0; outTrisArr = new int[0]; outVertsArr = new VInt3[0]; return; } List <IntPoint> list = null; if (extraShape == null && (mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 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 <VInt3> list4 = ListPool <VInt3> .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 <Polygon> stack = new Stack <Polygon>(); if (this.clipper == null) { this.clipper = new Clipper(0); } this.clipper.set_ReverseSolution(true); this.clipper.set_StrictlySimple(true); ListView <NavmeshCut> listView; if (mode == TileHandler.CutMode.CutExtra) { listView = new ListView <NavmeshCut>(); } else { listView = NavmeshCut.GetAllInRange(realBounds); } List <int> list7 = ListPool <int> .Claim(); List <IntRect> list8 = ListPool <IntRect> .Claim(); List <VInt2> list9 = ListPool <VInt2> .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; } Random random = null; if (perturbate > 0) { random = new Random(); } for (int k = 0; k < listView.Count; k++) { Bounds bounds = listView[k].GetBounds(); VInt3 vInt = (VInt3)bounds.min + cuttingOffset; VInt3 vInt2 = (VInt3)bounds.max + cuttingOffset; IntRect a = new IntRect(vInt.x, vInt.z, vInt2.x, vInt2.z); if (IntRect.Intersects(a, b)) { VInt2 vInt3 = new VInt2(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.get_Count(); listView[k].GetContour(list10); for (int l = count; l < list10.get_Count(); l++) { List <IntPoint> list13 = list10.get_Item(l); if (list13.get_Count() == 0) { Debug.LogError("Zero Length Contour"); list8.Add(default(IntRect)); list9.Add(new VInt2(0, 0)); } else { IntRect intRect = new IntRect((int)list13.get_Item(0).X + cuttingOffset.x, (int)list13.get_Item(0).Y + cuttingOffset.y, (int)list13.get_Item(0).X + cuttingOffset.x, (int)list13.get_Item(0).Y + cuttingOffset.y); for (int m = 0; m < list13.get_Count(); m++) { IntPoint intPoint = list13.get_Item(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.set_Item(m, intPoint); intRect = intRect.ExpandToContain((int)intPoint.X, (int)intPoint.Y); } list9.Add(new VInt2(vInt.y, vInt2.y)); list8.Add(intRect); list11.Add(listView[k].isDual); list12.Add(listView[k].cutsAddedGeom); } } } } List <NavmeshAdd> allInRange = NavmeshAdd.GetAllInRange(realBounds); VInt3[] array = verts; int[] array2 = tris; int num = -1; int n = -3; VInt3[] array3 = null; VInt3[] array4 = null; VInt3 vInt4 = VInt3.zero; if (allInRange.get_Count() > 0) { array3 = new VInt3[7]; array4 = new VInt3[7]; vInt4 = (VInt3)realBounds.extents; } while (true) { n += 3; while (n >= array2.Length) { num++; n = 0; if (num >= allInRange.get_Count()) { array = null; break; } if (array == verts) { array = null; } allInRange.get_Item(num).GetMesh(cuttingOffset, ref array, out array2); } if (array == null) { break; } VInt3 vInt5 = array[array2[n]]; VInt3 vInt6 = array[array2[n + 1]]; VInt3 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.get_Count(); num4++) { int x = list9.get_Item(num4).x; int y = list9.get_Item(num4).y; if (IntRect.Intersects(a2, list8.get_Item(num4)) && y >= num2 && x <= num3 && (list12.get_Item(num4) || num == -1)) { VInt3 vInt8 = vInt5; vInt8.y = x; VInt3 vInt9 = vInt5; vInt9.y = y; list7.Add(num4); flag |= list11.get_Item(num4); } } if (list7.get_Count() == 0 && (mode & TileHandler.CutMode.CutExtra) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0 && num == -1) { list5.Add(list4.get_Count()); list5.Add(list4.get_Count() + 1); list5.Add(list4.get_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(); VInt3 vInt10 = vInt6 - vInt5; VInt3 vInt11 = vInt7 - vInt5; VInt3 vInt12 = vInt10; VInt3 vInt13 = vInt11; vInt12.y = 0; vInt13.y = 0; for (int num7 = 0; num7 < 16; num7++) { if ((mode >> (num7 & 31 & 31) & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { if (1 << num7 == 1) { this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num8 = 0; num8 < list7.get_Count(); num8++) { this.clipper.AddPolygon(list10.get_Item(list7.get_Item(num8)), 1); } polyTree.Clear(); this.clipper.Execute(2, polyTree, 0, 1); } else if (1 << num7 == 2) { if (!flag) { goto IL_116B; } this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num9 = 0; num9 < list7.get_Count(); num9++) { if (list11.get_Item(list7.get_Item(num9))) { this.clipper.AddPolygon(list10.get_Item(list7.get_Item(num9)), 1); } } list6.Clear(); this.clipper.Execute(0, list6, 0, 1); this.clipper.Clear(); for (int num10 = 0; num10 < list6.get_Count(); num10++) { this.clipper.AddPolygon(list6.get_Item(num10), Clipper.Orientation(list6.get_Item(num10)) ? 1 : 0); } for (int num11 = 0; num11 < list7.get_Count(); num11++) { if (!list11.get_Item(list7.get_Item(num11))) { this.clipper.AddPolygon(list10.get_Item(list7.get_Item(num11)), 1); } } polyTree.Clear(); this.clipper.Execute(2, polyTree, 0, 1); } else if (1 << num7 == 4) { this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); this.clipper.AddPolygon(list, 1); polyTree.Clear(); this.clipper.Execute(0, polyTree, 0, 1); } for (int num12 = 0; num12 < polyTree.get_ChildCount(); num12++) { PolyNode polyNode = polyTree.get_Childs().get_Item(num12); List <IntPoint> contour = polyNode.get_Contour(); List <PolyNode> childs = polyNode.get_Childs(); if (childs.get_Count() == 0 && contour.get_Count() == 3 && num == -1) { for (int num13 = 0; num13 < contour.get_Count(); num13++) { VInt3 vInt14 = new VInt3((int)contour.get_Item(num13).X, 0, (int)contour.get_Item(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 = MMGame_Math.RoundToInt(num15 * (double)vInt5.y + num16 * (double)vInt6.y + (1.0 - num15 - num16) * (double)vInt7.y); list5.Add(list4.get_Count()); list4.Add(vInt14); } } } else { Polygon polygon = null; int num17 = -1; for (List <IntPoint> list14 = contour; list14 != null; list14 = ((num17 < childs.get_Count()) ? childs.get_Item(num17).get_Contour() : null)) { list3.Clear(); for (int num18 = 0; num18 < list14.get_Count(); num18++) { PolygonPoint polygonPoint = new PolygonPoint((double)list14.get_Item(num18).X, (double)list14.get_Item(num18).Y); list3.Add(polygonPoint); VInt3 vInt15 = new VInt3((int)list14.get_Item(num18).X, 0, (int)list14.get_Item(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 = MMGame_Math.RoundToInt(num20 * (double)vInt5.y + num21 * (double)vInt6.y + (1.0 - num20 - num21) * (double)vInt7.y); dictionary.set_Item(polygonPoint, list4.get_Count()); list4.Add(vInt15); } } Polygon polygon2; if (stack.get_Count() > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list3); } else { polygon2 = new 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(verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1); return; } for (int num22 = 0; num22 < polygon.get_Triangles().get_Count(); num22++) { DelaunayTriangle delaunayTriangle = polygon.get_Triangles().get_Item(num22); list5.Add(dictionary.get_Item(delaunayTriangle.Points._0)); list5.Add(dictionary.get_Item(delaunayTriangle.Points._1)); list5.Add(dictionary.get_Item(delaunayTriangle.Points._2)); } if (polygon.get_Holes() != null) { for (int num23 = 0; num23 < polygon.get_Holes().get_Count(); num23++) { polygon.get_Holes().get_Item(num23).get_Points().Clear(); polygon.get_Holes().get_Item(num23).ClearTriangles(); if (polygon.get_Holes().get_Item(num23).get_Holes() != null) { polygon.get_Holes().get_Item(num23).get_Holes().Clear(); } stack.Push(polygon.get_Holes().get_Item(num23)); } } polygon.ClearTriangles(); if (polygon.get_Holes() != null) { polygon.get_Holes().Clear(); } polygon.get_Points().Clear(); stack.Push(polygon); } } } IL_116B :; } } } Dictionary <VInt3, int> dictionary2 = this.cached_Int3_int_dict; dictionary2.Clear(); if (this.cached_int_array.Length < list4.get_Count()) { this.cached_int_array = new int[Math.Max(this.cached_int_array.Length * 2, list4.get_Count())]; } int[] array5 = this.cached_int_array; int num24 = 0; for (int num25 = 0; num25 < list4.get_Count(); num25++) { int num26; if (!dictionary2.TryGetValue(list4.get_Item(num25), ref num26)) { dictionary2.Add(list4.get_Item(num25), num24); array5[num25] = num24; list4.set_Item(num24, list4.get_Item(num25)); num24++; } else { array5[num25] = num26; } } outTCount = list5.get_Count(); if (outTrisArr == null || outTrisArr.Length < outTCount) { outTrisArr = new int[outTCount]; } for (int num27 = 0; num27 < outTCount; num27++) { outTrisArr[num27] = array5[list5.get_Item(num27)]; } outVCount = num24; if (outVertsArr == null || outVertsArr.Length < outVCount) { outVertsArr = new VInt3[outVCount]; } for (int num28 = 0; num28 < outVCount; num28++) { outVertsArr[num28] = list4.get_Item(num28); } for (int num29 = 0; num29 < listView.Count; num29++) { listView[num29].UsedForCut(); } ListPool <VInt3> .Release(list4); ListPool <int> .Release(list5); ListPool <int> .Release(list7); ListPool <VInt2> .Release(list9); ListPool <bool> .Release(list11); ListPool <bool> .Release(list12); ListPool <IntRect> .Release(list8); }
/// <summary> /// When we need to traverse from one triangle to the next we need /// the point in current triangle that is the opposite point to the next /// triangle. /// </summary> private static TriangulationPoint NextFlipPoint(TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle ot, TriangulationPoint op) { Orientation o2d = TriangulationUtil.Orient2d(eq, op, ep); if (o2d == Orientation.CW) { // Right return ot.PointCCW(op); } else if (o2d == Orientation.CCW) { // Left return ot.PointCW(op); } else { // TODO: implement support for point on constraint edge throw new PointOnEdgeException("Point on constrained edge not supported yet"); } }
GameObject GenerateProvinceRegionSurface(int provinceIndex, int regionIndex, Material material) { Region region = provinces [provinceIndex].regions [regionIndex]; Polygon poly = new Polygon(region.latlon); // Antarctica, Saskatchewan (Canada), British Columbia (Canada), Krasnoyarsk (Russia) - special cases due to its geometry if (provinceIndex == 218 || provinceIndex == 220 || provinceIndex == 224 || provinceIndex == 3423) { float step = 5; List <TriangulationPoint> steinerPoints = new List <TriangulationPoint>(); for (double x = region.minMaxLat.x + step / 2; x < region.minMaxLat.y - step / 2; x += step) { for (double y = region.minMaxLon.x + step / 2; y < region.minMaxLon.y - step / 2; y += step) { if (region.ContainsPoint(x, y)) { steinerPoints.Add(new TriangulationPoint(x, y)); } } } poly.AddSteinerPoints(steinerPoints); } P2T.Triangulate(poly); int flip1, flip2; if (_earthInvertedMode) { flip1 = 2; flip2 = 1; } else { flip1 = 1; flip2 = 2; } Vector3[] revisedSurfPoints = new Vector3[poly.Triangles.Count * 3]; for (int k = 0; k < poly.Triangles.Count; k++) { DelaunayTriangle dt = poly.Triangles[k]; revisedSurfPoints[k * 3] = GetSpherePointFromLatLon(dt.Points[0].X, dt.Points[0].Y); revisedSurfPoints[k * 3 + flip1] = GetSpherePointFromLatLon(dt.Points[1].X, dt.Points[1].Y); revisedSurfPoints[k * 3 + flip2] = GetSpherePointFromLatLon(dt.Points[2].X, dt.Points[2].Y); } int revIndex = revisedSurfPoints.Length - 1; // Generate surface mesh int cacheIndex = GetCacheIndexForProvinceRegion(provinceIndex, regionIndex); string cacheIndexSTR = cacheIndex.ToString(); // Deletes potential residual surface Transform t = surfacesLayer.transform.FindChild(cacheIndexSTR); if (t != null) { DestroyImmediate(t.gameObject); } GameObject surf = Drawing.CreateSurface(cacheIndexSTR, revisedSurfPoints, revIndex, material); surf.transform.SetParent(transform, false); surf.transform.localPosition = MiscVector.Vector3zero; if (_earthInvertedMode) { surf.transform.localScale = MiscVector.Vector3one * 0.998f; } if (surfaces.ContainsKey(cacheIndex)) { surfaces.Remove(cacheIndex); } surfaces.Add(cacheIndex, surf); return(surf); }
/// <summary> /// When we need to traverse from one triangle to the next we need /// the point in current triangle that is the opposite point to the next /// triangle. /// </summary> private static TriangulationPoint NextFlipPoint(TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle ot, TriangulationPoint op) { Orientation o2d = TriangulationUtil.Orient2d(eq, op, ep); if (o2d == Orientation.CW) { // Right return(ot.PointCCW(op)); } else if (o2d == Orientation.CCW) { // Left return(ot.PointCW(op)); } else { // TODO: implement support for point on constraint edge throw new PointOnEdgeException("Point on constrained edge not supported yet"); } }
private static void EdgeEvent( DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle triangle, TriangulationPoint point ) { TriangulationPoint p1, p2; if (tcx.IsDebugEnabled) tcx.DTDebugContext.PrimaryTriangle=triangle; if (IsEdgeSideOfTriangle(triangle, ep, eq)) return; p1 = triangle.PointCCWFrom(point); Orientation o1 = TriangulationUtil.Orient2d(eq, p1, ep); if (o1 == Orientation.Collinear) { // TODO: Split edge in two //// splitEdge( ep, eq, p1 ); // edgeEvent( tcx, p1, eq, triangle, point ); // edgeEvent( tcx, ep, p1, triangle, p1 ); // return; throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet",eq,p1,ep); } p2 = triangle.PointCWFrom(point); Orientation o2 = TriangulationUtil.Orient2d(eq, p2, ep); if (o2 == Orientation.Collinear) { // TODO: Split edge in two // edgeEvent( tcx, p2, eq, triangle, point ); // edgeEvent( tcx, ep, p2, triangle, p2 ); // return; throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet",eq,p2,ep); } if (o1 == o2) { // Need to decide if we are rotating CW or CCW to get to a triangle // that will cross edge if (o1 == Orientation.CW) { triangle = triangle.NeighborCCWFrom(point); } else { triangle = triangle.NeighborCWFrom(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! FlipEdgeEvent(tcx, ep, eq, triangle, point); } }
/// <summary> /// Creates a new front triangle and legalize it /// </summary> private static AdvancingFrontNode NewFrontTriangle( DTSweepContext tcx, TriangulationPoint point, AdvancingFrontNode node ) { AdvancingFrontNode newNode; DelaunayTriangle triangle; triangle = new DelaunayTriangle(point, node.Point, node.Next.Point); triangle.MarkNeighbor(node.Triangle); tcx.Triangles.Add(triangle); newNode = new AdvancingFrontNode(point) {Next = node.Next, Prev = node}; node.Next.Prev = newNode; node.Next = newNode; tcx.AddNode(newNode); // XXX: BST if (tcx.IsDebugEnabled) tcx.DTDebugContext.ActiveNode = newNode; if (!Legalize(tcx, triangle)) tcx.MapTriangleToNodes(triangle); return newNode; }
/// <summary> /// When we need to traverse from one triangle to the next we need /// the point in current triangle that is the opposite point to the next /// triangle. /// </summary> private static TriangulationPoint NextFlipPoint( TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle ot, TriangulationPoint op ) { Orientation o2d = TriangulationUtil.Orient2d(eq, op, ep); switch ( o2d ) { case Orientation.CW: return ot.PointCCWFrom(op); case Orientation.CCW: return ot.PointCWFrom(op); case Orientation.Collinear: // TODO: implement support for point on constraint edge throw new PointOnEdgeException("Point on constrained edge not supported yet",eq,op,ep); default: throw new NotImplementedException("Orientation not handled"); } }
public static GameObject CreateSurface(string name, Polygon poly, Material material, Rect rect, Vector2 textureScale, Vector2 textureOffset, float textureRotation, DisposalManager disposalManager) { GameObject hexa = new GameObject(name, typeof(MeshRenderer), typeof(MeshFilter)); int triCount = poly.Triangles.Count; if (newPoints == null) { newPoints = new List <Vector3> (triCount * 3); } else { newPoints.Clear(); } int[] triNew = new int[triCount * 3]; int newPointsCount = -1; if (hit == null) { hit = new Dictionary <Vector3, int> (20000); } else { hit.Clear(); } Vector3 p; p.z = 0; for (int k = 0; k < triCount; k++) { DelaunayTriangle dt = poly.Triangles [k]; int ptmp; p.x = dt.Points [0].Xf; p.y = dt.Points [0].Yf; if (hit.TryGetValue(p, out ptmp)) { triNew [k * 3] = ptmp; } else { newPoints.Add(p); hit [p] = ++newPointsCount; triNew [k * 3] = newPointsCount; } p.x = dt.Points [2].Xf; p.y = dt.Points [2].Yf; if (hit.TryGetValue(p, out ptmp)) { triNew [k * 3 + 1] = ptmp; } else { newPoints.Add(p); hit [p] = ++newPointsCount; triNew [k * 3 + 1] = newPointsCount; } p.x = dt.Points [1].Xf; p.y = dt.Points [1].Yf; if (hit.TryGetValue(p, out ptmp)) { triNew [k * 3 + 2] = ptmp; } else { newPoints.Add(p); hit [p] = ++newPointsCount; triNew [k * 3 + 2] = newPointsCount; } } Mesh mesh = new Mesh(); if (disposalManager != null) { if (disposalManager != null) { disposalManager.MarkForDisposal(hexa); } if (disposalManager != null) { disposalManager.MarkForDisposal(mesh); } } hexa.hideFlags |= HideFlags.HideInHierarchy; mesh.SetVertices(newPoints); // uv mapping if (material.mainTexture != null) { Vector2[] uv = new Vector2[newPoints.Count]; for (int k = 0; k < uv.Length; k++) { Vector2 coor = newPoints [k]; coor.x /= textureScale.x; coor.y /= textureScale.y; if (textureRotation != 0) { coor = RotatePoint(coor, Misc.Vector2zero, textureRotation); } coor += textureOffset; uv [k].x = (coor.x - rect.xMin) / rect.width; uv [k].y = (coor.y - rect.yMax) / rect.height; } mesh.uv = uv; } mesh.SetTriangles(triNew, 0); mesh.RecalculateNormals(); MeshFilter meshFilter = hexa.GetComponent <MeshFilter> (); meshFilter.mesh = mesh; hexa.GetComponent <MeshRenderer> ().sharedMaterial = material; return(hexa); }
/// <summary> /// Try to map a node to all sides of this triangle that don't have /// a neighbor. /// </summary> public void MapTriangleToNodes(DelaunayTriangle t) { AdvancingFrontNode n; for (int i = 0; i < 3; i++) { if (t.Neighbors[i] == null) { n = aFront.LocatePoint(t.PointCW(t.Points[i])); if (n != null) { n.Triangle = t; } } } }
private void CutPoly(Int3[] verts, int[] tris, ref Int3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, Int3[] extraShape, Int3 cuttingOffset, Bounds realBounds, TileHandler.CutMode mode = TileHandler.CutMode.CutAll | TileHandler.CutMode.CutDual, 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 & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 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>(); Pathfinding.IntRect b = new Pathfinding.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 <Pathfinding.Poly2Tri.Polygon> stack = new Stack <Pathfinding.Poly2Tri.Polygon>(); this.clipper = (this.clipper ?? new Clipper(0)); this.clipper.ReverseSolution = true; this.clipper.StrictlySimple = true; List <NavmeshCut> list7; if (mode == TileHandler.CutMode.CutExtra) { list7 = ListPool <NavmeshCut> .Claim(); } else { list7 = NavmeshCut.GetAllInRange(realBounds); } List <int> list8 = ListPool <int> .Claim(); List <Pathfinding.IntRect> list9 = ListPool <Pathfinding.IntRect> .Claim(); List <Int2> list10 = ListPool <Int2> .Claim(); List <List <IntPoint> > list11 = new List <List <IntPoint> >(); List <bool> list12 = ListPool <bool> .Claim(); List <bool> list13 = 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 < list7.Count; k++) { Bounds bounds = list7[k].GetBounds(); Int3 @int = (Int3)bounds.min + cuttingOffset; Int3 int2 = (Int3)bounds.max + cuttingOffset; Pathfinding.IntRect a = new Pathfinding.IntRect(@int.x, @int.z, int2.x, int2.z); if (Pathfinding.IntRect.Intersects(a, b)) { Int2 int3 = new Int2(0, 0); if (perturbate > 0) { int3.x = random.Next() % 6 * perturbate - 3 * perturbate; if (int3.x >= 0) { int3.x++; } int3.y = random.Next() % 6 * perturbate - 3 * perturbate; if (int3.y >= 0) { int3.y++; } } int count = list11.Count; list7[k].GetContour(list11); for (int l = count; l < list11.Count; l++) { List <IntPoint> list14 = list11[l]; if (list14.Count == 0) { Debug.LogError("Zero Length Contour"); list9.Add(default(Pathfinding.IntRect)); list10.Add(new Int2(0, 0)); } else { Pathfinding.IntRect item = new Pathfinding.IntRect((int)list14[0].X + cuttingOffset.x, (int)list14[0].Y + cuttingOffset.y, (int)list14[0].X + cuttingOffset.x, (int)list14[0].Y + cuttingOffset.y); for (int m = 0; m < list14.Count; m++) { IntPoint value = list14[m]; value.X += (long)cuttingOffset.x; value.Y += (long)cuttingOffset.z; if (perturbate > 0) { value.X += (long)int3.x; value.Y += (long)int3.y; } list14[m] = value; item = item.ExpandToContain((int)value.X, (int)value.Y); } list10.Add(new Int2(@int.y, int2.y)); list9.Add(item); list12.Add(list7[k].isDual); list13.Add(list7[k].cutsAddedGeom); } } } } List <NavmeshAdd> allInRange = NavmeshAdd.GetAllInRange(realBounds); Int3[] array = verts; int[] array2 = tris; int num = -1; int n = -3; Int3[] array3 = null; Int3[] array4 = null; Int3 int4 = Int3.zero; if (allInRange.Count > 0) { array3 = new Int3[7]; array4 = new Int3[7]; int4 = (Int3)realBounds.extents; } while (true) { n += 3; while (n >= array2.Length) { num++; n = 0; if (num >= allInRange.Count) { array = null; break; } if (array == verts) { array = null; } allInRange[num].GetMesh(cuttingOffset, ref array, out array2); } if (array == null) { break; } Int3 int5 = array[array2[n]]; Int3 int6 = array[array2[n + 1]]; Int3 int7 = array[array2[n + 2]]; Pathfinding.IntRect a2 = new Pathfinding.IntRect(int5.x, int5.z, int5.x, int5.z); a2 = a2.ExpandToContain(int6.x, int6.z); a2 = a2.ExpandToContain(int7.x, int7.z); int num2 = Math.Min(int5.y, Math.Min(int6.y, int7.y)); int num3 = Math.Max(int5.y, Math.Max(int6.y, int7.y)); list8.Clear(); bool flag = false; for (int num4 = 0; num4 < list11.Count; num4++) { int x = list10[num4].x; int y = list10[num4].y; if (Pathfinding.IntRect.Intersects(a2, list9[num4]) && y >= num2 && x <= num3 && (list13[num4] || num == -1)) { Int3 int8 = int5; int8.y = x; Int3 int9 = int5; int9.y = y; list8.Add(num4); flag |= list12[num4]; } } if (list8.Count == 0 && (mode & TileHandler.CutMode.CutExtra) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0 && num == -1) { list5.Add(list4.Count); list5.Add(list4.Count + 1); list5.Add(list4.Count + 2); list4.Add(int5); list4.Add(int6); list4.Add(int7); } else { list2.Clear(); if (num == -1) { list2.Add(new IntPoint((long)int5.x, (long)int5.z)); list2.Add(new IntPoint((long)int6.x, (long)int6.z)); list2.Add(new IntPoint((long)int7.x, (long)int7.z)); } else { array3[0] = int5; array3[1] = int6; array3[2] = int7; int num5 = Utility.ClipPolygon(array3, 3, array4, 1, 0, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * int4.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 * int4.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 int10 = int6 - int5; Int3 int11 = int7 - int5; Int3 int12 = int10; Int3 int13 = int11; int12.y = 0; int13.y = 0; for (int num7 = 0; num7 < 16; num7++) { if ((mode >> (num7 & 31) & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { if (1 << num7 == 1) { this.clipper.Clear(); this.clipper.AddPolygon(list2, PolyType.ptSubject); for (int num8 = 0; num8 < list8.Count; num8++) { this.clipper.AddPolygon(list11[list8[num8]], PolyType.ptClip); } polyTree.Clear(); this.clipper.Execute(ClipType.ctDifference, polyTree, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); } else if (1 << num7 == 2) { if (!flag) { goto IL_1174; } this.clipper.Clear(); this.clipper.AddPolygon(list2, PolyType.ptSubject); for (int num9 = 0; num9 < list8.Count; num9++) { if (list12[list8[num9]]) { this.clipper.AddPolygon(list11[list8[num9]], PolyType.ptClip); } } list6.Clear(); this.clipper.Execute(ClipType.ctIntersection, list6, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); this.clipper.Clear(); for (int num10 = 0; num10 < list6.Count; num10++) { this.clipper.AddPolygon(list6[num10], (!Clipper.Orientation(list6[num10])) ? PolyType.ptSubject : PolyType.ptClip); } for (int num11 = 0; num11 < list8.Count; num11++) { if (!list12[list8[num11]]) { this.clipper.AddPolygon(list11[list8[num11]], PolyType.ptClip); } } polyTree.Clear(); this.clipper.Execute(ClipType.ctDifference, polyTree, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); } else if (1 << num7 == 4) { this.clipper.Clear(); this.clipper.AddPolygon(list2, PolyType.ptSubject); this.clipper.AddPolygon(list, PolyType.ptClip); polyTree.Clear(); this.clipper.Execute(ClipType.ctIntersection, polyTree, PolyFillType.pftEvenOdd, 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 item2 = new Int3((int)contour[num13].X, 0, (int)contour[num13].Y); double num14 = (double)(int6.z - int7.z) * (double)(int5.x - int7.x) + (double)(int7.x - int6.x) * (double)(int5.z - int7.z); if (num14 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num15 = ((double)(int6.z - int7.z) * (double)(item2.x - int7.x) + (double)(int7.x - int6.x) * (double)(item2.z - int7.z)) / num14; double num16 = ((double)(int7.z - int5.z) * (double)(item2.x - int7.x) + (double)(int5.x - int7.x) * (double)(item2.z - int7.z)) / num14; item2.y = (int)Math.Round(num15 * (double)int5.y + num16 * (double)int6.y + (1.0 - num15 - num16) * (double)int7.y); list5.Add(list4.Count); list4.Add(item2); } } } else { Pathfinding.Poly2Tri.Polygon polygon = null; int num17 = -1; for (List <IntPoint> list15 = contour; list15 != null; list15 = ((num17 >= childs.Count) ? null : childs[num17].Contour)) { list3.Clear(); for (int num18 = 0; num18 < list15.Count; num18++) { PolygonPoint polygonPoint = new PolygonPoint((double)list15[num18].X, (double)list15[num18].Y); list3.Add(polygonPoint); Int3 item3 = new Int3((int)list15[num18].X, 0, (int)list15[num18].Y); double num19 = (double)(int6.z - int7.z) * (double)(int5.x - int7.x) + (double)(int7.x - int6.x) * (double)(int5.z - int7.z); if (num19 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num20 = ((double)(int6.z - int7.z) * (double)(item3.x - int7.x) + (double)(int7.x - int6.x) * (double)(item3.z - int7.z)) / num19; double num21 = ((double)(int7.z - int5.z) * (double)(item3.x - int7.x) + (double)(int5.x - int7.x) * (double)(item3.z - int7.z)) / num19; item3.y = (int)Math.Round(num20 * (double)int5.y + num21 * (double)int6.y + (1.0 - num20 - num21) * (double)int7.y); dictionary[polygonPoint] = list4.Count; list4.Add(item3); } } Pathfinding.Poly2Tri.Polygon polygon2; if (stack.Count > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list3); } else { polygon2 = new Pathfinding.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(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_1174 :; } } } 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 < list7.Count; num29++) { list7[num29].UsedForCut(); } ListPool <Int3> .Release(list4); ListPool <int> .Release(list5); ListPool <int> .Release(list8); ListPool <Int2> .Release(list10); ListPool <bool> .Release(list12); ListPool <bool> .Release(list13); ListPool <Pathfinding.IntRect> .Release(list9); ListPool <NavmeshCut> .Release(list7); }
public void CreateAdvancingFront() { AdvancingFrontNode head, tail, middle; // Initial triangle DelaunayTriangle iTriangle = new DelaunayTriangle(Points[0], Tail, Head); Triangles.Add(iTriangle); head = new AdvancingFrontNode(iTriangle.Points[1]); head.Triangle = iTriangle; middle = new AdvancingFrontNode(iTriangle.Points[0]); middle.Triangle = iTriangle; tail = new AdvancingFrontNode(iTriangle.Points[2]); aFront = new AdvancingFront(head, tail); aFront.AddNode(middle); // TODO: I think it would be more intuitive if head is middles next and not previous // so swap head and tail aFront.Head.Next = middle; middle.Next = aFront.Tail; middle.Prev = aFront.Head; aFront.Tail.Prev = middle; }
public override void Clear() { PrimaryTriangle = null; SecondaryTriangle = null; ActivePoint = null; ActiveNode = null; ActiveConstraint = null; }
public void AddTriangle(DelaunayTriangle t) { _triangles.Add(t); }
private static void EdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle triangle, TriangulationPoint point) { if (IsEdgeSideOfTriangle(triangle, ep, eq)) return; TriangulationPoint p1 = triangle.PointCCW(point); Orientation o1 = TriangulationUtil.Orient2d(eq, p1, ep); if (o1 == Orientation.Collinear) { if (triangle.Contains(eq, p1)) { triangle.MarkConstrainedEdge(eq, p1); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.EdgeEvent.ConstrainedEdge.Q = p1; triangle = triangle.NeighborAcross(point); EdgeEvent(tcx, ep, p1, triangle, p1); } else { throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet"); } return; } TriangulationPoint p2 = triangle.PointCW(point); Orientation o2 = TriangulationUtil.Orient2d(eq, p2, ep); if (o2 == Orientation.Collinear) { if (triangle.Contains(eq, p2)) { triangle.MarkConstrainedEdge(eq, p2); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.EdgeEvent.ConstrainedEdge.Q = p2; triangle = triangle.NeighborAcross(point); EdgeEvent(tcx, ep, p2, triangle, p2); } else { throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet"); } return; } if (o1 == o2) { // Need to decide if we are rotating CW or CCW to get to a triangle // that will cross edge if (o1 == Orientation.CW) { triangle = triangle.NeighborCCW(point); } else { triangle = triangle.NeighborCW(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! FlipEdgeEvent(tcx, ep, eq, triangle, point); } }
/// <summary> /// Returns true if triangle was legalized /// </summary> private static bool Legalize(DTSweepContext tcx, DelaunayTriangle t) { // To legalize a triangle we start by finding if any of the three edges // violate the Delaunay condition for (int i = 0; i < 3; i++) { // TODO: fix so that cEdge is always valid when creating new triangles then we can check it here // instead of below with ot if (t.EdgeIsDelaunay[i]) { continue; } DelaunayTriangle ot = t.Neighbors[i]; if (ot != null) { TriangulationPoint p = t.Points[i]; TriangulationPoint op = ot.OppositePoint(t, p); int oi = ot.IndexOf(op); // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) // then we should not try to legalize if (ot.EdgeIsConstrained[oi] || ot.EdgeIsDelaunay[oi]) { t.EdgeIsConstrained[i] = ot.EdgeIsConstrained[oi]; // XXX: have no good way of setting this property when creating new triangles so lets set it here continue; } bool inside = TriangulationUtil.SmartIncircle(p, t.PointCCW(p), t.PointCW(p), op); if (inside) { // Lets mark this shared edge as Delaunay t.EdgeIsDelaunay[i] = true; ot.EdgeIsDelaunay[oi] = true; // Lets rotate shared edge one vertex CW to legalize it RotateTrianglePair(t, p, ot, op); // We now got one valid Delaunay Edge shared by two triangles // This gives us 4 new edges to check for Delaunay // Make sure that triangle to node mapping is done only one time for a specific triangle bool notLegalized = !Legalize(tcx, t); if (notLegalized) { tcx.MapTriangleToNodes(t); } notLegalized = !Legalize(tcx, ot); if (notLegalized) { tcx.MapTriangleToNodes(ot); } // Reset the Delaunay edges, since they only are valid Delaunay edges // until we add a new triangle or point. // XXX: need to think about this. Can these edges be tried after we // return to previous recursive level? t.EdgeIsDelaunay[i] = false; ot.EdgeIsDelaunay[oi] = false; // If triangle have been legalized no need to check the other edges since // the recursive legalization will handles those so we can end here. return(true); } } } return(false); }
private static void FlipEdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle t, TriangulationPoint p) { DelaunayTriangle ot = t.NeighborAcross(p); TriangulationPoint op = ot.OppositePoint(t, p); if (ot == null) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here throw new InvalidOperationException("[BUG:FIXME] FLIP failed due to missing triangle"); } if (t.GetConstrainedEdgeAcross(p)) { throw new Exception("Intersecting Constraints"); } bool inScanArea = TriangulationUtil.InScanArea(p, t.PointCCW(p), t.PointCW(p), op); if (inScanArea) { // Lets rotate shared edge one vertex CW RotateTrianglePair(t, p, ot, op); tcx.MapTriangleToNodes(t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == tcx.EdgeEvent.ConstrainedEdge.Q && ep == tcx.EdgeEvent.ConstrainedEdge.P) { t.MarkConstrainedEdge(ep, eq); ot.MarkConstrainedEdge(ep, eq); Legalize(tcx, t); Legalize(tcx, ot); } else { // XXX: I think one of the triangles should be legalized here? } } else { // TODO: remove Orientation o = TriangulationUtil.Orient2d(eq, op, ep); t = NextFlipTriangle(tcx, o, t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { TriangulationPoint newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } }
/// <summary> /// Rotates a triangle pair one vertex CW /// n2 n2 /// P +-----+ P +-----+ /// | t /| |\ t | /// | / | | \ | /// n1| / |n3 n1| \ |n3 /// | / | after CW | \ | /// |/ oT | | oT \| /// +-----+ oP +-----+ /// n4 n4 /// </summary> private static void RotateTrianglePair(DelaunayTriangle t, TriangulationPoint p, DelaunayTriangle ot, TriangulationPoint op) { DelaunayTriangle n1 = t.NeighborCCW(p); DelaunayTriangle n2 = t.NeighborCW(p); DelaunayTriangle n3 = ot.NeighborCCW(op); DelaunayTriangle n4 = ot.NeighborCW(op); bool ce1 = t.GetConstrainedEdgeCCW(p); bool ce2 = t.GetConstrainedEdgeCW(p); bool ce3 = ot.GetConstrainedEdgeCCW(op); bool ce4 = ot.GetConstrainedEdgeCW(op); bool de1 = t.GetDelaunayEdgeCCW(p); bool de2 = t.GetDelaunayEdgeCW(p); bool de3 = ot.GetDelaunayEdgeCCW(op); bool de4 = ot.GetDelaunayEdgeCW(op); t.Legalize(p, op); ot.Legalize(op, p); // Remap dEdge ot.SetDelaunayEdgeCCW(p, de1); t.SetDelaunayEdgeCW(p, de2); t.SetDelaunayEdgeCCW(op, de3); ot.SetDelaunayEdgeCW(op, de4); // Remap cEdge ot.SetConstrainedEdgeCCW(p, ce1); t.SetConstrainedEdgeCW(p, ce2); t.SetConstrainedEdgeCCW(op, ce3); ot.SetConstrainedEdgeCW(op, ce4); // Remap neighbors // XXX: might optimize the markNeighbor by keeping track of // what side should be assigned to what neighbor after the // rotation. Now mark neighbor does lots of testing to find // the right side. t.Neighbors.Clear(); ot.Neighbors.Clear(); if (n1 != null) { ot.MarkNeighbor(n1); } if (n2 != null) { t.MarkNeighbor(n2); } if (n3 != null) { t.MarkNeighbor(n3); } if (n4 != null) { ot.MarkNeighbor(n4); } t.MarkNeighbor(ot); }
private static bool IsEdgeSideOfTriangle(DelaunayTriangle triangle, TriangulationPoint ep, TriangulationPoint eq) { int index = triangle.EdgeIndex(ep, eq); if (index != -1) { triangle.MarkConstrainedEdge(index); triangle = triangle.Neighbors[index]; if (triangle != null) { triangle.MarkConstrainedEdge(ep, eq); } return true; } return false; }
private static void EdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle triangle, TriangulationPoint point) { if (IsEdgeSideOfTriangle(triangle, ep, eq)) { return; } TriangulationPoint p1 = triangle.PointCCW(point); Orientation o1 = TriangulationUtil.Orient2d(eq, p1, ep); if (o1 == Orientation.Collinear) { if (triangle.Contains(eq, p1)) { triangle.MarkConstrainedEdge(eq, p1); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.EdgeEvent.ConstrainedEdge.Q = p1; triangle = triangle.NeighborAcross(point); EdgeEvent(tcx, ep, p1, triangle, p1); } else { throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet"); } if (tcx.IsDebugEnabled) { Debug.WriteLine("EdgeEvent - Point on constrained edge"); } return; } TriangulationPoint p2 = triangle.PointCW(point); Orientation o2 = TriangulationUtil.Orient2d(eq, p2, ep); if (o2 == Orientation.Collinear) { if (triangle.Contains(eq, p2)) { triangle.MarkConstrainedEdge(eq, p2); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.EdgeEvent.ConstrainedEdge.Q = p2; triangle = triangle.NeighborAcross(point); EdgeEvent(tcx, ep, p2, triangle, p2); } else { throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet"); } if (tcx.IsDebugEnabled) { Debug.WriteLine("EdgeEvent - Point on constrained edge"); } return; } if (o1 == o2) { // Need to decide if we are rotating CW or CCW to get to a triangle // that will cross edge if (o1 == Orientation.CW) { triangle = triangle.NeighborCCW(point); } else { triangle = triangle.NeighborCW(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! FlipEdgeEvent(tcx, ep, eq, triangle, point); } }
/// <summary> /// Creates a new front triangle and legalize it /// </summary> private static AdvancingFrontNode NewFrontTriangle(DTSweepContext tcx, TriangulationPoint point, AdvancingFrontNode node) { DelaunayTriangle triangle = new DelaunayTriangle(point, node.Point, node.Next.Point); triangle.MarkNeighbor(node.Triangle); tcx.Triangles.Add(triangle); AdvancingFrontNode newNode = new AdvancingFrontNode(point); newNode.Next = node.Next; newNode.Prev = node; node.Next.Prev = newNode; node.Next = newNode; tcx.AddNode(newNode); // XXX: BST if (!Legalize(tcx, triangle)) { tcx.MapTriangleToNodes(triangle); } return newNode; }
private static void FlipEdgeEvent(DTSweepContext tcx, TriangulationPoint ep, TriangulationPoint eq, DelaunayTriangle t, TriangulationPoint p) { DelaunayTriangle ot = t.NeighborAcross(p); TriangulationPoint op = ot.OppositePoint(t, p); if (ot == null) { // If we want to integrate the fillEdgeEvent do it here // With current implementation we should never get here throw new InvalidOperationException("[BUG:FIXME] FLIP failed due to missing triangle"); } if (t.GetConstrainedEdgeAcross(p)) { throw new Exception("Intersecting Constraints"); } bool inScanArea = TriangulationUtil.InScanArea(p, t.PointCCW(p), t.PointCW(p), op); if (inScanArea) { // Lets rotate shared edge one vertex CW RotateTrianglePair(t, p, ot, op); tcx.MapTriangleToNodes(t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == tcx.EdgeEvent.ConstrainedEdge.Q && ep == tcx.EdgeEvent.ConstrainedEdge.P) { if (tcx.IsDebugEnabled) { Console.WriteLine("[FLIP] - constrained edge done"); // TODO: remove } t.MarkConstrainedEdge(ep, eq); ot.MarkConstrainedEdge(ep, eq); Legalize(tcx, t); Legalize(tcx, ot); } else { if (tcx.IsDebugEnabled) { Console.WriteLine("[FLIP] - subedge done"); // TODO: remove } // XXX: I think one of the triangles should be legalized here? } } else { if (tcx.IsDebugEnabled) { Console.WriteLine("[FLIP] - flipping and continuing with triangle still crossing edge"); } // TODO: remove Orientation o = TriangulationUtil.Orient2d(eq, op, ep); t = NextFlipTriangle(tcx, o, t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { TriangulationPoint newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } }
/// <summary> /// After a flip we have two triangles and know that only one will still be /// intersecting the edge. So decide which to contiune with and legalize the other /// </summary> /// <param name="tcx"></param> /// <param name="o">should be the result of an TriangulationUtil.orient2d( eq, op, ep )</param> /// <param name="t">triangle 1</param> /// <param name="ot">triangle 2</param> /// <param name="p">a point shared by both triangles</param> /// <param name="op">another point shared by both triangles</param> /// <returns>returns the triangle still intersecting the edge</returns> private static DelaunayTriangle NextFlipTriangle(DTSweepContext tcx, Orientation o, DelaunayTriangle t, DelaunayTriangle ot, TriangulationPoint p, TriangulationPoint op) { int edgeIndex; if (o == Orientation.CCW) { // ot is not crossing edge after flip edgeIndex = ot.EdgeIndex(p, op); ot.EdgeIsDelaunay[edgeIndex] = true; Legalize(tcx, ot); ot.EdgeIsDelaunay.Clear(); return t; } // t is not crossing edge after flip edgeIndex = t.EdgeIndex(p, op); t.EdgeIsDelaunay[edgeIndex] = true; Legalize(tcx, t); t.EdgeIsDelaunay.Clear(); return ot; }
public virtual void AddTriangle(DelaunayTriangle t) { Triangles.Add(t); }