public static bool TryMerge(ref Poly toPoly, Triangle mergeTri, ref GeoEdge sharedEdge) { if (CouldMerge(ref toPoly, mergeTri, sharedEdge)) { return(Merge(ref toPoly, mergeTri, ref sharedEdge)); } else { return(false); } }
public static bool IsIntersect(Poly poly, int x, int z) { Vector2 pA = new Vector2(left + tileSize * x, bottom + tileSize * z); Vector2 pB = new Vector2(left + tileSize * (x + 1), bottom + tileSize * z); Vector2 pC = new Vector2(left + tileSize * (x + 1), bottom + tileSize * (z + 1)); Vector2 pD = new Vector2(left + tileSize * x, bottom + tileSize * (z + 1)); Geo2D poly2d = poly.GetGeo2D(); Geo2D rect2d = new Geo2D(pA, pB, pC, pD); return(GraphTester2D.IsIntersect(poly2d, rect2d)); }
protected int GetPoly(Vector2 pos, List <int> plys) { foreach (int i in plys) { Poly p = polys[i]; if (GraphTester2D.IsInside(pos, p.GetGeo2D())) { return(i); } } return(-1); }
public static GeoEdge SharedEdge(Poly polyA, Poly polyB) { for (int i = 0; i < polyA.EdgeCount; i++) { for (int j = 0; j < polyB.EdgeCount; j++) { if (AreEqual(polyA.Edges[i], polyB.Edges[j])) { return(polyA.Edges[i]); } } } return(null); }
public static bool HasSharedEdge(Poly polyA, Poly polyB) { for (int i = 0; i < polyA.EdgeCount; i++) { for (int j = 0; j < polyB.EdgeCount; j++) { if (AreEqual(polyA.Edges[i], polyB.Edges[j])) { return(true); } } } return(false); }
public static bool Merge(ref Poly toPoly, Poly mergeTri, ref GeoEdge sharedEdge) { List <GeoEdge> restEdge = mergeTri.RestEdge(sharedEdge); if (!toPoly.ContainsSomeEdge(restEdge)) { toPoly.RemoveEdge(sharedEdge); toPoly.AddEdges(restEdge); return(true); } else { return(false); } }
public static bool CouldMerge(ref Poly toPoly, Poly mergeTri, GeoEdge sharedEdge) { bool couldmerge = true; Vector3 a = toPoly.RelatedEdgeExtrude(sharedEdge.A, sharedEdge).OtherPoint(sharedEdge.A); Vector3 b = sharedEdge.PointA; Vector3 c = mergeTri.RelatedEdgeExtrude(sharedEdge.A, sharedEdge).OtherPoint(sharedEdge.A); Vector3 d = sharedEdge.OtherPoint(sharedEdge.A); couldmerge &= GraphTester2D.TotalAngleForThreeSeg(a, b, c, d) - 180f < 1e-06; a = toPoly.RelatedEdgeExtrude(sharedEdge.B, sharedEdge).OtherPoint(sharedEdge.B); b = sharedEdge.PointB; c = mergeTri.RelatedEdgeExtrude(sharedEdge.B, sharedEdge).OtherPoint(sharedEdge.B); d = sharedEdge.OtherPoint(sharedEdge.B); couldmerge &= GraphTester2D.TotalAngleForThreeSeg(a, b, c, d) - 180f < 1e-06; return(couldmerge); }
/// <summary> /// 得到处理过后的导航文件,包含信息(顶点、多边形、多边形连接、预计算路径信息、多边形的AOI信息) /// </summary> /// <param name="fileName"></param> /// <param name="ifPreCalculatePath"></param> public static void WriteProcessedNavFile(NavMesh navMesh, string fileName, bool ifPreCalculatePath) { if (File.Exists(fileName)) { File.Delete(fileName); } StreamWriter sw = new StreamWriter(fileName); StringBuilder lBuilder; for (int i = 0; i < navMesh.Points.Count; i++)//顶点信息 { lBuilder = new StringBuilder("v").Append(navMesh.Points[i].x.ToString()).Append(" ").Append(navMesh.Points[i].y.ToString()).Append(" ").Append(navMesh.Points[i].z); sw.WriteLine(lBuilder.ToString()); } SortedDictionary <int, Poly> .Enumerator polyIter = navMesh.Polys.GetEnumerator(); while (polyIter.MoveNext()) //Poly 信息 { lBuilder = new StringBuilder("p").Append(polyIter.Current.Key.ToString()).Append(" "); Poly p = polyIter.Current.Value; foreach (GeoEdge e in p.Edges) { lBuilder.Append("|").Append(e.A.ToString()).Append(" ").Append(e.B); } sw.WriteLine(lBuilder.ToString()); } polyIter.Dispose(); SortedDictionary <int, HashSet <PolyConnection> > .Enumerator iter = navMesh.NearPolys.GetEnumerator(); while (iter.MoveNext())//Poly connection信息 { //有连接的poly的序号 lBuilder = new StringBuilder("c ").Append(iter.Current.Key.ToString()); HashSet <PolyConnection> cons = iter.Current.Value; foreach (PolyConnection con in cons) { lBuilder.Append(" ").Append(con.Other(iter.Current.Key).ToString()).Append(" ").Append(con.Weight.ToString()).Append(" ").Append(con.ConnectionEdge.A.ToString()).Append(" ").Append(con.ConnectionEdge.B.ToString()); //每个连接有4个数据,分别是:连向的Poly的序号、此连接的权重、对应此连接的边的两个顶点 } sw.WriteLine(lBuilder.ToString()); } iter.Dispose(); if (ifPreCalculatePath) {//预存储的路径信息, 存在文件的后部 List <int>[,] paths = navMesh.Paths; for (int m = 0; m < navMesh.Polys.Count; m++) { for (int n = 0; n < navMesh.Polys.Count; n++) { List <int> pth = paths[m, n]; if (pth != null && pth.Count > 0) { lBuilder = new StringBuilder("from ").Append(m.ToString()).Append(" to ").Append(n.ToString()); for (int x = 0; x < pth.Count; x++) { lBuilder.Append(" ").Append(pth[x].ToString()); } sw.WriteLine(lBuilder.ToString()); } } } } sw.WriteLine("componentCount " + navMesh.ComponentCount); //这里把AOI信息也写进来 NavAOI navAOI = NavAOIProcesser.ProcessPolyAOI(navMesh.Polys, navMesh); sw.WriteLine("navAOI:"); lBuilder = new StringBuilder("AOIInfo ").Append(navAOI.Left.ToString()).Append(" ").Append(navAOI.Bottom).Append(" ").Append(navAOI.TileSize).Append(" ").Append(navAOI.Width).Append(" ").Append(navAOI.Height); sw.WriteLine(lBuilder.ToString()); for (int i = 0; i < navAOI.Width; i++) { for (int j = 0; j < navAOI.Height; j++) { List <int> aoiList = navAOI.NavPolyAOI[i, j]; if (aoiList != null) { lBuilder = new StringBuilder(i.ToString()).Append(",").Append(j.ToString()).Append(":"); for (int k = 0; k < aoiList.Count; k++) { lBuilder.Append(" ").Append(aoiList[k]); } sw.WriteLine(lBuilder.ToString()); } } } sw.Close(); sw.Dispose(); }
public void ProcessMeshToGraph() { Dictionary <Triangle, bool> visited = new Dictionary <Triangle, bool>(); foreach (Triangle tri in triangles) { visited.Add(tri, false); } Queue <Poly> processEdgeQueue = new Queue <Poly>(); int i = 0; componentCount = 0; int mergedCout = 0; while (triangles.Count > 0) { componentCount++; //整张图的联通分量计数++ Triangle tri = triangles.First(); //拿出一个三角形 tri.Index = i++; //为这个poly分配索引 visited[tri] = true; processEdgeQueue.Enqueue(tri); triangles.Remove(tri); foreach (GeoEdge e in tri.Edges) { if (edgeTriangleMap.ContainsKey(e.Index) && edgeTriangleMap[e.Index].Contains(tri)) { edgeTriangleMap[e.Index].Remove(tri);//移除这个三角形和它的边的映射 } } while (processEdgeQueue.Count > 0) { Poly poly = processEdgeQueue.Dequeue(); bool hasConnection = false; for (int j = 0; j < poly.Edges.Count; j++) {//对于这个多边形的每一条边 GeoEdge e = poly.Edges[j]; for (int k = 0; k < edgeTriangleMap[e.Index].Count; k++) {//如果有与之相连的其他三角形 Triangle t = edgeTriangleMap[e.Index][k]; if (triangles.Contains(t) && t != poly && PolyProcesser.HasSharedEdge(poly, t)) { GeoEdge sharedEdge = PolyProcesser.SharedEdge(poly, t); if (PolyProcesser.TryMerge(ref poly, t, ref sharedEdge)) //如果可以成功合并 { //这里ref Poly处理过后,里面就有t的边了 hasConnection = true; mergedCout++; } else {//相连但不可成功合并,说明是相连的多边形 if (!visited[t]) { processEdgeQueue.Enqueue(t); t.Index = i++; visited[t] = true; //设置polyConnection,这里polyConnection还不用计算Weight,因为可能poly和t的顶点都没有全部得到 PolyConnection con = new PolyConnection(poly.Index, t.Index, sharedEdge); if (!polyConnections.Contains(con)) { polyConnections.Add(con); InsertNearPoly(con.A, con); InsertNearPoly(con.B, con); } } } edgeTriangleMap[e.Index].Remove(t); triangles.Remove(t); } } } if (hasConnection) { processEdgeQueue.Enqueue(poly);//说明还有连接,可能这个poly还没有处理完 } else {//Poly没有连接了,说明处理完了,对poly做最后的处理 if (!polys.ContainsKey(poly.Index)) { polys.Add(poly.Index, poly); } } } } //对polyConnection计算权值 foreach (PolyConnection polyCon in polyConnections) { Vector3 pointA = CenterPoint(polys[polyCon.A].GetPoints()); Vector3 pointB = CenterPoint(polys[polyCon.B].GetPoints()); polyCon.Weight = Vector3.Distance(pointA, pointB); } Debug.Log("merged count :" + mergedCout); Debug.Log("component count :" + componentCount); }
public static PathFinder Read(string fileName) { StreamReader sr = new StreamReader(fileName); string l; float left = 0f; float bottom = 0f; float tileSize = 0f; int width = 0; int height = 0; int componentCount = 0; List <Vector3> points = new List <Vector3>(); Dictionary <int, Poly> polys = new Dictionary <int, Poly>(); Dictionary <int, List <NodeEdge> > edges = new Dictionary <int, List <NodeEdge> >(); List <int>[,] pths = null; List <int>[,] polyAOI = null; while ((l = sr.ReadLine()) != null) { string[] info = l.Split(' '); if (info[0] == "v") { Vector3 p = new Vector3(Convert.ToSingle(info[1]), Convert.ToSingle(info[2]), Convert.ToSingle(info[3])); points.Add(p); } else if (info[0] == "p") { string[] infos = l.Split('|'); Poly poly = new Poly(); int index = Convert.ToInt32(info[1]); poly.Index = Convert.ToInt32(info[1]); for (int i = 1; i < infos.Length; i++) { string[] edge = infos[i].Split(' '); poly.AddEdge(new GeoEdge(Convert.ToInt32(edge[0]), Convert.ToInt32(edge[1]), points)); } polys.Add(index, poly); } else if (info[0] == "c") { int index = Convert.ToInt32(info[1]); List <NodeEdge> eEdges = new List <NodeEdge>(); for (int i = 2; i < info.Length - 3; i += 4) { NodeEdge nEdge = new NodeEdge(); nEdge.A = index; nEdge.B = Convert.ToInt32(info[i]); nEdge.Weight = Convert.ToSingle(info[i + 1]); nEdge.PointA = Convert.ToInt32(info[i + 2]); nEdge.PointB = Convert.ToInt32(info[i + 3]); } edges.Add(index, eEdges); } else if (info[0] == "from") { if (pths == null) { pths = new List <int> [polys.Count, polys.Count]; } List <int> path = new List <int>(); int from = Convert.ToInt32(info[1]); int to = Convert.ToInt32(info[3]); for (int i = 4; i < info.Length; i++) { path.Add(Convert.ToInt32(info[i])); } pths[from, to] = path; } else if (info[0] == "componentCount") { componentCount = Convert.ToInt32(info[1]); } else if (info[0] == "AOIInfo") { left = Convert.ToSingle(info[1]); bottom = Convert.ToSingle(info[2]); tileSize = Convert.ToSingle(info[3]); width = Convert.ToInt32(info[4]); height = Convert.ToInt32(info[5]); } else if (info[0] == "aoiOf") { if (polyAOI == null) { polyAOI = new List <int> [width, height]; } List <int> aoi = new List <int>(); int i = Convert.ToInt32(info[1]); int j = Convert.ToInt32(info[2]); for (int k = 3; k < info.Length; k++) { aoi.Add(Convert.ToInt32(info[k])); } polyAOI[i, j] = aoi; } } sr.Close(); sr.Dispose(); if (pths == null) { return(new PathFinderRealtime(points, polys, edges, left, bottom, tileSize, width, height, componentCount, polyAOI)); } else { return(new PathFinderPre(points, polys, edges, left, bottom, tileSize, width, height, componentCount, polyAOI)); } }
public static NavAOI ProcessPolyAOI(SortedDictionary <int, Poly> polys, NavMesh mesh) { float l = Mathf.Infinity; float r = Mathf.NegativeInfinity; float b = Mathf.Infinity; float t = Mathf.NegativeInfinity; float area = 0f; SortedDictionary <int, Poly> .Enumerator polyIter = polys.GetEnumerator(); while (polyIter.MoveNext()) {//Poly 信息 Poly poly = polyIter.Current.Value; foreach (int pIndex in poly.GetPoints()) { Vector3 point = mesh.Point(pIndex); if (point.x < l) { l = point.x; } if (point.z < b) { b = point.z; } if (point.x > r) { r = point.x; } if (point.z > t) { t = point.z; } } area += poly.GetGeo2D().GetArea(); } polyIter.Dispose(); area /= polys.Count; left = l; bottom = b; width = r - l; height = t - b; tileSize = Mathf.Sqrt(area); int w = Mathf.CeilToInt(width / tileSize); int h = Mathf.CeilToInt(height / tileSize); NavAOI navAOI = new NavAOI(left, bottom, width, height, tileSize); polyIter = polys.GetEnumerator(); while (polyIter.MoveNext()) { Poly poly = polyIter.Current.Value; Geo2D geo2D = poly.GetGeo2D(); int xStart = Mathf.FloorToInt(geo2D.MinX / tileSize); int xEnd = Mathf.CeilToInt(geo2D.MaxX / tileSize); int yStart = Mathf.FloorToInt(geo2D.MinY / tileSize); int yEnd = Mathf.CeilToInt(geo2D.MaxY / tileSize); for (int i = xStart; i < xEnd; i++) { for (int j = yStart; j < yEnd; j++) { if (IsIntersect(poly, i, j)) { navAOI.AddPolyToAOI(i, j, polyIter.Current.Key); } } } } polyIter.Dispose(); return(navAOI); }