/// <summary> /// Checks the cross. /// </summary> /// <returns><c>true</c>, if cross was checked, <c>false</c> otherwise.</returns> /// <param name="line">Line.</param> /// <param name="pos">Position.</param> /// <param name="radius">Radius.</param> public static bool CheckCross(Line2D line, Vector2 pos, float radius) { float fDis = line.GetLength(); Vector2 d; d.x = (line.GetEndPoint().x - line.GetStartPoint().x) / fDis; d.y = (line.GetEndPoint().y - line.GetStartPoint().y) / fDis; Vector2 E; E.x = pos.x - line.GetStartPoint().x; E.y = pos.y - line.GetStartPoint().y; float a = E.x * d.x + E.y * d.y; float a2 = a * a; float e2 = E.x * E.x + E.y * E.y; float r2 = radius * radius; if ((r2 - e2 + a2) < 0) { return(false); } return(true); }
// void SplitBigTriangle(ref List<Triangle> triangles) // { // // 将面积过大的三角形拆分成三个小三角形 // for (int i = 0; i < triangles.Count; i++) // { // if (triangles[i].Area() > NeedSplitSize) // { // } // } // } /// <summary> /// 判断点是否是线段的可见点,组成的三角形没有和其他边相交 /// </summary> /// <param name="line"></param> /// <param name="point"></param> /// <returns></returns> private bool IsPointVisibleOfLine(Line2D line, Vector2 point) { if (line == null) { return(false); } Vector2 sPnt = line.GetStartPoint(); Vector2 ePnt = line.GetEndPoint(); // 是否是线段端点 if (point == sPnt || point == ePnt) { return(false); } //点不在线段的右侧(多边形顶点顺序为顺时针) if (line.ClassifyPoint(point) != PointSide.RIGHT_SIDE) { return(false); } if (!IsVisibleIn2Point(sPnt, point)) { return(false); } if (!IsVisibleIn2Point(ePnt, point)) { return(false); } return(true); }
/// <summary> /// 根据线段生成矩形 /// </summary> /// <param name="linePath">线段</param> /// <returns>矩形</returns> public static Rect LineRect(Line2D linePath) { Rect lineRect = new Rect(); if (linePath.GetStartPoint().x < linePath.GetEndPoint().x) { lineRect.xMin = linePath.GetStartPoint().x; } else { lineRect.xMin = linePath.GetEndPoint().x; } if (linePath.GetStartPoint().y < linePath.GetEndPoint().y) { lineRect.yMin = linePath.GetStartPoint().y; } else { lineRect.yMin = linePath.GetEndPoint().y; } lineRect.width = Math.Abs(linePath.GetEndPoint().x - linePath.GetStartPoint().x); lineRect.height = Math.Abs(linePath.GetEndPoint().y - linePath.GetStartPoint().y); return(lineRect); }
/// <summary> /// Checks the cross. /// </summary> /// <returns><c>true</c>, if cross was checked, <c>false</c> otherwise.</returns> /// <param name="line">Line.</param> /// <param name="tri">Tri.</param> public static bool CheckCross(Line2D line, Triangle tri) { for (int i = 0; i < 3; i++) { Line2D lineTri = tri.GetSide(i); if (CheckCross(line.GetStartPoint(), line.GetEndPoint(), lineTri.GetStartPoint(), lineTri.GetEndPoint()) ) { return(true); } } return(false); }
/// <summary> /// 根据拐点计算法获得导航网格的下一个拐点 /// </summary> /// <param name="way"></param> /// <param name="triPathList"></param> /// <param name="endPos"></param> /// <param name="offSet"></param> /// <returns></returns> private WayPoint GetFurthestWayPoint(WayPoint way, List <NavTriangle> triPathList, Vector2 endPos, int offSet) { WayPoint nextWay = null; Vector2 currPnt = way.GetPoint(); NavTriangle currTri = way.GetTriangle(); NavTriangle lastTriA = currTri; NavTriangle lastTriB = currTri; int startIndex = triPathList.IndexOf(currTri); //开始路点所在的网格索引 Line2D outSide = currTri.GetSide(currTri.GetOutWallIndex()); //路径线在网格中的穿出边? Vector2 lastPntA = outSide.GetStartPoint(); Vector2 lastPntB = outSide.GetEndPoint(); Line2D lastLineA = new Line2D(currPnt, lastPntA); Line2D lastLineB = new Line2D(currPnt, lastPntB); Vector2 testPntA, testPntB; for (int i = startIndex + 1; i < triPathList.Count; i++) { currTri = triPathList[i]; outSide = currTri.GetSide(currTri.GetOutWallIndex()); if (i == triPathList.Count - 1) { testPntA = endPos; testPntB = endPos; } else { testPntA = outSide.GetStartPoint(); testPntB = outSide.GetEndPoint(); } if (lastPntA != testPntA) { if (lastLineB.ClassifyPoint(testPntA) == PointSide.RIGHT_SIDE) { nextWay = new WayPoint(lastPntB, lastTriB); return(nextWay); } else if (lastLineA.ClassifyPoint(testPntA) != PointSide.LEFT_SIDE) { lastPntA = testPntA; lastTriA = currTri; //重设直线 lastLineA = new Line2D(lastLineA.GetStartPoint(), lastPntA); } } if (lastPntB != testPntB) { if (lastLineA.ClassifyPoint(testPntB) == PointSide.LEFT_SIDE) { nextWay = new WayPoint(lastPntA, lastTriA); return(nextWay); } else if (lastLineB.ClassifyPoint(testPntB) != PointSide.RIGHT_SIDE) { lastPntB = testPntB; lastTriB = currTri; //重设直线 lastLineB = new Line2D(lastLineB.GetStartPoint(), lastPntB); } } } //到达终点 nextWay = new WayPoint(endPos, triPathList[triPathList.Count - 1]); return(nextWay); }
/// <summary> /// 根据拐点计算法获得导航网格的下一个拐点 /// </summary> /// <param name="way"></param> /// <param name="triPathList"></param> /// <param name="endPos"></param> /// <param name="offSet"></param> /// <returns></returns> private WayPoint GetFurthestWayPoint(WayPoint way, List<NavTriangle> triPathList, Vector2 endPos, int offSet) { WayPoint nextWay = null; Vector2 currPnt = way.GetPoint(); NavTriangle currTri = way.GetTriangle(); NavTriangle lastTriA = currTri; NavTriangle lastTriB = currTri; int startIndex = triPathList.IndexOf(currTri);//开始路点所在的网格索引 Line2D outSide = currTri.GetSide(currTri.GetOutWallIndex());//路径线在网格中的穿出边? Vector2 lastPntA = outSide.GetStartPoint(); Vector2 lastPntB = outSide.GetEndPoint(); Line2D lastLineA = new Line2D(currPnt, lastPntA); Line2D lastLineB = new Line2D(currPnt, lastPntB); Vector2 testPntA, testPntB; for (int i = startIndex + 1; i < triPathList.Count; i++) { currTri = triPathList[i]; outSide = currTri.GetSide(currTri.GetOutWallIndex()); if (i == triPathList.Count - 1) { testPntA = endPos; testPntB = endPos; } else { testPntA = outSide.GetStartPoint(); testPntB = outSide.GetEndPoint(); } if (lastPntA != testPntA) { if (lastLineB.ClassifyPoint(testPntA) == PointSide.RIGHT_SIDE) { nextWay = new WayPoint(lastPntB, lastTriB); return nextWay; } else if (lastLineA.ClassifyPoint(testPntA) != PointSide.LEFT_SIDE) { lastPntA = testPntA; lastTriA = currTri; //重设直线 lastLineA = new Line2D(lastLineA.GetStartPoint(), lastPntA); } } if (lastPntB != testPntB) { if (lastLineA.ClassifyPoint(testPntB) == PointSide.LEFT_SIDE) { nextWay = new WayPoint(lastPntA, lastTriA); return nextWay; } else if (lastLineB.ClassifyPoint(testPntB) != PointSide.RIGHT_SIDE) { lastPntB = testPntB; lastTriB = currTri; //重设直线 lastLineB = new Line2D(lastLineB.GetStartPoint(), lastPntB); } } } //到达终点 nextWay = new WayPoint(endPos, triPathList[triPathList.Count - 1]); return nextWay; }
/// <summary> /// 找到指定边的约束边DT /// </summary> /// <param name="line"></param> /// <returns></returns> private bool FindDT(Line2D line, out Vector2 dtPoint) { dtPoint = new Vector2(); if (line == null) return false; Vector2 ptA = line.GetStartPoint(); Vector2 ptB = line.GetEndPoint(); List<Vector2> visiblePnts = new List<Vector2>(); foreach (Vector2 point in allPoints) { if (IsPointVisibleOfLine(line, point)) visiblePnts.Add(point); } if (visiblePnts.Count == 0) return false; bool bContinue = false; dtPoint = visiblePnts[0]; do { bContinue = false; //Step1.构造三角形的外接圆,以及外接圆的包围盒 Circle circle = NMath.CreateCircle(ptA, ptB, dtPoint); Rect boundBox = NMath.GetCircleBoundBox(circle); //Step2. 依次访问网格包围盒内的每个网格单元: //若某个网格单元中存在可见点 p, 并且 ∠p1pp2 > ∠p1p3p2,则令 p3=p,转Step1; //否则,转Step3. float angOld = (float)Math.Abs(NMath.LineRadian(ptA, dtPoint, ptB)); foreach (Vector2 pnt in visiblePnts) { if (pnt == ptA || pnt == ptB || pnt == dtPoint) continue; if (!boundBox.Contains(pnt)) continue; float angNew = (float)Math.Abs(NMath.LineRadian(ptA, pnt, ptB)); if (angNew > angOld) { dtPoint = pnt; bContinue = true; break; } } //false 转Step3 } while (bContinue); //Step3. 若当前网格包围盒内所有网格单元都已被处理完, // 也即C(p1,p2,p3)内无可见点,则 p3 为的 p1p2 的 DT 点 return true; }
// void SplitBigTriangle(ref List<Triangle> triangles) // { // // 将面积过大的三角形拆分成三个小三角形 // for (int i = 0; i < triangles.Count; i++) // { // if (triangles[i].Area() > NeedSplitSize) // { // } // } // } /// <summary> /// 判断点是否是线段的可见点,组成的三角形没有和其他边相交 /// </summary> /// <param name="line"></param> /// <param name="point"></param> /// <returns></returns> private bool IsPointVisibleOfLine(Line2D line, Vector2 point) { if (line == null) return false; Vector2 sPnt = line.GetStartPoint(); Vector2 ePnt = line.GetEndPoint(); // 是否是线段端点 if (point == sPnt || point == ePnt) return false; //点不在线段的右侧(多边形顶点顺序为顺时针) if (line.ClassifyPoint(point) != PointSide.RIGHT_SIDE) return false; if (!IsVisibleIn2Point(sPnt, point)) return false; if (!IsVisibleIn2Point(ePnt, point)) return false; return true; }
/// <summary> /// 找到指定边的约束边DT /// </summary> /// <param name="line"></param> /// <returns></returns> private bool FindDT(Line2D line, out Vector2 dtPoint) { dtPoint = new Vector2(); if (line == null) { return(false); } Vector2 ptA = line.GetStartPoint(); Vector2 ptB = line.GetEndPoint(); List <Vector2> visiblePnts = new List <Vector2>(); foreach (Vector2 point in allPoints) { if (IsPointVisibleOfLine(line, point)) { visiblePnts.Add(point); } } if (visiblePnts.Count == 0) { return(false); } bool bContinue = false; dtPoint = visiblePnts[0]; do { bContinue = false; //Step1.构造三角形的外接圆,以及外接圆的包围盒 Circle circle = NMath.CreateCircle(ptA, ptB, dtPoint); Rect boundBox = NMath.GetCircleBoundBox(circle); //Step2. 依次访问网格包围盒内的每个网格单元: //若某个网格单元中存在可见点 p, 并且 ∠p1pp2 > ∠p1p3p2,则令 p3=p,转Step1; //否则,转Step3. float angOld = (float)Math.Abs(NMath.LineRadian(ptA, dtPoint, ptB)); foreach (Vector2 pnt in visiblePnts) { if (pnt == ptA || pnt == ptB || pnt == dtPoint) { continue; } if (!boundBox.Contains(pnt)) { continue; } float angNew = (float)Math.Abs(NMath.LineRadian(ptA, pnt, ptB)); if (angNew > angOld) { dtPoint = pnt; bContinue = true; break; } } //false 转Step3 } while (bContinue); //Step3. 若当前网格包围盒内所有网格单元都已被处理完, // 也即C(p1,p2,p3)内无可见点,则 p3 为的 p1p2 的 DT 点 return(true); }
/// <summary> /// 创建导航网格 /// </summary> /// <param name="polyAll">所有阻挡区域</param> /// <param name="triAll">输出的导航网格</param> /// <returns></returns> public NavResCode CreateNavMesh(List <Polygon> polyAll, ref int id, int groupid, ref List <Triangle> triAll) { triAll.Clear(); List <Line2D> allLines = new List <Line2D>(); //线段堆栈 //Step1 保存顶点和边 NavResCode initRes = InitData(polyAll); if (initRes != NavResCode.Success) { return(initRes); } int lastNeighborId = -1; Triangle lastTri = null; //Step2.遍历边界边作为起点 { Line2D sEdge = startEdge; allLines.Add(sEdge); Line2D edge = null; do { //Step3.选出计算出边的DT点,构成约束Delaunay三角形 edge = allLines[allLines.Count - 1]; allLines.Remove(edge); Vector2 dtPoint; bool isFindDt = FindDT(edge, out dtPoint); if (!isFindDt) { continue; } Line2D lAD = new Line2D(edge.GetStartPoint(), dtPoint); Line2D lDB = new Line2D(dtPoint, edge.GetEndPoint()); //创建三角形 Triangle delaunayTri = new Triangle(edge.GetStartPoint(), edge.GetEndPoint(), dtPoint, id++, groupid); // 保存邻居节点 // if (lastNeighborId != -1) // { // delaunayTri.SetNeighbor(lastNeighborId); // if(lastTri != null) // lastTri.SetNeighbor(delaunayTri.ID); // } //save result triangle triAll.Add(delaunayTri); // 保存上一次的id和三角形 lastNeighborId = delaunayTri.GetID(); lastTri = delaunayTri; int lineIndex; //Step4.检测刚创建的的线段ad,db;如果如果它们不是约束边 //并且在线段堆栈中,则将其删除,如果不在其中,那么将其放入 if (!Line2D.CheckLineIn(allEdges, lAD, out lineIndex)) { if (!Line2D.CheckLineIn(allLines, lAD, out lineIndex)) { allLines.Add(lAD); } else { allLines.RemoveAt(lineIndex); } } if (!Line2D.CheckLineIn(allEdges, lDB, out lineIndex)) { if (!Line2D.CheckLineIn(allLines, lDB, out lineIndex)) { allLines.Add(lDB); } else { allLines.RemoveAt(lineIndex); } } //Step5.如果堆栈不为空,则转到第Step3.否则结束循环 } while (allLines.Count > 0); } // 计算邻接边和每边中点距离 for (int i = 0; i < triAll.Count; i++) { Triangle tri = triAll[i]; //// 计算每个三角形每边中点距离 //tri.calcWallDistance(); // 计算邻居边 for (int j = 0; j < triAll.Count; j++) { Triangle triNext = triAll[j]; if (tri.GetID() == triNext.GetID()) { continue; } int result = tri.isNeighbor(triNext); if (result != -1) { tri.SetNeighbor(result, triNext.GetID()); } } } return(NavResCode.Success); }
/// <summary> /// Checks the cross. /// </summary> /// <returns><c>true</c>, if cross was checked, <c>false</c> otherwise.</returns> /// <param name="line">Line.</param> /// <param name="pos">Position.</param> /// <param name="radius">Radius.</param> public static bool CheckCross( Line2D line , Vector2 pos , float radius ) { float fDis = line.GetLength(); Vector2 d; d.x = (line.GetEndPoint().x - line.GetStartPoint().x) / fDis; d.y = (line.GetEndPoint().y - line.GetStartPoint().y) / fDis; Vector2 E; E.x = pos.x - line.GetStartPoint().x; E.y = pos.y - line.GetStartPoint().y; float a = E.x * d.x + E.y * d.y; float a2 = a * a; float e2 = E.x * E.x + E.y * E.y; float r2 = radius * radius; if ((r2 - e2 + a2) < 0) { return false; } return true; }
/// <summary> /// Checks the cross. /// </summary> /// <returns><c>true</c>, if cross was checked, <c>false</c> otherwise.</returns> /// <param name="line">Line.</param> /// <param name="tri">Tri.</param> public static bool CheckCross( Line2D line , Triangle tri ) { for(int i = 0 ; i < 3 ; i++ ) { Line2D lineTri = tri.GetSide(i); if( CheckCross(line.GetStartPoint() , line.GetEndPoint() , lineTri.GetStartPoint() , lineTri.GetEndPoint()) ) { return true; } } return false; }
/// <summary> /// 根据线段生成矩形 /// </summary> /// <param name="linePath">线段</param> /// <returns>矩形</returns> public static Rect LineRect(Line2D linePath) { Rect lineRect = new Rect(); if (linePath.GetStartPoint().x < linePath.GetEndPoint().x) lineRect.xMin = linePath.GetStartPoint().x; else lineRect.xMin = linePath.GetEndPoint().x; if (linePath.GetStartPoint().y < linePath.GetEndPoint().y) lineRect.yMin = linePath.GetStartPoint().y; else lineRect.yMin = linePath.GetEndPoint().y; lineRect.width = Math.Abs(linePath.GetEndPoint().x - linePath.GetStartPoint().x); lineRect.height = Math.Abs(linePath.GetEndPoint().y - linePath.GetStartPoint().y); return lineRect; }