private static PolyNode StepPath(List<Vector2> route, PolyNode current, PolyNode end, ref Vector2 endv) { if (current == null) return null; if (current == end) { return null; } PolyLink shortestLink = null; float shortestDistance = int.MaxValue; foreach (PolyLink link in current.Links) { var d = Vector2.Distance (link.Target.GetVertex(), endv); if (shortestLink == null || d < shortestDistance) { shortestDistance = d; shortestLink = link.Target; } } if (shortestLink != null) { route.Add (shortestLink.GetVertex()); return shortestLink.Parent; } return null; }
public void RemoveConnection(PolyNode fromMe) { int foundIndex = -1; for (int i=0; i<nConnected; ++i) { if (fromMe == connected[i]) {//.position == connected[i]->position){ foundIndex = i; break; } } //b2Assert(isFound); --nConnected; //printf("nConnected: %d\n",nConnected); for (int i=foundIndex; i < nConnected; ++i) { connected[i] = connected[i+1]; } }
/* Method: Start at vertex with minimum y (pick maximum x one if there are two). We aim our "lastDir" vector at (1.0, 0) We look at the two rays going off from our start vertex, and follow whichever has the smallest angle (in -Pi -> Pi) wrt lastDir ("rightest" turn) Loop until we hit starting vertex: We add our current vertex to the list. We check the seg from current vertex to next vertex for intersections - if no intersections, follow to next vertex and continue - if intersections, pick one with minimum distance - if more than one, pick one with "rightest" next point (two possibilities for each) */ public static Polygon TraceEdge(Polygon p) { List<PolyNode> nodes = new List<PolyNode>();//overkill, but sufficient (order of mag. is right) //Add base nodes (raw outline) for (int i=0; i < p.nVertices; ++i) { Vec2 pos = new Vec2(p.x[i], p.y[i]); nodes.Add(new PolyNode()); nodes[i].position = pos; int iplus = (i==p.nVertices-1)?0:i+1; int iminus = (i==0)?p.nVertices-1:i-1; nodes[i].AddConnection(nodes[iplus]); nodes[i].AddConnection(nodes[iminus]); } //Process intersection nodes - horribly inefficient bool dirty = true; int counter = 0; while (dirty) { dirty = false; for (int i=0; i < nodes.Count; ++i) { for (int j=0; j < nodes[i].nConnected; ++j) { for (int k=0; k < nodes.Count; ++k) { if (k==i || nodes[k] == nodes[i].connected[j]) continue; for (int l=0; l < nodes[k].nConnected; ++l) { if (nodes[k].connected[l] == nodes[i].connected[j] || nodes[k].connected[l] == nodes[i]) continue; //Check intersection Vec2 intersectPt = new Vec2(); //if (counter > 100) printf("checking intersection: %d, %d, %d, %d\n",i,j,k,l); bool crosses = intersect(nodes[i].position, nodes[i].connected[j].position, nodes[k].position, nodes[k].connected[l].position, ref intersectPt); if (crosses) { /*if (counter > 100) { printf("Found crossing at %f, %f\n",intersectPt.X, intersectPt.Y); printf("Locations: %f,%f - %f,%f | %f,%f - %f,%f\n", nodes[i].position.X, nodes[i].position.Y, nodes[i].connected[j]->position.X, nodes[i].connected[j]->position.Y, nodes[k].position.X,nodes[k].position.Y, nodes[k].connected[l]->position.X,nodes[k].connected[l]->position.Y); printf("Memory addresses: %d, %d, %d, %d\n",(int)&nodes[i],(int)nodes[i].connected[j],(int)&nodes[k],(int)nodes[k].connected[l]); }*/ dirty = true; //Destroy and re-hook connections at crossing point PolyNode connj = nodes[i].connected[j]; PolyNode connl = nodes[k].connected[l]; nodes[i].connected[j].RemoveConnection(nodes[i]); nodes[i].RemoveConnection(connj); nodes[k].connected[l].RemoveConnection(nodes[k]); nodes[k].RemoveConnection(connl); int nNodes = nodes.Count; nodes.Add(new PolyNode()); nodes[nNodes] = new PolyNode(intersectPt); nodes[nNodes].AddConnection(nodes[i]); nodes[i].AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(nodes[k]); nodes[k].AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(connj); connj.AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(connl); connl.AddConnection(nodes[nNodes]); ++nNodes; goto SkipOut; } } } } } SkipOut: ++counter; //if (counter > 100) printf("Counter: %d\n",counter); } /* // Debugging: check for connection consistency for (int i=0; i<nNodes; ++i) { int nConn = nodes[i].nConnected; for (int j=0; j<nConn; ++j) { if (nodes[i].connected[j]->nConnected == 0) b2Assert(false); b2PolyNode* connect = nodes[i].connected[j]; bool found = false; for (int k=0; k<connect->nConnected; ++k) { if (connect->connected[k] == &nodes[i]) found = true; } b2Assert(found); } }*/ //Collapse duplicate points bool foundDupe = true; int nActive = nodes.Count; while (foundDupe) { foundDupe = false; for (int i=0; i < nodes.Count; ++i) { if (nodes[i].nConnected == 0) continue; for (int j=i+1; j < nodes.Count; ++j) { if (nodes[j].nConnected == 0) continue; Vec2 diff = nodes[i].position - nodes[j].position; if (diff.LengthSquared() <= PolyNode.COLLAPSE_DIST_SQR) { if (nActive <= 3) return new Polygon(); //printf("Found dupe, %d left\n",nActive); --nActive; foundDupe = true; PolyNode inode = nodes[i]; PolyNode jnode = nodes[j]; //Move all of j's connections to i, and orphan j int njConn = jnode.nConnected; for (int k=0; k < njConn; ++k) { PolyNode knode = jnode.connected[k]; //b2Assert(knode != jnode); if (knode != inode) { inode.AddConnection(knode); knode.AddConnection(inode); } knode.RemoveConnection(jnode); //printf("knode %d on node %d now has %d connections\n",k,j,knode->nConnected); //printf("Found duplicate point.\n"); } //printf("Orphaning node at address %d\n",(int)jnode); //for (int k=0; k<njConn; ++k) { // if (jnode->connected[k]->IsConnectedTo(*jnode)) printf("Problem!!!\n"); //} /* for (int k=0; k < njConn; ++k){ jnode->RemoveConnectionByIndex(k); }*/ jnode.nConnected = 0; } } } } /* // Debugging: check for connection consistency for (int i=0; i<nNodes; ++i) { int nConn = nodes[i].nConnected; printf("Node %d has %d connections\n",i,nConn); for (int j=0; j<nConn; ++j) { if (nodes[i].connected[j]->nConnected == 0) { printf("Problem with node %d connection at address %d\n",i,(int)(nodes[i].connected[j])); b2Assert(false); } b2PolyNode* connect = nodes[i].connected[j]; bool found = false; for (int k=0; k<connect->nConnected; ++k) { if (connect->connected[k] == &nodes[i]) found = true; } if (!found) printf("Connection %d (of %d) on node %d (of %d) did not have reciprocal connection.\n",j,nConn,i,nNodes); b2Assert(found); } }//*/ //Now walk the edge of the list //Find node with minimum y value (max x if equal) float minY = FLT_MAX; float maxX = -FLT_MAX; int minYIndex = -1; for (int i = 0; i < nodes.Count; ++i) { if (nodes[i].position.Y < minY && nodes[i].nConnected > 1) { minY = nodes[i].position.Y; minYIndex = i; maxX = nodes[i].position.X; } else if (nodes[i].position.Y == minY && nodes[i].position.X > maxX && nodes[i].nConnected > 1) { minYIndex = i; maxX = nodes[i].position.X; } } Vec2 origDir = new Vec2(1.0f, 0.0f); List<Vec2> resultVecs = new List<Vec2>();// nodes may be visited more than once, unfortunately - change to growable array! PolyNode currentNode = nodes[minYIndex]; PolyNode startNode = currentNode; //b2Assert(currentNode->nConnected > 0); PolyNode nextNode = currentNode.GetRightestConnection(ref origDir); if (nextNode == null) goto CleanUp; // Borked, clean up our mess and return resultVecs[0] = startNode.position; while (nextNode != startNode) { resultVecs.Add(nextNode.position); PolyNode oldNode = currentNode; currentNode = nextNode; //printf("Old node connections = %d; address %d\n",oldNode->nConnected, (int)oldNode); //printf("Current node connections = %d; address %d\n",currentNode->nConnected, (int)currentNode); nextNode = currentNode.GetRightestConnection(oldNode); if (nextNode == null) goto CleanUp; // There was a problem, so jump out of the loop and use whatever garbage we've generated so far //printf("nextNode address: %d\n",(int)nextNode); } CleanUp: float[] xres = new float[resultVecs.Count]; float[] yres = new float[resultVecs.Count]; for (int i=0; i<resultVecs.Count; ++i) { xres[i] = resultVecs[i].X; yres[i] = resultVecs[i].Y; } return new Polygon(xres.ToList<float>(), yres.ToList<float>()); }
private static void ProcessPolyTreeNodeIntoSeparatIslands(this Polygons polygonsIn, PolyNode node, List <Polygons> ret) { for (int n = 0; n < node.ChildCount; n++) { PolyNode child = node.Childs[n]; Polygons polygons = new Polygons(); polygons.Add(child.Contour); for (int i = 0; i < child.ChildCount; i++) { polygons.Add(child.Childs[i].Contour); polygonsIn.ProcessPolyTreeNodeIntoSeparatIslands(child.Childs[i], ret); } ret.Add(polygons); } }
// Token: 0x060029AF RID: 10671 RVA: 0x001C2AEC File Offset: 0x001C0CEC 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); }
public virtual void IsHoleTest() { PolyNode node = new PolyNode(); NUnit.Framework.Assert.IsTrue(node.IsHole); }
private static void FlattenPolyTreeToPolygonsHelper(PolyNode current, bool isHole, List <(Polygon2, bool)> results, int depthFilter, bool flipIsHoleResult)
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); }
private static void H(ref IntLineSegment2 seg, PolyNode polyNode, ref IntLineSegment2 contourSegment, List<(PolyNode, double)> localBreakpoints)
internal void CalcOuterPathSegments(PolyNode outerPathAsPolyNode, Dictionary <Vector3, List <TriangleConnectionInfo> > outerPathUnsorted) { //find sourcepoint on outer path var sourcePointAsPolyNodeContourPoint = new IntPoint((int)(this.OuterPathSourcePoint.X * 10000), (int)(this.OuterPathSourcePoint.Y * 10000), (int)(this.OuterPathSourcePoint.Z * 10000)); var sourcePointStartIndex = 0; for (var contourPointIndex = 0; contourPointIndex < outerPathAsPolyNode.Contour.Count; contourPointIndex++) { if (outerPathAsPolyNode.Contour[contourPointIndex] == sourcePointAsPolyNodeContourPoint) { sourcePointStartIndex = contourPointIndex; break; } } //create order list starting from startindex var polyContourWithStartIndex = new List <IntPoint>(); for (var contourPointIndex = sourcePointStartIndex; contourPointIndex < outerPathAsPolyNode.Contour.Count; contourPointIndex++) { polyContourWithStartIndex.Add(outerPathAsPolyNode.Contour[contourPointIndex]); } for (var contourPointIndex = 0; contourPointIndex < sourcePointStartIndex; contourPointIndex++) { polyContourWithStartIndex.Add(outerPathAsPolyNode.Contour[contourPointIndex]); } //find intersectionpoint index var intersectionPointAsPolyNodeContourPoint = new IntPoint((int)(this.OuterPathIntersectionPointProperties.EdgeStartPoint.X * 10000), (int)(this.OuterPathIntersectionPointProperties.EdgeStartPoint.Y * 10000), (int)(this.OuterPathIntersectionPointProperties.EdgeStartPoint.Z * 10000)); var segmentContourPoints = new List <IntPoint>(); for (var contourPointIndex = 0; contourPointIndex < outerPathAsPolyNode.Contour.Count; contourPointIndex++) { segmentContourPoints.Add(outerPathAsPolyNode.Contour[contourPointIndex]); if (outerPathAsPolyNode.Contour[contourPointIndex] == intersectionPointAsPolyNodeContourPoint) { this.OuterPathContourSegmentVectors.Add(segmentContourPoints); segmentContourPoints = new List <IntPoint>(); } } this.OuterPathContourSegmentVectors.Add(segmentContourPoints); var segmentStartBasedOnLowestOuterPathSegments = this.OuterPathContourSegmentVectors[0][0]; if (this.OuterPathContourSegmentVectors[1].Count < this.OuterPathContourSegmentVectors[0].Count) { segmentStartBasedOnLowestOuterPathSegments = this.OuterPathContourSegmentVectors[1][0]; } //find triangle based on intpoint var outerPathContourTriangleConnectionInfo = new TriangleConnectionInfo(); var outerPathUnsortedKeys = new List <Vector3>(); outerPathUnsortedKeys.AddRange(outerPathUnsorted.Keys); for (var outerPathUnsortedIndex = 0; outerPathUnsortedIndex < outerPathUnsorted.Count; outerPathUnsortedIndex++) { var outerPathKey = outerPathUnsortedKeys[outerPathUnsortedIndex]; var outerPathContourPoint = new IntPoint((int)(outerPathKey.X * 10000), (int)(outerPathKey.Y * 10000), (int)(outerPathKey.Z * 10000)); if (outerPathContourPoint == segmentStartBasedOnLowestOuterPathSegments) { //get next outerPathKey = outerPathUnsortedKeys[outerPathUnsortedIndex + 2]; var outerPathValues = outerPathUnsorted[outerPathKey]; outerPathContourTriangleConnectionInfo = outerPathValues[0]; break; } } this.OuterPathContourSmallestContourTriangleConnectionIndex = outerPathContourTriangleConnectionInfo; }
public CampState() : base("Camp") { #region NavMesh var p1 = new Polygon ( new Vector2(151, 274), new Vector2(331, 257), new Vector2(435, 384), new Vector2(215, 392)); var p2 = new Polygon ( new Vector2(4, 416), new Vector2(215, 395), new Vector2(434, 388), new Vector2(871, 405), new Vector2(904, 714), new Vector2(2, 717)); var p3 = new Polygon ( new Vector2 (1090 - 225, 406), new Vector2 (1563 - 225, 414), new Vector2 (1573 - 225, 533), new Vector2 (1300 - 225, 715), new Vector2 (1128 - 225, 714)); var p4 = new Polygon ( new Vector2(936, 398), new Vector2(1113, 287), new Vector2(1219, 295), new Vector2(1267, 402)); var p1n = new PolyNode (p1); var p2n = new PolyNode (p2); var p3n = new PolyNode (p3); var p4n = new PolyNode (p4); PolyLink.AttachLinks (318, 391, ref p1n, ref p2n); PolyLink.AttachLinks (887, 555, ref p2n, ref p3n); PolyLink.AttachLinks (1119, 403, ref p3n, ref p4n); Nav = new List<PolyNode> { p1n, p2n, p3n, p4n, }; #endregion Background = G.C.Load<Texture2D>("CampArea/background"); Foreground = G.C.Load<Texture2D>("CampArea/foreground"); Backpack = CreateItem("Backpack", "A torn backpack", "CampArea/backpack", 734, 410, new Rectagon(0, 0, 111, 59).Vertices.ToArray()); Batteries = CreateItem("Batteries", "Your tongue hurts - they are supprisingly strong", "CampArea/batteries", "UI/Icons/batteries", 761, 480, new Rectagon(0, 0, 78, 32).Vertices.ToArray()); EmptyWineBottle = CreateItem("Empty Wine Bottle", "It's empty", "CampArea/wine1", "UI/Icons/bottle", 137, 574, new Rectagon(0, 0, 24, 81).Vertices.ToArray()); BrokenWineBottle = CreateItem("Broken Wine Bottle", "The neck of the bottle has been broken, likely due to a fall", "CampArea/wine2", "UI/Icons/bottle", 422, 615, new Rectagon(0, 0, 53, 35).Vertices.ToArray()); Papers = CreateItem("Shrededd paper", "[TODO]", "CampArea/papers", "UI/Icons/papers", 822, 457, new Rectagon(0, 0, 53, 35).Vertices.ToArray()); Boulder = CreateItem ("Boulder", "A heavy rock", "CampArea/boulder", "UI/Icons/papers", 480, 313); Machete = CreateItem ("Machete", "A knife used for cutting things down", "CampArea/machete", 560, 420, new Rectagon (0, 0, 150, 60).Vertices.ToArray()); var fireIdle = new Animation ("Idle", new[] { new Rectangle(0, 0, 450, 300), new Rectangle(450, 0, 450, 300), new Rectangle(900, 0, 450, 300), new Rectangle(1350, 0, 450, 300) }, Looping: true); FirepitAnimation = new AnimatedSprite (G.C.Load<Texture2D> ("CampArea/fire_animation"), new Animation[] { fireIdle }); FirepitAnimation._IHateRectangles = new Rectangle (0, 0, 450, 300); FirepitAnimation.IsVisible = false; FirepitAnimation.Location = new Vector2 (0, 350); FirepitAnimation.AnimationManager.SetAnimation ("Idle"); var fireflies_idle = new Animation ("Idle", new[] { new Rectangle(0, 0, 200, 200), new Rectangle(200, 0, 200, 200), new Rectangle(400, 0, 200, 200), new Rectangle(600, 0, 200, 200), new Rectangle(800, 0, 200, 200), new Rectangle(1000, 0, 200, 200), new Rectangle(1200, 0, 200, 200), new Rectangle(1400, 0, 200, 200) }, Looping: true); FliesAnimation = new AnimatedSprite (G.C.Load<Texture2D> ("CampArea/fireflies_animation"), new [] { fireflies_idle}); FliesAnimation._IHateRectangles = new Rectangle (0, 0, 200, 200); FliesAnimation.IsVisible = true; FliesAnimation.Location = new Vector2 (900, 325); FliesAnimation.AnimationManager.SetAnimation ("Idle"); Boulder.IsActive = false; Boulder.CanPickup = false; Boulder.IsMouseHover = false; Machete.IsActive = false; Machete.CanPickup = false; Machete.IsMouseHover = false; Backpack.IsActive = true; Backpack.CanPickup = false; Batteries.IsActive = false; Batteries.CanPickup = false; Batteries.IsVisible = false; Batteries.IsMouseHover = false; EmptyWineBottle.IsActive = false; EmptyWineBottle.CanPickup = true; BrokenWineBottle.IsActive = false; BrokenWineBottle.CanPickup = true; BrokenWineBottle.IsVisible= false; Papers.IsActive = false; Papers.CanPickup = false; Papers.IsVisible = false; Papers.IsMouseHover = false; FirepitLight = CreateSprite("CampArea/light map 1", 0, 0); FirepitLight.IsVisible = false; TentLight = CreateSprite("CampArea/light map 1", 0, 0); #region HotSpots TentEntrance = new Hotspot ( "Tent Entrance", new Polygon (new Vector2 (3, 277), new Vector2 (333, 247), new Vector2 (83, 107), new Vector2 (2, 107)), (t,i) => { G.LastScreen = "Camp"; G.FadeOut.Finished = () => { G.FadeOut.Reset (); G.StateManager.Set ("Tent"); G.FadeIn.TriggerStart (); }; G.C.Load<SoundEffect> ("sfx/Zipper").Play (); G.FadeOut.TriggerStart (); }) { WalkLocation = new Vector2 (170, 279) }; CampExit = new Hotspot( "Camp Exit", new Polygon( new Vector2(1087, 281), new Vector2(1075, 110), new Vector2(1277, 114), new Vector2(1268, 301)), (t,i) => { if (CanLeaveLevel) { G.FadeOut.Finished += () => { G.FadeOut.Reset (); G.StateManager.Set ("Forest"); G.FadeIn.TriggerStart (); }; G.FadeOut.TriggerStart (); } else { SoundWrapper.PlayDialog ("Too Dark"); G.DialogManager.PostQueuedMessage("It's too dark, maybe if I had a flashlight or something.", new TimeSpan (0, 0, 3)); } }) { WalkLocation = new Vector2 (1170, 298) }; Firepit = new Hotspot( "Light Fire Pit", new Polygon(new Vector2(57, 497), new Vector2(50, 465), new Vector2(184, 412), new Vector2 (307, 458), new Vector2 (290, 503), new Vector2(194, 526), new Vector2(97, 518)), (t,i) => { if (FirepitAnimation.IsVisible) return; if (i != null && i.Name == "Matches") { G.C.Load<SoundEffect> ("sfx/Match").Play(); TentLight.IsVisible = false; FirepitAnimation.IsVisible = true; G.DialogManager.PostMessage("You have used the matches", TimeSpan.Zero, new TimeSpan(0, 0, 3)); G.InventoryManager.CurrentItems.Remove("Matches"); foreach (var item in Items) { item.IsActive = true; } } else { G.DialogManager.PostMessage("I need matches to light this...", TimeSpan.Zero, new TimeSpan(0, 0, 3)); } }); BoulderSpot = new Hotspot ( "Pry Boulder up", new Polygon ( new Vector2 (485, 388), new Vector2 (555, 314), new Vector2 (626, 315), new Vector2 (676, 384), new Vector2 (673, 431), new Vector2 (589, 474), new Vector2 (484, 441)), (t, i) => { if (i != null && i.Name == "Bloody Broken Branch") { Boulder.Location.X -= 50; BoulderSpot.IsUsable = false; Machete.IsActive = true; Machete.IsMouseHover = true; Machete.CanPickup = true; G.DialogManager.PostMessage ("You pried up the boulder with the branch", TimeSpan.Zero, new TimeSpan (0, 0, 3)); G.InventoryManager.CurrentItems.Remove ("Bloody Broken Branch"); foreach (var item in Items) { item.IsActive = true; } } else { SoundWrapper.PlayDialog ("Rock"); G.DialogManager.PostMessage ("I need something strong to pry this up", TimeSpan.Zero, new TimeSpan (0, 0, 3)); } }) { WalkLocation = new Vector2(606, 470) }; #endregion Batteries.OnClick += s => SoundWrapper.PlayDialog ("Batteries"); Papers.OnClick += s => SoundWrapper.PlayDialog ("Letter"); Backpack.OnClick += state => { Batteries.IsActive = true; Batteries.CanPickup = true; Batteries.IsVisible = true; Batteries.IsMouseHover = true; Papers.IsActive = true; Papers.CanPickup = true; Papers.IsVisible = true; Papers.IsMouseHover = true; }; GameItem.AddCraftingRecipie("Flashlight", "Batteries", () => { GameItem.ItemDictionary["Flashlight"].Description = "A flashlight, it's batteries are fully charged"; GameItem.ItemDictionary["Flashlight"].InventoryIcon = G.C.Load<Texture2D>("UI/Icons/flashlight_on"); G.InventoryManager.CurrentItems.Remove("Batteries"); // Since we're doing this manually, we have to update it manually ItemsToLeave.Remove ("Flashlight_lit"); CanLeaveLevel = (ItemsToLeave.Count == 0); }); ItemsToLeave.Add("Flashlight_lit"); Items.AddRange(new[] { Batteries, EmptyWineBottle, BrokenWineBottle, Papers, Backpack, Machete, Boulder }); Lights.AddRange(new[] { FirepitLight, TentLight }); Hotspots.AddRange(new[] { Firepit, TentEntrance, CampExit, BoulderSpot }); return; //REMOVE TentLight.IsVisible = false; FirepitAnimation.IsVisible = true; G.DialogManager.PostMessage ("You have used the matches", TimeSpan.Zero, new TimeSpan (0, 0, 3)); G.InventoryManager.CurrentItems.Remove ("Matches"); foreach (var item in Items) { item.IsActive = true; } }
/// <summary> /// Note: Containment definition varies by hole vs terrain: Containment for holes /// does not include the hole edge, containment for terrain includes the terrain edge. /// This is important, else e.g. knockback + terrain push placing an entity on an edge /// would potentially infinite loop. /// </summary> public static void PickDeepestPolynodeGivenHoleShapePolytree(this PolyTree polyTree, IntVector2 query, out PolyNode result, out bool isHole) { polyTree.AssertIsContourlessRootHolePunchResult(); PolyNode current = polyTree; while (true) { // current is a hole of a hole's shape PolyNode match; // if we fail to find the first child land node border-inclusively containing the query point if (!current.Childs.TryFindFirst(child => Clipper.PointInPolygon(new IntVector2(query.X, query.Y), child.Contour) == PolygonContainmentResult.InPolygon, out match)) { result = current; isHole = true; return; } // next off, current is land of a hole's shape current = match; // If we fail to find a child hole border-excludingly containing the query point if (!current.Childs.TryFindFirst(child => Clipper.PointInPolygon(new IntVector2(query.X, query.Y), child.Contour) != PolygonContainmentResult.OutsidePolygon, out match)) { result = current; isHole = false; return; } // next off, current is a hole of a hole's shape current = match; } }
public static bool PointInPolytree(this PolyTree polyTree, IntVector2 query, out PolyNode deepestPolyNode) { PickDeepestPolynodeGivenHoleShapePolytree(polyTree, query, out deepestPolyNode, out var isHole); return(!isHole); }
public TentState() : base("Tent") { Background = G.C.Load<Texture2D> ("TentArea/background"); #region NavMesh var p1 = new Polygon ( new Vector2 (106, 469), new Vector2 (152, 442), new Vector2 (420, 433), new Vector2 (777, 429), new Vector2 (1000, 443), new Vector2 (997, 480), new Vector2 (896, 594), new Vector2 (627, 646), new Vector2 (345, 644), new Vector2 (159, 605)); var p1n = new PolyNode (p1); Nav = new List<PolyNode> { p1n }; #endregion Blanket = CreateItem ("Blanket", "A warm blanket", "TentArea/blanket", 200, 500, new Vector2 (0, 41), new Vector2 (256, -6), new Vector2 (419, 91), new Vector2 (296, 153)); Flash = CreateItem ("Flashlight", "A dead flashlight, it's missing batteries", "TentArea/flashlight","UI/Icons/flashlight_off", 587, 436, new Vector2 (568 - 587, 493 - 436), new Vector2 (575 - 587, 427 - 436), new Vector2 (630 - 587, 433 - 436), new Vector2 (634 - 587, 484 - 436)); Sweater = CreateItem("Sweater", "A Sweater", "TentArea/sweater", "UI/Icons/sweater", 390, 550, new Vector2 (426 - 500, 563 - 550), new Vector2 (513 - 500, 551 - 550), new Vector2 (653 - 500, 559 - 550), new Vector2 (639 - 500, 594 - 550), new Vector2 (566 - 500, 615 - 550), new Vector2 (496 - 500, 603 - 550)); Matches = CreateItem ("Matches", "A set of matches", "TentArea/matches", "UI/Icons/matches", 850, 500, new Vector2 (830 - 850, 505 - 500), new Vector2 (892 - 850, 491 - 500), new Vector2 (905 - 850, 516 - 500), new Vector2 (844 - 850, 532 - 500)); Blanket.OnClick += t => { Blanket.IsActive = false; Blanket.Texture = G.C.Load<Texture2D> ("TentArea/tossedblanket"); Sweater.IsActive = true; G.C.Load<SoundEffect> ("sfx/Blanket").Play(); }; Sweater.OnClick += s => G.C.Load<SoundEffect> ("sfx/Sweater").Play(); Matches.OnClick += s => SoundWrapper.PlayDialog ("Matches"); Flash.OnClick += s => SoundWrapper.PlayDialog ("Flashlight"); Matches.IsActive = false; Matches.IsVisible = false; Blanket.IsActive = true; Blanket.CanPickup = false; Sweater.CanPickup = true; Flash.IsActive = true; Flash.CanPickup = true; Bag = new Hotspot ( "Duffle Bag", new Polygon ( new Vector2 (757, 443), new Vector2 (883, 417), new Vector2 (902, 489), new Vector2 (776, 507), new Vector2 (745, 483) ), (t, i) => { if (BagOpened) return; Player.AnimationManager.SetAnimation ("Kick"); Matches.IsVisible = true; Matches.IsActive = true; Matches.CanPickup = true; BagOpened = true; }) { WalkLocation = new Vector2 (740, 482) }; Exit = new Hotspot( "Tent Exit", new Polygon( new Vector2(620 + 90, 250), new Vector2(607 + 90, 373), new Vector2(575 + 90, 459), new Vector2(650 + 90, 468), new Vector2(675 + 90, 374), new Vector2(657 + 90, 299)), (t,i) => { if (CanLeaveLevel) { G.C.Load<SoundEffect> ("sfx/Zipper").Play (); G.FadeOut.Finished = () => { G.FadeOut.Reset(); G.LastScreen = "Tent"; G.StateManager.Set ("Camp"); G.FadeIn.TriggerStart(); }; G.FadeOut.TriggerStart(); } else { SoundWrapper.PlayDialog ("Cold and Dark"); G.DialogManager.PostMessage ("I should put on some clothes... and grab my flashlight.", TimeSpan.Zero, new TimeSpan (0, 0, 5)); } }) { WalkLocation = new Vector2(706, 486)}; ItemsToLeave.Add("Sweater"); ItemsToLeave.Add("Flashlight"); lantern = CreateSprite ("TentArea/lantern", 510, 89); light1 = CreateSprite ("TentArea/light1"); light2 = CreateSprite ("TentArea/light2"); glow = CreateSprite ("TentArea/lanternGlow", 370, 140); border = CreateSprite ("TentArea/border"); LanternSpot = new Hotspot("Unlit Lantern", new Circlegon(545, 315, 64), (t,i) => { if (light2.IsVisible) return; G.C.Load<SoundEffect> ("sfx/Lantern").Play(); Player.AnimationManager.SetAnimation ("Wake Up"); LanternSpot.Name = "Lit Lantern"; light1.IsVisible = false; light2.IsVisible = true; //glow.IsVisible = true; }) { WalkLocation = new Vector2 (596, 546) }; light1.IsVisible = true; light2.IsVisible = false; glow.IsVisible = false; Items.Add (Flash); Items.Add (Sweater); Items.Add (Matches); Items.Add (Blanket); Lights.Add (lantern); Lights.Add (glow); Lights.Add (border); Lights.Add (light1); Lights.Add (light2); Hotspots.Add (Exit); Hotspots.Add (LanternSpot); Hotspots.Add (Bag); }
public PolyNode GetRightestConnection(PolyNode incoming) { if (nConnected == 0) throw new Exception("wat"); // This means the connection graph is inconsistent if (nConnected == 1) { //b2Assert(false); // Because of the possibility of collapsing nearby points, // we may end up with "spider legs" dangling off of a region. // The correct behavior here is to turn around. return incoming; } Vec2 inDir = position - incoming.position; float inLength = inDir.Normalize(); //b2Assert(inLength > FLT_EPSILON); PolyNode result = null; for (int i=0; i<nConnected; ++i) { if (connected[i] == incoming) continue; Vec2 testDir = connected[i].position - position; float testLengthSqr = testDir.LengthSquared(); testDir.Normalize(); /* if (testLengthSqr < COLLAPSE_DIST_SQR) { printf("Problem with connection %d\n",i); printf("This node has %d connections\n",nConnected); printf("That one has %d\n",connected[i]->nConnected); if (this == connected[i]) printf("This points at itself.\n"); }*/ //b2Assert(testLengthSqr >= COLLAPSE_DIST_SQR); float myCos = inDir.Dot(testDir); float mySin = inDir.Cross(testDir); if (result != null) { Vec2 resultDir = result.position - position; resultDir.Normalize(); float resCos = inDir.Dot(resultDir); float resSin = inDir.Cross(resultDir); if (Statics.IsRighter(mySin, myCos, resSin, resCos)) result = connected[i]; } else result = connected[i]; } if (Polygon.ReportErrors && result == null) { //printf("nConnected = %d\n", nConnected); //for (int32 i=0; i<nConnected; ++i) //{ // printf("connected[%d] @ %d\n", i, 0);//(int)connected[i]); //} throw new Exception("wat"); } //b2Assert(result); return result; }
/// <summary> /// Get a list of triangles which will fill the area described by the slice /// </summary> public IEnumerable <Triangle> Triangles() { TriangleNet.Behavior behavior = new TriangleNet.Behavior(); behavior.ConformingDelaunay = true; foreach (var poly in IndividualPolygons()) { PolyNode node = polyTree.GetFirst(); InputGeometry geometry = new InputGeometry(); while (node != null) { var offset = geometry.Points.Count(); var index = 0; foreach (IntPoint point in node.Contour) { geometry.AddPoint(point.X, point.Y); if (index > 0) { geometry.AddSegment(index - 1 + offset, index + offset); } index++; } geometry.AddSegment(index - 1 + offset, offset); if (node.IsHole) { // To describe a hole, AddHole must be called with a location inside the hole. IntPoint last = new IntPoint(0, 0); bool lastKnown = false; double longest = 0; IntPoint longestAlong = new IntPoint(0, 0); IntPoint from = new IntPoint(0, 0); foreach (IntPoint point in node.Contour) { if (lastKnown) { IntPoint along = new IntPoint(point.X - last.X, point.Y - last.Y); double length = Math.Sqrt(along.X * along.X + along.Y * along.Y); if (length > longest) { longest = length; longestAlong = along; from = last; } } last = point; lastKnown = true; } if (longest > 0) { double perpendicularX = ((double)longestAlong.Y * (double)scale * 0.001d) / longest; double perpendicularY = -((double)longestAlong.X * (double)scale * 0.001d) / longest; geometry.AddHole(perpendicularX + from.X + longestAlong.X / 2.0d, perpendicularY + from.Y + longestAlong.Y / 2.0d); } else { } } node = node.GetNext(); } if (geometry.Points.Count() > 0) { var mesh = new TriangleNet.Mesh(behavior); mesh.Triangulate(geometry); mesh.Renumber(); foreach (Triangle t in this.GetMeshTriangles(mesh)) { yield return(t); } } } }
public ForestState() : base("Forest") { #region Nav Mesh var p1 = new Polygon( new Vector2(111, 233), new Vector2(339, 304), new Vector2(316, 367), new Vector2(71, 259)); var p2 = new Polygon( new Vector2(316, 367), new Vector2(240, 449), new Vector2(160, 414), new Vector2(242, 336)); var p3 = new Polygon( new Vector2(293, 390), new Vector2(241, 446), new Vector2(492, 555), new Vector2(515, 490)); var p4 = new Polygon( new Vector2(515, 490), new Vector2(770, 488), new Vector2 (715, 558), new Vector2(492, 555)); var p5 = new Polygon ( new Vector2 (714, 560), new Vector2 (828, 380), new Vector2 (928, 380), new Vector2 (929, 542), new Vector2 (866, 653)); var p6 = new Polygon ( new Vector2 (928, 541), new Vector2 (2032, 502), new Vector2 (2026, 702), new Vector2 (866, 653)); var p1n = new PolyNode(p1); var p2n = new PolyNode(p2); var p3n = new PolyNode(p3); var p4n = new PolyNode(p4); var p5n = new PolyNode(p5); var p6n = new PolyNode(p6); PolyLink.AttachLinks(277, 350, ref p1n, ref p2n); PolyLink.AttachLinks(268, 414, ref p2n, ref p3n); PolyLink.AttachLinks(505, 521, ref p3n, ref p4n); PolyLink.AttachLinks (744, 514, ref p4n, ref p5n); PolyLink.AttachLinks (891, 581, ref p5n, ref p6n); Nav = new List<PolyNode> { p1n, p2n, p3n, p4n, p5n, p6n }; #endregion Background = G.C.Load<Texture2D> ("ForestArea/background"); Foreground = G.C.Load<Texture2D> ("ForestArea/foreground"); light = new RenderTarget2D(G.Graphics.GraphicsDevice, G.SCREEN_WIDTH, G.SCREEN_HEIGHT, false, SurfaceFormat.Color, DepthFormat.None); Flashlight = CreateSprite("ForestArea/flashlight_beam"); Lightmask = new Sprite { IsVisible = true, Texture = light, }; pixel = new Texture2D(G.Graphics.GraphicsDevice, 1, 1, false, SurfaceFormat.Color); pixel.SetData<Color>(new Color[] {Color.White}); Shoe = CreateItem ("Sarah's Shoe", "", "ForestArea/shoe", "UI/Icons/shoe", 326, 467, new Rectagon (0, 0, 53, 35).Vertices.ToArray ()); Branch = CreateItem ("Bloody Broken Branch", "", "ForestArea/branch", "UI/Icons/branch", 784, 410, new Vector2 (815 - 784, 383 - 410), new Vector2 (761 - 784, 501 - 410), new Vector2 (814 - 784, 511 - 410), new Vector2 (916 - 784, 435 - 410)); ThornBush = CreateItem ("Bush of Thorns", "", "ForestArea/bush", "UI/Icons/papers", 830, 283, new Rectagon (0, 0, 53, 35).Vertices.ToArray ()); CoverBrush1 = CreateItem ("CB1", "", "ForestArea/coverbush", "UI/Icons/papers", 1230, 489, new Rectagon (0, 0, 53, 35).Vertices.ToArray ()); CoverBrush2 = CreateItem ("CB2", "", "ForestArea/coverbush", "UI/Icons/papers", 1463, 486, new Rectagon (0, 0, 53, 35).Vertices.ToArray ()); CoverBrush3 = CreateItem ("CB13", "", "ForestArea/coverbush", "UI/Icons/papers", 1666, 493, new Rectagon (0, 0, 53, 35).Vertices.ToArray ()); Branch.OnClick += s => SoundWrapper.PlayDialog ("Bloody Branch"); Shoe.IsActive = true; Shoe.CanPickup = true; Branch.IsActive = true; Branch.CanPickup = true; ThornBush.IsActive = false; ThornBush.CanPickup = false; ThornBush.IsMouseHover = false; CoverBrush1.IsActive = false; CoverBrush2.IsActive = false; CoverBrush3.IsActive = false; var exitidle = new Animation ("Idle", new[] { new Rectangle(0, 0, 200, 200), new Rectangle(200, 0, 200, 200), new Rectangle(400, 0, 200, 200), new Rectangle(600, 0, 200, 200), new Rectangle(800, 0, 200, 200) }, Looping: true); ExitLight = new AnimatedSprite (G.C.Load<Texture2D> ("ForestArea/exit_animation"), new[] { exitidle }); ExitLight._IHateRectangles = new Rectangle (0, 0, 200, 200); ExitLight.IsVisible = true; ExitLight.Location = new Vector2 (0, 0); ExitLight.AnimationManager.SetAnimation ("Idle"); ForestExit = new Hotspot ( "Tent Entrance", new Polygon ( new Vector2(4, 271), new Vector2(3, 4), new Vector2(330, 114), new Vector2(205, 258)), (t, i) => { G.LastScreen = "Forest"; G.FadeOut.Finished = () => { G.FadeOut.Reset (); G.StateManager.Set ("Camp"); G.FadeIn.TriggerStart(); }; G.FadeOut.TriggerStart(); }) { WalkLocation = new Vector2 (170, 279) }; SarahSpot = new Hotspot ( "Sarah's Body", new Polygon ( new Vector2(1545, 551), new Vector2(1839, 548), new Vector2(1871, 659), new Vector2(1552, 638)), (t, i) => { }); ShrubSpot = new Hotspot ( "Chop down thorny bushes", new Polygon ( new Vector2(938, 596), new Vector2(1021, 343), new Vector2(2046, 483), new Vector2(2036, 709)), (t, i) => { if (i != null && i.Name == "Machete") { CoverBrush1.IsVisible = false; CoverBrush2.IsVisible = false; CoverBrush3.IsVisible = false; ThornBush.IsVisible = false; ThornBush.IsActive = false; ThornBush.IsMouseHover = false; SarahSpot.IsUsable = true; ShrubSpot.IsUsable = false; G.DialogManager.PostMessage ("You chopped down the thorny bushes", TimeSpan.Zero, new TimeSpan (0, 0, 3)); foreach (var item in Items) { item.IsActive = true; } } else { G.DialogManager.PostMessage ("I need something to chop these bushes down", TimeSpan.Zero, new TimeSpan (0, 0, 3)); } }); SarahSpot.IsUsable = false; ShrubSpot.IsUsable = true; Items.Add (Shoe); Items.Add (Branch); Items.Add (ThornBush); Items.Add (CoverBrush1); Items.Add (CoverBrush2); Items.Add (CoverBrush3); Hotspots.Add (ForestExit); Hotspots.Add (ShrubSpot); Hotspots.Add (SarahSpot); }
public PolyMapLoader(string x, string y, string goal, string start, string buttons) { polyData = new PolyData(); string xFile = prefix + x + postfix; string yFile = prefix + y + postfix; string goalFile = prefix + goal + postfix; string startFile = prefix + start + postfix; string buttonsFile = prefix + buttons + postfix; System.IO.StreamReader xReader = new System.IO.StreamReader(xFile); System.IO.StreamReader yReader = new System.IO.StreamReader(yFile); System.IO.StreamReader buttonReader = new System.IO.StreamReader(buttonsFile); string xpos, ypos; PolyNode curFigure = new PolyNode(); int curFirstPoint = 0; int index = 0; bool newOne = true; while ((xpos = xReader.ReadLine()) != null) { ypos = yReader.ReadLine(); // xFile and yFile matches each other int curButton = int.Parse(buttonReader.ReadLine()); // Här funkar det inte float xfloat; float yfloat; xpos = xpos.Replace(",", "."); ypos = ypos.Replace(",", "."); Vector3 curVec = new Vector3(float.Parse(xpos), 1f, float.Parse(ypos)); curFigure.vertices.Add(curVec); polyData.buttons.Add(curButton); //New Figure if (curButton == 3) { polyData.figures.Add(curFigure); curFigure = new PolyNode(); Line newLine1 = new Line(curVec, polyData.nodes[curFirstPoint]); Line newLine2 = new Line(polyData.nodes[index - 1], curVec); polyData.lines.Add(newLine1); polyData.lines.Add(newLine2); curFirstPoint = index + 1; newOne = true; } else { if (polyData.nodes.Count != 0 && !newOne) { Line newLine = new Line(polyData.nodes[index - 1], curVec); polyData.lines.Add(newLine); } newOne = false; } polyData.nodes.Add(curVec); index++; } xReader.Close(); yReader.Close(); buttonReader.Close(); System.IO.StreamReader startReader = new System.IO.StreamReader(startFile); string line; while ((line = startReader.ReadLine()) != null) { string[] startPos = line.Split(' '); polyData.start.Add(new Vector3(Mathf.Round(float.Parse(startPos [0])), 1f, float.Parse(startPos [1]))); } startReader.Close(); System.IO.StreamReader endReader = new System.IO.StreamReader(goalFile); while ((line = endReader.ReadLine()) != null) { string[] endPos = line.Split(' '); polyData.end.Add(new Vector3(Mathf.Round(float.Parse(endPos [0])), 1f, float.Parse(endPos [1]))); } endReader.Close(); /*System.IO.StreamReader buttonReader = new System.IO.StreamReader (buttonsFile); * string button; * while ((button = buttonReader.ReadLine ()) != null) { * polyData.buttons.Add (Convert.ToInt32(button)); * } * buttonReader.Close ();*/ }
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) 3, 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>(); 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 <Polygon> stack = new Stack <Polygon>(); if (this.clipper == null) { this.clipper = new Clipper(0); } this.clipper.ReverseSolution = 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 <IntRect> list9 = ListPool <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; } Random random = null; if (perturbate > 0) { random = new 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; IntRect a = new IntRect(@int.x, @int.z, int2.x, int2.z); if (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(IntRect)); list10.Add(new Int2(0, 0)); } else { IntRect item = new 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; } for (;;) { 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]]; IntRect a2 = new 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 (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, 0); for (int num8 = 0; num8 < list8.Count; num8++) { this.clipper.AddPolygon(list11[list8[num8]], 1); } polyTree.Clear(); this.clipper.Execute(2, polyTree, 0, 1); } else if (1 << num7 == 2) { if (!flag) { goto IL_1161; } this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num9 = 0; num9 < list8.Count; num9++) { if (list12[list8[num9]]) { this.clipper.AddPolygon(list11[list8[num9]], 1); } } list6.Clear(); this.clipper.Execute(0, list6, 0, 1); this.clipper.Clear(); for (int num10 = 0; num10 < list6.Count; num10++) { this.clipper.AddPolygon(list6[num10], (!Clipper.Orientation(list6[num10])) ? 0 : 1); } for (int num11 = 0; num11 < list8.Count; num11++) { if (!list12[list8[num11]]) { this.clipper.AddPolygon(list11[list8[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.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 { 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); } } Polygon polygon2; if (stack.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.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_1161 :; } } } 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 <IntRect> .Release(list9); ListPool <NavmeshCut> .Release(list7); }
public PolyNode GetRightestConnection(PolyNode incoming) { if (nConnected == 1) { //b2Assert(false); // Because of the possibility of collapsing nearby points, // we may end up with "spider legs" dangling off of a region. // The correct behavior here is to turn around. return(incoming); } Vector2 inDir = position - incoming.position; inDir.Normalize(); PolyNode result = null; for (int i = 0; i < nConnected; ++i) { if (connected[i] == incoming) { continue; } Vector2 testDir = connected[i].position - position; testDir.Normalize(); /* * if (testLengthSqr < COLLAPSE_DIST_SQR) { * printf("Problem with connection %d\n",i); * printf("This node has %d connections\n",nConnected); * printf("That one has %d\n",connected[i].nConnected); * if (this == connected[i]) printf("This points at itself.\n"); * }*/ float myCos = Vector2.Dot(inDir, testDir); float mySin = Cross(inDir, testDir); if (result != null) { Vector2 resultDir = result.position - position; resultDir.Normalize(); float resCos = Vector2.Dot(inDir, resultDir); float resSin = Cross(inDir, resultDir); if (IsRighter(mySin, myCos, resSin, resCos)) { result = connected[i]; } } else { result = connected[i]; } } //if (B2_POLYGON_REPORT_ERRORS && result != null) //{ // printf("nConnected = %d\n", nConnected); // for (int i = 0; i < nConnected; ++i) // { // printf("connected[%d] @ %d\n", i, (int)connected[i]); // } //} return(result); }
public virtual void GetNextNoChildsTest() { PolyNode node = new PolyNode(); NUnit.Framework.Assert.IsNull(node.GetNext()); }
private static void GetModelRasterPoints(PolyNode polyNode, int projectorResolutionY, SortedList <int, List <SliceLine2D> > modelPointsByY) { var contourRasterPoints = new List <SlicePoint2D>(); for (var contourLineIndex = 0; contourLineIndex < polyNode.Contour.Count; contourLineIndex++) { var contourLine = new SliceLine2D(); contourLine.p1 = new SlicePoint2D(polyNode.Contour[contourLineIndex]); if (contourLineIndex < polyNode.Contour.Count - 1) { contourLine.p2 = new SlicePoint2D(polyNode.Contour[contourLineIndex + 1]); } else { contourLine.p2 = new SlicePoint2D(polyNode.Contour[0]); } //check if line has a pixel intersecting a whole pixel var startLinePixelY = (int)contourLine.p1.Y; var startLineY = contourLine.p1.Y; var endLinePixelY = (int)contourLine.p2.Y; var endLineY = contourLine.p2.Y; if (contourLine.p1.Y > contourLine.p2.Y) { startLinePixelY = (int)contourLine.p2.Y; startLineY = contourLine.p2.Y; endLinePixelY = (int)contourLine.p1.Y; endLineY = contourLine.p1.Y; } var rasterPoints = new List <SlicePoint2D>(); if (startLinePixelY != endLinePixelY) { //get intersectionpoints for (var i = startLinePixelY - 1; i <= endLinePixelY; i++) { if (i >= startLineY && i <= endLineY) { rasterPoints.Add(contourLine.IntersectY(i)); } } } //x raster points var startLinePixelX = (int)contourLine.p1.X; var startLineX = contourLine.p1.X; var endLinePixelX = (int)contourLine.p2.X; var endLineX = contourLine.p2.X; if (contourLine.p1.X > contourLine.p2.X) { startLinePixelX = (int)contourLine.p2.X; startLineX = contourLine.p2.X; endLinePixelX = (int)contourLine.p1.X; endLineX = contourLine.p1.X; } if (startLinePixelX != endLinePixelX) { //get intersectionpoints for (var i = startLinePixelX - 1; i <= endLinePixelX; i++) { if (i >= startLineX && i <= endLineX) { rasterPoints.Add(contourLine.IntersectX(i)); } } } if (rasterPoints.Count > 0) { //order by distance var rasterPointsOrdered = new SortedDictionary <float, SlicePoint2D>(); var lineStartPointAsVector2 = new Vector2(contourLine.p1.X, contourLine.p1.Y); foreach (var rasterPoint in rasterPoints) { var pointDistance = (new Vector2(rasterPoint.X, rasterPoint.Y) - (lineStartPointAsVector2)).Length; rasterPointsOrdered.Add(pointDistance, rasterPoint); } contourRasterPoints.AddRange(rasterPointsOrdered.Values); } } var bitmap = new Bitmap(1920, 1080); var g = Graphics.FromImage(bitmap); var path = new GraphicsPath(); var points = new List <PointF>(); foreach (var contourRasterPoint in contourRasterPoints) { points.Add(new PointF(contourRasterPoint.X, contourRasterPoint.Y)); } path.AddLines(points.ToArray()); g.DrawLines(new Pen(Color.Red, 1), points.ToArray()); points = new List <PointF>(); for (var contourRasterPointIndex = 0; contourRasterPointIndex < contourRasterPoints.Count - 1; contourRasterPointIndex++) { //calc rasterline volume var rasterPointStart = contourRasterPoints[contourRasterPointIndex]; if (contourRasterPointIndex == 0) { rasterPointStart = contourRasterPoints[contourRasterPoints.Count - 1]; } var rasterPointEnd = contourRasterPoints[contourRasterPointIndex + 1]; var rasterPointVolume = rasterPointStart.X - (int)rasterPointStart.X; rasterPointVolume += rasterPointStart.Y - (int)rasterPointStart.Y; rasterPointVolume += rasterPointEnd.X - (int)rasterPointEnd.X; rasterPointVolume += rasterPointEnd.Y - (int)rasterPointEnd.Y; rasterPointVolume /= 4; rasterPointVolume *= 100; if (rasterPointVolume < 1f) { rasterPointVolume = 1f; } rasterPointVolume = 255 / rasterPointVolume; g.DrawLine(new Pen(Color.FromArgb(255, (int)rasterPointVolume, 255, 255)), rasterPointStart.X, rasterPointStart.Y, rasterPointEnd.X, rasterPointEnd.Y); } bitmap.Save("t.png"); }
private void CutPoly(ListView <NavmeshCut> InNavmeshCuts, VInt3[] verts, int[] tris, ref VInt3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, VInt3[] extraShape, VInt3 cuttingOffset, Bounds realBounds, SGameTileHandler.CutMode mode = (SGameTileHandler.CutMode) 3, 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 & SGameTileHandler.CutMode.CutExtra) != (SGameTileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & SGameTileHandler.CutMode.CutExtra) != (SGameTileHandler.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 == SGameTileHandler.CutMode.CutExtra) { listView = new ListView <NavmeshCut>(); } else { listView = new ListView <NavmeshCut>(InNavmeshCuts); } 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); } } } } ListView <NavmeshAdd> listView2 = new ListView <NavmeshAdd>(); VInt3[] array = verts; int[] array2 = tris; int num = -1; int n = -3; VInt3[] array3 = null; VInt3[] array4 = null; VInt3 vInt4 = VInt3.zero; if (listView2.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 >= listView2.Count) { array = null; break; } if (array == verts) { array = null; } listView2[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 & SGameTileHandler.CutMode.CutExtra) == (SGameTileHandler.CutMode) 0 && (mode & SGameTileHandler.CutMode.CutAll) != (SGameTileHandler.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) & SGameTileHandler.CutMode.CutAll) != (SGameTileHandler.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_1173; } 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))) ? 0 : 1); } 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 = (int)Math.Round(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()) ? null : childs.get_Item(num17).get_Contour())) { 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 = (int)Math.Round(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(InNavmeshCuts, 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_1173 :; } } } 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); }
private static Dictionary <int, List <SlicePoint2D> > GetSupportIntersectionPointsFromPolyNode(PolyNode polyNode, int projectorResolutionX, int projectorResolutionY) { var totalSupportStructureIntersectionPoints = new List <Dictionary <int, List <SlicePoint2D> > >(); var supportPointsByY = new SortedList <int, List <SliceLine2D> >(); for (var contourLineIndex = 0; contourLineIndex < polyNode.Contour.Count; contourLineIndex++) { var contourLine = new SliceLine2D(); contourLine.p1 = new SlicePoint2D(polyNode.Contour[contourLineIndex]); if (contourLineIndex < polyNode.Contour.Count - 1) { contourLine.p2 = new SlicePoint2D(polyNode.Contour[contourLineIndex + 1]); } else { contourLine.p2 = new SlicePoint2D(polyNode.Contour[0]); } if (contourLine.p2.Y < contourLine.p1.Y) { //flip order var tempP1 = contourLine.p1; contourLine.p1 = contourLine.p2; contourLine.p2 = tempP1; } //check if line has a pixel intersecting a whole pixel var startLinePixelY = (int)Math.Ceiling(contourLine.p1.Y); var endLinePixelY = (int)Math.Floor(contourLine.p2.Y); if (endLinePixelY > projectorResolutionY - 1) { endLinePixelY = projectorResolutionY - 1; } if (startLinePixelY < projectorResolutionY && startLinePixelY <= endLinePixelY) { if (contourLine.p1.Y != contourLine.p2.Y) { for (var lineContainsIndexY = startLinePixelY; lineContainsIndexY <= endLinePixelY; lineContainsIndexY++) { if (!supportPointsByY.ContainsKey(lineContainsIndexY)) { supportPointsByY.Add(lineContainsIndexY, new List <SliceLine2D>()); } supportPointsByY[lineContainsIndexY].Add(contourLine); } } } } //get intersectionPoints for this support cone var supportIntersectionPoints = new Dictionary <int, List <SlicePoint2D> >(); foreach (var supportPointIndex in supportPointsByY.Keys) { if (supportPointsByY[supportPointIndex] != null) { //beware zero based index GetIntersectingSupportPoints(supportPointIndex, supportPointsByY[supportPointIndex], ref supportIntersectionPoints); //get normal based intersection points //supportIntersectionPoints[supportPointIndex] = GetSupportPointsByNormal(supportIntersectionPoints[supportPointIndex], supportPointIndex); //do not sort! will be done in later stage } } return(supportIntersectionPoints); }
internal void CalcPolyNode(SupportProfile selectedMaterialProfile, AtumPrinter selectedPrinter, float sliceHeight, int objectIndex) { this.PolyTree = new PolyTree(); var polygonPoints = new List <IntPoint>(); foreach (var polyLinePart in this) { var tStart = (polyLinePart.P1 - new Vector3Class(selectedPrinter.ProjectorResolutionX / 2, selectedPrinter.ProjectorResolutionY / 2, 0)) / 10f; tStart -= new Vector3Class(0.1f, 0.1f, 0); DebugPoints.Add(tStart); polygonPoints.Add(new IntPoint(tStart + new Vector3Class(0, 0, sliceHeight))); } //add the end of the line var tEnd = (this.Last().P2 - new Vector3Class(selectedPrinter.ProjectorResolutionX / 2, selectedPrinter.ProjectorResolutionY / 2, 0)) / 10f; tEnd -= new Vector3Class(0.1f, 0.1f, 0); polygonPoints.Add(new IntPoint(tEnd)); //when not closed use normals to create offset points if (!ClosedLine) { this.Reverse(); // this.Reverse(); var normalVector = new Vector3Class(); foreach (var polyLinePart in this) { normalVector += polyLinePart.Normal; normalVector.Z = 0; normalVector.Normalize(); normalVector *= selectedMaterialProfile.SupportOverhangDistance / 2; //do point offset var tPoint = normalVector + ((polyLinePart.P1 - new Vector3Class(selectedPrinter.ProjectorResolutionX / 2, selectedPrinter.ProjectorResolutionY / 2, 0)) / 10f); tPoint -= new Vector3Class(0.1f, 0.1f, 0); DebugPoints.Add(tPoint + new Vector3Class(0, 0, sliceHeight)); polygonPoints.Add(new IntPoint(tPoint)); normalVector = polyLinePart.Normal; } var polyTreeOffset = new PolyTree(); var polyNode = new PolyNode(); polyNode.m_polygon = polygonPoints; polyTreeOffset._allPolys.Add(polyNode); var c = new Clipper(); c.AddPath(polyTreeOffset._allPolys[0].Contour, PolyType.ptClip, true); c.AddPath(new List <IntPoint>(), PolyType.ptSubject, true); c.Execute(ClipType.ctXor, this.PolyTree, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); //if (sliceHeight >=13 && sliceHeight <=15f) // TriangleHelper.SavePolyNodesContourToPng(this.PolyTree._allPolys, sliceHeight.ToString("0.00") + "-" + objectIndex.ToString() + "-t2"); } else { var polyTreeOffset = new PolyTree(); var polyNode = new PolyNode(); polyNode.m_polygon = polygonPoints; polyTreeOffset._allPolys.Add(polyNode); polyTreeOffset = MagsAIEngine.ClipperOffset(polyTreeOffset, selectedMaterialProfile.SupportOverhangDistance / 2); if (polyTreeOffset._allPolys.Count > 0) { var c = new Clipper(); c.AddPath(polygonPoints, PolyType.ptClip, true); c.AddPath(polyTreeOffset._allPolys[0].Contour, PolyType.ptClip, true); c.AddPath(new List <IntPoint>(), PolyType.ptSubject, true); c.Execute(ClipType.ctXor, this.PolyTree, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); } } }
//------------------------------------------------------------------------------ private void BmpUpdateNeeded() { const int textOffset = 20; if (bmpGraphics == null) { return; } FillMode fm = (mEvenOdd.Checked ? FillMode.Alternate : FillMode.Winding); bmpGraphics.Clear(Color.White); //draw the subject and clip paths ... Paths openPaths = new Paths(); Paths closedPaths = new Paths(); Paths clipPaths = new Paths(); //sort the paths into open and closed subjects and (closed) clips ... foreach (MultiPath mp2 in allPaths) { if (mp2.RefID == CLIP) { clipPaths.Add(mp2.Flatten()); } else if (mp2.IsClosed) { closedPaths.Add(mp2.Flatten()); } else { openPaths.Add(mp2.Flatten()); } } DrawPath(bmpGraphics, openPaths, false, 0x0, 0xFFAAAAAA, fm, 1.0); DrawPath(bmpGraphics, closedPaths, true, 0x0, 0xFFAAAAAA, fm, 1.0); DrawPath(bmpGraphics, clipPaths, true, 0x10FF6600, 0x99FF6600, fm, 1.0); if (cbShowCoords.Checked) { Font fnt = new Font("Arial", 8); SolidBrush brush = new SolidBrush(Color.Navy); foreach (MultiPath mp2 in allPaths) { foreach (MultiPathSegment mps in mp2) { foreach (IntPoint ip in mps) { IntPoint ip2 = new IntPoint(ip.X / scale, ip.Y / scale); string coords = ip2.X.ToString() + "," + ip2.Y.ToString(); bmpGraphics.DrawString(coords, fnt, brush, ip2.X - textOffset, ip2.Y - textOffset, null); } } } fnt.Dispose(); brush.Dispose(); } //for the active path, draw control buttons and control lines too ... MultiPath activePath = GetActivePath(); if (activePath != null && activePath.Count > 0) { foreach (MultiPathSegment mps in activePath) { CurveType pt = mps.curvetype; if (pt == CurveType.CubicBezier) { DrawBezierCtrlLines(bmpGraphics, mps, 0xFFEEEEEE); } else if (pt == CurveType.QuadBezier) { DrawBezierCtrlLines(bmpGraphics, mps, 0xFFEEEEEE); } } DrawButtons(bmpGraphics, activePath); //display the coords of a moving button ... if (MovingButtonIdx >= 0) { Font f = new Font("Arial", 8); SolidBrush b = new SolidBrush(Color.Navy); IntPoint ip = MovingButtonSeg[MovingButtonIdx]; ip.X = (int)(ip.X / scale); ip.Y = (int)(ip.Y / scale); string coords = ip.X.ToString() + "," + ip.Y.ToString(); bmpGraphics.DrawString(coords, f, b, ip.X - textOffset, ip.Y - textOffset, null); f.Dispose(); b.Dispose(); } } //if there's any clipping to be done, do it here ... if (!mNone.Checked && GetCurrentSubjMultiPath() != null && GetCurrentClipMultiPath() != null) { PolyFillType pft = (mEvenOdd.Checked ? PolyFillType.pftEvenOdd : PolyFillType.pftNonZero); ClipType ct; if (mUnion.Checked) { ct = ClipType.ctUnion; } else if (mDifference.Checked) { ct = ClipType.ctDifference; } else if (mXor.Checked) { ct = ClipType.ctXor; } else { ct = ClipType.ctIntersection; } //CLIPPING DONE HERE ... Clipper c = new Clipper(); c.ZFillFunction = MultiPaths.ClipCallback; //set the callback function (called at intersections) if (openPaths.Count > 0) { c.AddPaths(openPaths, PolyType.ptSubject, false); } if (closedPaths.Count > 0) { c.AddPaths(closedPaths, PolyType.ptSubject, true); } c.AddPaths(clipPaths, PolyType.ptClip, true); PolyTree polytree = new PolyTree(); Paths solution; c.Execute(ct, polytree, pft, pft); //EXECUTE CLIP !!!!!!!!!!!!!!!!!!!!!! solution = Clipper.ClosedPathsFromPolyTree(polytree); if (!cbReconstCurve.Checked) { DrawPath(bmpGraphics, solution, true, 0x2033AA00, 0xFF33AA00, fm, 2.0); } solution = Clipper.OpenPathsFromPolyTree(polytree); if (!cbReconstCurve.Checked) { DrawPath(bmpGraphics, solution, false, 0x0, 0xFF33AA00, fm, 2.0); } //now to demonstrate reconstructing beziers & arcs ... if (cbReconstCurve.Checked) { PolyNode pn = polytree.GetFirst(); while (pn != null) { if (pn.IsHole || pn.Contour.Count < 2) { pn = pn.GetNext(); continue; } if (pn.ChildCount > 0) { throw new Exception("Sorry, this demo doesn't currently handle holes"); } //and reconstruct each curve ... MultiPath reconstructedMultiPath = allPaths.Reconstruct(pn.Contour); if (cbShowCtrls.Enabled && cbShowCtrls.Checked) { //show (small) buttons on the red reconstructed path too ... DrawButtons(bmpGraphics, reconstructedMultiPath, true); } //now to show how accurate these reconstructed (control) paths are, //we flatten them (drawing them red) so we can compare them with //the original flattened paths (light gray) ... Paths paths = new Paths(); paths.Add(reconstructedMultiPath.Flatten()); DrawPath(bmpGraphics, paths, !pn.IsOpen, 0x18FF0000, 0xFFFF0000, fm, 2.0); pn = pn.GetNext(); } } //else //shows just how many vertices there are in flattened paths ... //{ // solution = Clipper.PolyTreeToPaths(polytree); // MultiPath flatMultiPath = new MultiPath(null, 0, false); // foreach (Path p in solution) // flatMultiPath.NewMultiPathSegment(PathType.Line, p); // DrawButtons(bmpGraphics, flatMultiPath, true); //} } string s = " "; if (mIntersection.Checked) { s += "INTERSECTION"; } else if (mUnion.Checked) { s += "UNION"; } else if (mDifference.Checked) { s += "DIFFERENCE"; } else if (mXor.Checked) { s += "XOR"; } else { s += "NO CLIPPING"; } s += " with "; if (mEvenOdd.Checked) { s += "EVENODD fill."; } else { s += "NONZERO fill."; } toolStripStatusLabel2.Text = s; displayPanel.Invalidate(); }
// From Eric Jordan's convex decomposition library /// <summary> /// Trace the edge of a non-simple polygon and return a simple polygon. /// /// Method: /// Start at vertex with minimum y (pick maximum x one if there are two). /// We aim our "lastDir" vector at (1.0, 0) /// We look at the two rays going off from our start vertex, and follow whichever /// has the smallest angle (in -Pi . Pi) wrt lastDir ("rightest" turn) /// Loop until we hit starting vertex: /// We add our current vertex to the list. /// We check the seg from current vertex to next vertex for intersections /// - if no intersections, follow to next vertex and continue /// - if intersections, pick one with minimum distance /// - if more than one, pick one with "rightest" next point (two possibilities for each) /// </summary> /// <param name="verts">The vertices.</param> /// <returns></returns> public Vertices TraceEdge(Vertices verts) { PolyNode[] nodes = new PolyNode[verts.Count * verts.Count]; //overkill, but sufficient (order of mag. is right) int nNodes = 0; //Add base nodes (raw outline) for (int i = 0; i < verts.Count; ++i) { Vector2 pos = new Vector2(verts[i].X, verts[i].Y); nodes[i].Position = pos; ++nNodes; int iplus = (i == verts.Count - 1) ? 0 : i + 1; int iminus = (i == 0) ? verts.Count - 1 : i - 1; nodes[i].AddConnection(nodes[iplus]); nodes[i].AddConnection(nodes[iminus]); } //Process intersection nodes - horribly inefficient bool dirty = true; int counter = 0; while (dirty) { dirty = false; for (int i = 0; i < nNodes; ++i) { for (int j = 0; j < nodes[i].NConnected; ++j) { for (int k = 0; k < nNodes; ++k) { if (k == i || nodes[k] == nodes[i].Connected[j]) { continue; } for (int l = 0; l < nodes[k].NConnected; ++l) { if (nodes[k].Connected[l] == nodes[i].Connected[j] || nodes[k].Connected[l] == nodes[i]) { continue; } //Check intersection Vector2 intersectPt; bool crosses = LineTools.LineIntersect(nodes[i].Position, nodes[i].Connected[j].Position, nodes[k].Position, nodes[k].Connected[l].Position, out intersectPt); if (crosses) { dirty = true; //Destroy and re-hook connections at crossing point PolyNode connj = nodes[i].Connected[j]; PolyNode connl = nodes[k].Connected[l]; nodes[i].Connected[j].RemoveConnection(nodes[i]); nodes[i].RemoveConnection(connj); nodes[k].Connected[l].RemoveConnection(nodes[k]); nodes[k].RemoveConnection(connl); nodes[nNodes] = new PolyNode(intersectPt); nodes[nNodes].AddConnection(nodes[i]); nodes[i].AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(nodes[k]); nodes[k].AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(connj); connj.AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(connl); connl.AddConnection(nodes[nNodes]); ++nNodes; goto SkipOut; } } } } } SkipOut: ++counter; } //Collapse duplicate points bool foundDupe = true; int nActive = nNodes; while (foundDupe) { foundDupe = false; for (int i = 0; i < nNodes; ++i) { if (nodes[i].NConnected == 0) { continue; } for (int j = i + 1; j < nNodes; ++j) { if (nodes[j].NConnected == 0) { continue; } Vector2 diff = nodes[i].Position - nodes[j].Position; if (diff.LengthSquared() <= Settings.Epsilon * Settings.Epsilon) { if (nActive <= 3) { return(new Vertices()); } //printf("Found dupe, %d left\n",nActive); --nActive; foundDupe = true; PolyNode inode = nodes[i]; PolyNode jnode = nodes[j]; //Move all of j's connections to i, and orphan j int njConn = jnode.NConnected; for (int k = 0; k < njConn; ++k) { PolyNode knode = jnode.Connected[k]; Debug.Assert(knode != jnode); if (knode != inode) { inode.AddConnection(knode); knode.AddConnection(inode); } knode.RemoveConnection(jnode); } jnode.NConnected = 0; } } } } //Now walk the edge of the list //Find node with minimum y value (max x if equal) float minY = float.MaxValue; float maxX = -float.MaxValue; int minYIndex = -1; for (int i = 0; i < nNodes; ++i) { if (nodes[i].Position.Y < minY && nodes[i].NConnected > 1) { minY = nodes[i].Position.Y; minYIndex = i; maxX = nodes[i].Position.X; } else if (nodes[i].Position.Y == minY && nodes[i].Position.X > maxX && nodes[i].NConnected > 1) { minYIndex = i; maxX = nodes[i].Position.X; } } Vector2 origDir = new Vector2(1.0f, 0.0f); Vector2[] resultVecs = new Vector2[4 * nNodes]; // nodes may be visited more than once, unfortunately - change to growable array! int nResultVecs = 0; PolyNode currentNode = nodes[minYIndex]; PolyNode startNode = currentNode; Debug.Assert(currentNode.NConnected > 0); PolyNode nextNode = currentNode.GetRightestConnection(origDir); if (nextNode == null) { Vertices vertices = new Vertices(nResultVecs); for (int i = 0; i < nResultVecs; ++i) { vertices.Add(resultVecs[i]); } return(vertices); } // Borked, clean up our mess and return resultVecs[0] = startNode.Position; ++nResultVecs; while (nextNode != startNode) { if (nResultVecs > 4 * nNodes) { Debug.Assert(false); } resultVecs[nResultVecs++] = nextNode.Position; PolyNode oldNode = currentNode; currentNode = nextNode; nextNode = currentNode.GetRightestConnection(oldNode); if (nextNode == null) { Vertices vertices = new Vertices(nResultVecs); for (int i = 0; i < nResultVecs; ++i) { vertices.Add(resultVecs[i]); } return(vertices); } // There was a problem, so jump out of the loop and use whatever garbage we've generated so far } return(new Vertices()); }
public static Mesh triangulate(PolyNode polynode, AXTexCoords tex, int seglen = 100000) { return(triangulate(polynode.Childs, tex, seglen)); }
public void AddConnection(PolyNode toMe) { //.b2Assert(nConnected < MAX_CONNECTED); // Ignore duplicate additions for (int i=0; i<nConnected; ++i) { if (connected[i] == toMe) return; } connected[nConnected] = toMe; ++nConnected; }
public static Mesh triangulatePolyNode(PolyNode node, AXTexCoords tex, int seglenBigInt = 1000000) { //Debug.Log ("D " + seglenBigInt); Polygon _polygon = null; if (seglenBigInt < 10) { seglenBigInt = 999999; } List <Mesh> meshes = new List <Mesh>(); // Contour is Solid PolygonPoints _points = null; if (seglenBigInt > 0 && seglenBigInt != 9999999) { _points = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(node.Contour), seglenBigInt)); } else { _points = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(node.Contour)); } // POLYGON if (_points.Count >= 3) { _polygon = new Polygon(_points); } //Debug.Log ("_polygon="+_points.Count); // ADD HOLES TO POLYGON foreach (PolyNode subnode in node.Childs) { PolygonPoints hpoints = null; if (seglenBigInt > 0 && seglenBigInt != 9999999) { hpoints = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(subnode.Contour), seglenBigInt)); } else { hpoints = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(subnode.Contour)); } if (hpoints.Count >= 3) { _polygon.AddHole(new Polygon(hpoints)); } } try { // STEINER POINTS ClipperOffset co = new ClipperOffset(); co.AddPath(node.Contour, AXClipperLib.JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon); //addSteinerPointsAtAllOffsets(ref _polygon, ref co, seglenBigInt/AXGeometryTools.Utilities.IntPointPrecision, seglenBigInt); addSteinerPointsAtAllOffsets(ref _polygon, ref co, (float)seglenBigInt / ((float)AXGeometryTools.Utilities.IntPointPrecision), seglenBigInt); P2T.Triangulate(_polygon); meshes.Add(polygon2mesh(_polygon, tex)); } catch { //Debug.Log ("Can't triangulate: probably point on edge."); } // Continue down the tree... /* * foreach(PolyNode cnode in node.Childs) * { * Mesh submesh = triangulatePolyNode(cnode, tex); * if (submesh != null) * meshes.Add(submesh); * } */ CombineInstance[] combine = new CombineInstance[meshes.Count]; for (int i = 0; i < meshes.Count; i++) { combine[i].mesh = meshes[i]; combine[i].transform = Matrix4x4.identity; } Mesh mesh = new Mesh(); mesh.CombineMeshes(combine); mesh.RecalculateNormals(); return(mesh); }
public bool IsConnectedTo(PolyNode me) { bool isFound = false; for (int i=0; i<nConnected; ++i) { if (me == connected[i]) { isFound = true; break; } } return isFound; }
public float GetCost(PolyNode from, PolyNode to) { //return Mathf.Abs (to.pos.x - from.pos.x) + Mathf.Abs (to.pos.y - from.pos.y); return(Vector3.Distance(from.pos, to.pos)); }
public PolyNode GetRightestConnection(ref Vec2 incomingDir) { Vec2 diff = position - incomingDir; PolyNode temp = new PolyNode(diff); PolyNode res = GetRightestConnection(temp); //b2Assert(res); return res; }
private void TriangulateHelper(PolyNode node, List <TriangulationIsland> islands) { DebugPrint("TriangulateRoot out"); var cps = new Polygon(ConvertToTriangulationPoints(node.Contour)); foreach (var hole in node.Childs) { cps.AddHole(new Polygon(ConvertToTriangulationPoints(hole.Contour))); } P2T.Triangulate(cps); var triangles = new Triangle3[cps.Triangles.Count]; var p2tTriangleToIndex = new Dictionary <Poly2Tri.Triangulation.Delaunay.DelaunayTriangle, int>(); for (int i = 0; i < cps.Triangles.Count; i++) { triangles[i].Index = i; p2tTriangleToIndex[cps.Triangles[i]] = i; } for (var i = 0; i < cps.Triangles.Count; i++) { var p2tTriangle = cps.Triangles[i]; ref Triangle3 t = ref triangles[i]; t.Points = new Array3 <DoubleVector2>( p2tTriangle.Points[0].ToOpenMobaPointD(), p2tTriangle.Points[1].ToOpenMobaPointD(), p2tTriangle.Points[2].ToOpenMobaPointD() ); // Console.WriteLine(string.Join(", ", p2tTriangle.Points.Select(p => p.Z))); t.Centroid = (t.Points[0] + t.Points[1] + t.Points[2]) / 3.0; t.IntPaddedBounds2D = CreatePaddedIntAxisAlignedBoundingBoxXY2D(ref triangles[i].Points); for (int j = 0; j < 3; j++) { if (p2tTriangle.Neighbors[j] != null && p2tTriangle.Neighbors[j].IsInterior) { triangles[i].NeighborOppositePointIndices[j] = p2tTriangleToIndex[p2tTriangle.Neighbors[j]]; } else { triangles[i].NeighborOppositePointIndices[j] = Triangle3.NO_NEIGHBOR_INDEX; } #if DEBUG var p0 = triangles[i].Points[0]; var p1 = triangles[i].Points[1]; var p2 = triangles[i].Points[2]; var centroid = triangles[i].Centroid; var cp0 = p0 - centroid; var cp1 = p1 - centroid; var cp2 = p2 - centroid; var cl01 = GeometryOperations.Clockness(cp0, cp1); var cl12 = GeometryOperations.Clockness(cp1, cp2); var cl20 = GeometryOperations.Clockness(cp2, cp0); var cond = cl01 == cl12 && cl12 == cl20 && cl20 == Clockness.CounterClockwise; if (!cond) { throw new ArgumentException("P2T Triangle Clockness wasn't expected"); } #endif } }
private static void _processPolyTreeNode(this Polygons polygonsIn, PolyNode node, List<Polygons> ret) { for (int n = 0; n < node.ChildCount; n++) { PolyNode child = node.Childs[n]; Polygons polygons = new Polygons(); polygons.Add(child.Contour); for (int i = 0; i < child.ChildCount; i++) { polygons.Add(child.Childs[i].Contour); polygonsIn._processPolyTreeNode(child.Childs[i], ret); } ret.Add(polygons); } }
public static List <(Polygon2 polygon, bool isHole)> FlattenToPolygonAndIsHoles(this PolyNode polytree, bool includeOuterPolygon = true, bool flipIsHoleResult = false) { var results = new List <(Polygon2, bool)>(); var depthFilter = includeOuterPolygon ? 0 : 2; // 2 for outer void level and outer land poly level FlattenPolyTreeToPolygonsHelper(polytree, polytree.IsHole, results, depthFilter, flipIsHoleResult); return(results); }