点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部
判斷一點是否在不規則圖像的內部算法,如下圖是由一個個點組成的不規則圖像,判斷某一點是否在不規則矩形內部,先上效果圖
算法實現如下,算法簡單,親試有效
public class PositionAlgorithmHelper{/// <summary>/// 判斷當前位置是否在不規則形狀里面/// </summary>/// <param name="nvert">不規則形狀的定點數</param>/// <param name="vertx">當前x坐標</param>/// <param name="verty">當前y坐標</param>/// <param name="testx">不規則形狀x坐標集合</param>/// <param name="testy">不規則形狀y坐標集合</param>/// <returns></returns>public static bool PositionPnpoly(int nvert, List<double> vertx, List<double> verty, double testx, double testy){int i, j, c = 0;for (i = 0, j = nvert - 1; i < nvert; j = i++){if (((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i])){c = 1 + c; ;}}if (c % 2 == 0){return false;}else{return true;}}}用上圖坐標進行測試:
class Program{static void Main(string[] args){test1();}/// <summary>/// test1/// </summary>public static void test1(){//不規則圖像坐標List<Position> position = new List<Position>();position.Add(new Position() { x = 6, y = 0 });position.Add(new Position() { x = 10, y = 2 });position.Add(new Position() { x = 16, y = 2 });position.Add(new Position() { x = 20, y = 6 });position.Add(new Position() { x = 14, y = 10 });position.Add(new Position() { x = 16, y = 6 });position.Add(new Position() { x = 12, y = 6 });position.Add(new Position() { x = 14, y = 8 });position.Add(new Position() { x = 10, y = 8 });position.Add(new Position() { x = 8, y = 6 });position.Add(new Position() { x = 12, y = 4 });position.Add(new Position() { x = 6, y = 4 });position.Add(new Position() { x = 8, y = 2 });//用戶當前位置坐標List<Position> userPositions = new List<Position>();userPositions.Add(new Position() { x = 14, y = 4 });userPositions.Add(new Position() { x = 15, y = 4 });userPositions.Add(new Position() { x = 10, y = 6 });userPositions.Add(new Position() { x = 8, y = 5 });//不規則圖像x坐標集合List<double> xList = position.Select(x => x.x).ToList();//不規則圖像y坐標集合List<double> yList = position.Select(x => x.y).ToList();foreach (var userPosition in userPositions){bool result = PositionAlgorithmHelper.PositionPnpoly(position.Count, xList, yList, userPosition.x, userPosition.y);if (result){Console.WriteLine(string.Format("{0},{1}【在】坐標內", userPosition.x, userPosition.y));}else{Console.WriteLine(string.Format("{0},{1}【不在】坐標內", userPosition.x, userPosition.y));}}}}另外兩種方式:
/// <summary> /// 判斷點是否在多邊形內. /// ----------原理---------- /// 注意到如果從P作水平向左的射線的話,如果P在多邊形內部,那么這條射線與多邊形的交點必為奇數, /// 如果P在多邊形外部,則交點個數必為偶數(0也在內)。 /// 所以,我們可以順序考慮多邊形的每條邊,求出交點的總個數。還有一些特殊情況要考慮。假如考慮邊(P1,P2), /// 1)如果射線正好穿過P1或者P2,那么這個交點會被算作2次,處理辦法是如果P的從坐標與P1,P2中較小的縱坐標相同,則直接忽略這種情況 /// 2)如果射線水平,則射線要么與其無交點,要么有無數個,這種情況也直接忽略。 /// 3)如果射線豎直,而P0的橫坐標小于P1,P2的橫坐標,則必然相交。 /// 4)再判斷相交之前,先判斷P是否在邊(P1,P2)的上面,如果在,則直接得出結論:P再多邊形內部。 /// </summary> /// <param name="checkPoint">要判斷的點</param> /// <param name="polygonPoints">多邊形的頂點</param> /// <returns></returns> public static bool IsInPolygon2(Position checkPoint, List<Position> polygonPoints){int counter = 0;int i;double xinters;Position p1, p2;int pointCount = polygonPoints.Count;p1 = polygonPoints[0];for (i = 1; i <= pointCount; i++){p2 = polygonPoints[i % pointCount];if (checkPoint.y > Math.Min(p1.y, p2.y)//校驗點的Y大于線段端點的最小Y && checkPoint.y <= Math.Max(p1.y, p2.y))//校驗點的Y小于線段端點的最大Y {if (checkPoint.x <= Math.Max(p1.x, p2.x))//校驗點的X小于等線段端點的最大X(使用校驗點的左射線判斷). {if (p1.y != p2.y)//線段不平行于X軸 {xinters = (checkPoint.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;if (p1.x == p2.x || checkPoint.x <= xinters){counter++;}}}}p1 = p2;}if (counter % 2 == 0){return false;}else{return true;}}/// <summary> /// 判斷點是否在多邊形內. /// ----------原理---------- /// 注意到如果從P作水平向左的射線的話,如果P在多邊形內部,那么這條射線與多邊形的交點必為奇數, /// 如果P在多邊形外部,則交點個數必為偶數(0也在內)。 /// </summary> /// <param name="checkPoint">要判斷的點</param> /// <param name="polygonPoints">多邊形的頂點</param> /// <returns></returns> public static bool IsInPolygon(Position checkPoint, List<Position> polygonPoints){bool inside = false;int pointCount = polygonPoints.Count;Position p1, p2;for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一個點和最后一個點作為第一條線,之后是第一個點和第二個點作為第二條線,之后是第二個點與第三個點,第三個點與第四個點... {p1 = polygonPoints[i];p2 = polygonPoints[j];if (checkPoint.y < p2.y){//p2在射線之上 if (p1.y <= checkPoint.y){//p1正好在射線中或者射線下方 if ((checkPoint.y - p1.y) * (p2.x - p1.x) > (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判斷,在P1和P2之間且在P1P2右側 {//射線與多邊形交點為奇數時則在多邊形之內,若為偶數個交點時則在多邊形之外。 //由于inside初始值為false,即交點數為零。所以當有第一個交點時,則必為奇數,則在內部,此時為inside=(!inside) //所以當有第二個交點時,則必為偶數,則在外部,此時為inside=(!inside) inside = (!inside);}}}else if (checkPoint.y < p1.y){//p2正好在射線中或者在射線下方,p1在射線上 if ((checkPoint.y - p1.y) * (p2.x - p1.x) < (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判斷,在P1和P2之間且在P1P2右側 {inside = (!inside);}}}return inside;}/// <summary>??? ? ? ? /// 判斷點是否在多邊形內.??? ? ? ? /// ----------原理----------??? ? ? ? /// 注意到如果從P作水平向左的射線的話,如果P在多邊形內部,那么這條射線與多邊形的交點必為奇數,??? ? ? ? /// 如果P在多邊形外部,則交點個數必為偶數(0也在內)。??? ? ? ? /// 所以,我們可以順序考慮多邊形的每條邊,求出交點的總個數。還有一些特殊情況要考慮。假如考慮邊(P1,P2),??? ? ? ? /// 1)如果射線正好穿過P1或者P2,那么這個交點會被算作2次,處理辦法是如果P的從坐標與P1,P2中較小的縱坐標相同,則直接忽略這種情況??? ? ? ? /// 2)如果射線水平,則射線要么與其無交點,要么有無數個,這種情況也直接忽略。??? ? ? ? /// 3)如果射線豎直,而P0的橫坐標小于P1,P2的橫坐標,則必然相交。??? ? ? ? /// 4)再判斷相交之前,先判斷P是否在邊(P1,P2)的上面,如果在,則直接得出結論:P再多邊形內部。??? ? ? ? /// </summary>??? ? ? ? /// <param name="checkPoint">要判斷的點</param>??? ? ? ? /// <param name="polygonPoints">多邊形的頂點</param>??? ? ? ? /// <returns></returns>??? ? ? ? public static bool IsInPolygon2(Position checkPoint, List<Position> polygonPoints)? ? ? ? {? ? ? ? ? ? int counter = 0;? ? ? ? ? ? int i;? ? ? ? ? ? double xinters;? ? ? ? ? ? Position p1, p2;? ? ? ? ? ? int pointCount = polygonPoints.Count;? ? ? ? ? ? p1 = polygonPoints[0];? ? ? ? ? ? for (i = 1; i <= pointCount; i++)? ? ? ? ? ? {? ? ? ? ? ? ? ? p2 = polygonPoints[i % pointCount];? ? ? ? ? ? ? ? if (checkPoint.y > Math.Min(p1.y, p2.y)//校驗點的Y大于線段端點的最小Y??? ? ? ? ? ? ? ? ? ? && checkPoint.y <= Math.Max(p1.y, p2.y))//校驗點的Y小于線段端點的最大Y??? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? if (checkPoint.x <= Math.Max(p1.x, p2.x))//校驗點的X小于等線段端點的最大X(使用校驗點的左射線判斷).??? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? if (p1.y != p2.y)//線段不平行于X軸??? ? ? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? xinters = (checkPoint.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;? ? ? ? ? ? ? ? ? ? ? ? ? ? if (p1.x == p2.x || checkPoint.x <= xinters)? ? ? ? ? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? counter++;? ? ? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? p1 = p2;? ? ? ? ? ? }
? ? ? ? ? ? if (counter % 2 == 0)? ? ? ? ? ? {? ? ? ? ? ? ? ? return false;? ? ? ? ? ? }? ? ? ? ? ? else? ? ? ? ? ? {? ? ? ? ? ? ? ? return true;? ? ? ? ? ? }? ? ? ? }
? ? ? ? /// <summary>??? ? ? ? /// 判斷點是否在多邊形內.??? ? ? ? /// ----------原理----------??? ? ? ? /// 注意到如果從P作水平向左的射線的話,如果P在多邊形內部,那么這條射線與多邊形的交點必為奇數,??? ? ? ? /// 如果P在多邊形外部,則交點個數必為偶數(0也在內)。??? ? ? ? /// </summary>??? ? ? ? /// <param name="checkPoint">要判斷的點</param>??? ? ? ? /// <param name="polygonPoints">多邊形的頂點</param>??? ? ? ? /// <returns></returns>??? ? ? ? public static bool IsInPolygon(Position checkPoint, List<Position> polygonPoints)? ? ? ? {? ? ? ? ? ? bool inside = false;? ? ? ? ? ? int pointCount = polygonPoints.Count;? ? ? ? ? ? Position p1, p2;? ? ? ? ? ? for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一個點和最后一個點作為第一條線,之后是第一個點和第二個點作為第二條線,之后是第二個點與第三個點,第三個點與第四個點...??? ? ? ? ? ? {? ? ? ? ? ? ? ? p1 = polygonPoints[i];? ? ? ? ? ? ? ? p2 = polygonPoints[j];? ? ? ? ? ? ? ? if (checkPoint.y < p2.y)? ? ? ? ? ? ? ? {//p2在射線之上??? ? ? ? ? ? ? ? ? ? if (p1.y <= checkPoint.y)? ? ? ? ? ? ? ? ? ? {//p1正好在射線中或者射線下方??? ? ? ? ? ? ? ? ? ? ? ? if ((checkPoint.y - p1.y) * (p2.x - p1.x) > (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判斷,在P1和P2之間且在P1P2右側??? ? ? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? //射線與多邊形交點為奇數時則在多邊形之內,若為偶數個交點時則在多邊形之外。??? ? ? ? ? ? ? ? ? ? ? ? ? ? //由于inside初始值為false,即交點數為零。所以當有第一個交點時,則必為奇數,則在內部,此時為inside=(!inside)??? ? ? ? ? ? ? ? ? ? ? ? ? ? //所以當有第二個交點時,則必為偶數,則在外部,此時為inside=(!inside)??? ? ? ? ? ? ? ? ? ? ? ? ? ? inside = (!inside);? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? else if (checkPoint.y < p1.y)? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? //p2正好在射線中或者在射線下方,p1在射線上??? ? ? ? ? ? ? ? ? ? if ((checkPoint.y - p1.y) * (p2.x - p1.x) < (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判斷,在P1和P2之間且在P1P2右側??? ? ? ? ? ? ? ? ? ? {? ? ? ? ? ? ? ? ? ? ? ? inside = (!inside);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? ? ? return inside;? ? ? ? }
總結
以上是生活随笔為你收集整理的点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 意外险受益人可以是朋友吗
- 下一篇: 广发无限卡办理条件