C#:判断点是否在多边形内

原理:

奇偶规则射线法:多边形内任意一点,向任意方向射线,相交数必然为奇数。

接着我们就可以利用线段到线段的相交数,求出想要的结果。

cs 复制代码
using System.Collections.Generic;
using System;
using UnityEngine;
using System.Drawing;



public class TestTools : MonoBehaviour
{

    public List<Transform> tranPos = new List<Transform>();

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
      
    }


    Point GetNode(Transform _t)
    {
        var _nod = new Point(_t.position.x, _t.position.z);
        return _nod;
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A)) IsIn();
    }





    void IsIn()
    {
        var polygon = new List<Point>();
        polygon.Add(GetNode(tranPos[0]));
        polygon.Add(GetNode(tranPos[1]));
        polygon.Add(GetNode(tranPos[2]));
        polygon.Add(GetNode(tranPos[3]));


        Point point = GetNode(tranPos[4]);
        Point _pEnd = new Point(100,point.Y) ;

        int _num = 0;//相交数量
        for (var _i = 0; _i < polygon.Count; _i++)
        {
            var _p1 = polygon[_i];
            Point _p2 = polygon[0];
            if (_i < polygon.Count - 1) _p2 = polygon[_i + 1];

            Debug.Log("~~~~~~~~!!!");
            Debug.Log(_p1.X + "   " + _p1.Y + "   " + _p2.X + "   " + _p2.Y);

            var intersect = AreSegmentsIntersecting(point, _pEnd, _p1, _p2);
            Debug.Log(intersect);
            if (intersect) _num++;
        }
        Debug.LogError("相交数" + _num);
        var _get = _num % 2 != 0;
        Debug.Log(_get ? "在多边形内" : "不在多边形内");

    }

    // 定义点结构
    public struct Point
    {
        public double X, Y;

        public Point(double x, double y)
        {
            X = x;
            Y = y;
        }
    }

    // 计算两个向量的叉积 (P2 - P1) × (P3 - P1)
    private static double CrossProduct(Point p1, Point p2, Point p3)
    {
        return (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
    }

    // 判断点p是否在a和b之间(用于共线情况下判断是否有重叠)
    private static bool IsPointOnSegment(Point p, Point a, Point b)
    {
        return Math.Min(a.X, b.X) <= p.X && p.X <= Math.Max(a.X, b.X) &&
               Math.Min(a.Y, b.Y) <= p.Y && p.Y <= Math.Max(a.Y, b.Y);
    }

    // 判断两条线段 (p1, p2) 和 (p3, p4) 是否相交
    public static bool AreSegmentsIntersecting(Point p1, Point p2, Point p3, Point p4)
    {
        double d1 = CrossProduct(p3, p4, p1);
        double d2 = CrossProduct(p3, p4, p2);
        double d3 = CrossProduct(p1, p2, p3);
        double d4 = CrossProduct(p1, p2, p4);

        // 检查叉积是否满足线段相交条件
        if (d1 * d2 < 0 && d3 * d4 < 0)
        {
            return true;
        }

        // 检查是否共线且重叠
        if (d1 == 0 && IsPointOnSegment(p1, p3, p4)) return true;
        if (d2 == 0 && IsPointOnSegment(p2, p3, p4)) return true;
        if (d3 == 0 && IsPointOnSegment(p3, p1, p2)) return true;
        if (d4 == 0 && IsPointOnSegment(p4, p1, p2)) return true;

        return false;
    }

    public static void Main()
    {
        Point p1 = new Point(0, 0);
        Point p2 = new Point(2, 2);
        Point p3 = new Point(0, 2);
        Point p4 = new Point(2, 0);

        bool intersecting = AreSegmentsIntersecting(p1, p2, p3, p4);
        Console.WriteLine("Are the segments intersecting? " + (intersecting ? "Yes" : "No"));
    }


}

简化函数为:

cs 复制代码
 public bool IsInPolygon(Point _p, List<Point> _polygon)
 {
     // 计算两个向量的叉积 (P2 - P1) × (P3 - P1)
     double CrossProduct(Point p1, Point p2, Point p3)
     {
         return (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
     }

     // 判断点p是否在a和b之间(用于共线情况下判断是否有重叠)
    bool IsPointOnSegment(Point p, Point a, Point b)
     {
         return Math.Min(a.X, b.X) <= p.X && p.X <= Math.Max(a.X, b.X) &&
                Math.Min(a.Y, b.Y) <= p.Y && p.Y <= Math.Max(a.Y, b.Y);
     }

     // 判断两条线段 (p1, p2) 和 (p3, p4) 是否相交
     bool AreSegmentsIntersecting(Point p1, Point p2, Point p3, Point p4)
     {
         double d1 = CrossProduct(p3, p4, p1);
         double d2 = CrossProduct(p3, p4, p2);
         double d3 = CrossProduct(p1, p2, p3);
         double d4 = CrossProduct(p1, p2, p4);

         // 检查叉积是否满足线段相交条件
         if (d1 * d2 < 0 && d3 * d4 < 0)
         {
             return true;
         }

         // 检查是否共线且重叠
         if (d1 == 0 && IsPointOnSegment(p1, p3, p4)) return true;
         if (d2 == 0 && IsPointOnSegment(p2, p3, p4)) return true;
         if (d3 == 0 && IsPointOnSegment(p3, p1, p2)) return true;
         if (d4 == 0 && IsPointOnSegment(p4, p1, p2)) return true;

         return false;
     }

     Point _pEnd = new Point(float.MaxValue, _p.Y);

     int _num = 0;//相交数量
     for (var _i = 0; _i < _polygon.Count; _i++)
     {
         var _p1 = _polygon[_i];
         Point _p2 = _polygon[0];
         if (_i < _polygon.Count - 1) _p2 = _polygon[_i + 1];

         Debug.Log("~~~~~~~~!!!");
         Debug.Log(_p1.X + "   " + _p1.Y + "   " + _p2.X + "   " + _p2.Y);

         var intersect = AreSegmentsIntersecting(_p, _pEnd, _p1, _p2);
         Debug.Log(intersect);
         if (intersect) _num++;
     }
     Debug.LogError("相交数" + _num);
     var _get = _num % 2 != 0;
     Debug.Log(_get ? "在多边形内" : "不在多边形内");
     return _get;


 }


 // 定义点结构
 public struct Point
 {
     public double X, Y;

     public Point(double x, double y)
     {
         X = x;
         Y = y;
     }
 }

除了顶点照顾不到,基本也够用了。

相关推荐
cpp_w16 分钟前
C#基础3- 面向对象中级应用3
后端·c#
weixin_3077791317 分钟前
C++代码实现MATLAB中的spectralcluster函数功能
开发语言·c++·算法·matlab
鸽鸽程序猿17 分钟前
【项目】【在线判题系统】c端:竞赛报名
c语言·开发语言
Wang's Blog21 分钟前
Java 项目实战: 交友项目 - 个人资料管理的需求分析与接口设计
java·开发语言·交友
1024奇点26 分钟前
【仓颉语言入门 · 第二篇 第 8 课】
开发语言·数据库·ide·mysql·开源
gopher951140 分钟前
RUST:序列化与反序列化 serde + derive 详解
开发语言·后端·rust
H.莓飛1 小时前
【Linux】自主 Shell
linux·运维·服务器·c语言·开发语言·visual studio
熊猫钓鱼>_>1 小时前
Kotlin Multiplatform for OpenHarmony 实战:kotlinx-coroutines 结构化并发适配
开发语言·kotlin·agent·harmonyos·openharmony·适配·华为云码道
步步为营DotNet1 小时前
Async 状态机要搬进运行时了:.NET 10 Runtime Async 实测,快的地方快 1.5 倍,贵的地方贵 5 倍
性能优化·c#·.net·async·runtime
沫璃染墨1 小时前
《Qt从零入门系列(十四):QThread多线程详解——从线程创建到客户端阻塞处理》
开发语言·c++·笔记·qt·ui·交互·线程