/** Returns randomly selected points on the specified nodes with each point being separated by \a clearanceRadius from each other. * Selecting points ON the nodes only works for TriangleMeshNode (used by Recast Graph and Navmesh Graph) and GridNode (used by GridGraph). * For other node types, only the positions of the nodes will be used. * * clearanceRadius will be reduced if no valid points can be found. */ public static List<Vector3> GetPointsOnNodes (List<GraphNode> nodes, int count, float clearanceRadius = 0) { if (nodes == null) throw new ArgumentNullException ("nodes"); if (nodes.Count == 0) throw new ArgumentException ("no nodes passed"); var rnd = new System.Random(); var pts = ListPool<Vector3>.Claim(count); // Square clearanceRadius *= clearanceRadius; if (nodes[0] is TriangleMeshNode || nodes[0] is GridNode) { //Assume all nodes are triangle nodes or grid nodes var accs = ListPool<float>.Claim(nodes.Count); float tot = 0; for (var i=0;i<nodes.Count;i++) { var tnode = nodes[i] as TriangleMeshNode; if (tnode != null) { float a = Math.Abs(Polygon.TriangleArea(tnode.GetVertex(0), tnode.GetVertex(1), tnode.GetVertex(2))); tot += a; accs.Add (tot); } else { var gnode = nodes[i] as GridNode; if (gnode != null) { var gg = GridNode.GetGridGraph (gnode.GraphIndex); var a = gg.nodeSize*gg.nodeSize; tot += a; accs.Add (tot); } else { accs.Add(tot); } } } for (var i=0;i<count;i++) { //Pick point var testCount = 0; var testLimit = 10; var worked = false; while (!worked) { worked = true; //If no valid points can be found, progressively lower the clearance radius until such a point is found if (testCount >= testLimit) { clearanceRadius *= 0.8f; testLimit += 10; if (testLimit > 100) clearanceRadius = 0; } var tg = (float)rnd.NextDouble()*tot; var v = accs.BinarySearch(tg); if (v < 0) v = ~v; if (v >= nodes.Count) { // This shouldn't happen, due to NextDouble being smaller than 1... but I don't trust floating point arithmetic. worked = false; continue; } var node = nodes[v] as TriangleMeshNode; Vector3 p; if (node != null) { // Find a random point inside the triangle float v1; float v2; do { v1 = (float)rnd.NextDouble(); v2 = (float)rnd.NextDouble(); } while (v1+v2 > 1); p = ((Vector3)(node.GetVertex(1)-node.GetVertex(0)))*v1 + ((Vector3)(node.GetVertex(2)-node.GetVertex(0)))*v2 + (Vector3)node.GetVertex(0); } else { var gnode = nodes[v] as GridNode; if (gnode != null) { var gg = GridNode.GetGridGraph (gnode.GraphIndex); var v1 = (float)rnd.NextDouble(); var v2 = (float)rnd.NextDouble(); p = (Vector3)gnode.position + new Vector3(v1 - 0.5f, 0, v2 - 0.5f) * gg.nodeSize; } else { //Point nodes have no area, so we break directly instead pts.Add ((Vector3)nodes[v].position); break; } } // Test if it is some distance away from the other points if (clearanceRadius > 0) { for (var j=0;j<pts.Count;j++) { if ((pts[j]-p).sqrMagnitude < clearanceRadius) { worked = false; break; } } } if (worked) { pts.Add (p); break; } else { testCount++; } } } ListPool<float>.Release(accs); } else { for (var i=0;i<count;i++) { pts.Add ((Vector3)nodes[rnd.Next (nodes.Count)].position); } } return pts; }
public static List <Vector3> GetPointsOnNodes(List <GraphNode> nodes, int count, float clearanceRadius = 0f) { if (nodes == null) { throw new ArgumentNullException("nodes"); } if (nodes.Count == 0) { throw new ArgumentException("no nodes passed"); } Random random = new Random(); List <Vector3> list = ListPool <Vector3> .Claim(count); clearanceRadius *= clearanceRadius; if (nodes[0] is TriangleMeshNode || nodes[0] is GridNode) { List <float> list2 = ListPool <float> .Claim(nodes.Count); float num = 0f; for (int i = 0; i < nodes.Count; i++) { TriangleMeshNode triangleMeshNode = nodes[i] as TriangleMeshNode; if (triangleMeshNode != null) { float num2 = (float)Math.Abs(Polygon.TriangleArea(triangleMeshNode.GetVertex(0), triangleMeshNode.GetVertex(1), triangleMeshNode.GetVertex(2))); num += num2; list2.Add(num); } else { GridNode gridNode = nodes[i] as GridNode; if (gridNode != null) { GridGraph gridGraph = GridNode.GetGridGraph(gridNode.GraphIndex); float num3 = gridGraph.nodeSize * gridGraph.nodeSize; num += num3; list2.Add(num); } else { list2.Add(num); } } } for (int j = 0; j < count; j++) { int num4 = 0; int num5 = 10; bool flag = false; while (!flag) { flag = true; if (num4 >= num5) { clearanceRadius *= 0.8f; num5 += 10; if (num5 > 100) { clearanceRadius = 0f; } } float item = (float)random.NextDouble() * num; int num6 = list2.BinarySearch(item); if (num6 < 0) { num6 = ~num6; } if (num6 >= nodes.Count) { flag = false; } else { TriangleMeshNode triangleMeshNode2 = nodes[num6] as TriangleMeshNode; Vector3 vector; if (triangleMeshNode2 != null) { float num7; float num8; do { num7 = (float)random.NextDouble(); num8 = (float)random.NextDouble(); }while (num7 + num8 > 1f); vector = (Vector3)(triangleMeshNode2.GetVertex(1) - triangleMeshNode2.GetVertex(0)) * num7 + (Vector3)(triangleMeshNode2.GetVertex(2) - triangleMeshNode2.GetVertex(0)) * num8 + (Vector3)triangleMeshNode2.GetVertex(0); } else { GridNode gridNode2 = nodes[num6] as GridNode; if (gridNode2 == null) { list.Add((Vector3)nodes[num6].position); break; } GridGraph gridGraph2 = GridNode.GetGridGraph(gridNode2.GraphIndex); float num9 = (float)random.NextDouble(); float num10 = (float)random.NextDouble(); vector = (Vector3)gridNode2.position + new Vector3(num9 - 0.5f, 0f, num10 - 0.5f) * gridGraph2.nodeSize; } if (clearanceRadius > 0f) { for (int k = 0; k < list.Count; k++) { if ((list[k] - vector).sqrMagnitude < clearanceRadius) { flag = false; break; } } } if (flag) { list.Add(vector); break; } num4++; } } } ListPool <float> .Release(list2); } else { for (int l = 0; l < count; l++) { list.Add((Vector3)nodes[random.Next(nodes.Count)].position); } } return(list); }