点在面内(考虑内环外环)------射线算法

射线算法计算点是否在面内 , 考虑内环和外环的情况

cpp 复制代码
// 判断点是否在线段上
bool on_segment(const studio_point& point, const studio_point& l_beg, const studio_point& l_end)
{
    return std::min(l_beg.lgtd, l_end.lgtd) <= point.lgtd && point.lgtd <= std::max(l_beg.lgtd, l_end.lgtd) && std::min(l_beg.lttd, l_end.lttd) <= point.lttd && point.lttd <= std::max(l_beg.lttd, l_end.lttd);
}

// 计算两条线段相交点
studio_point line_intersection(const studio_point& p1, const studio_point& p2, const studio_point& q1, const studio_point& q2)
{
    // 利用直线方程求解交点
    double a1 = p2.lttd - p1.lttd;
    double b1 = p1.lgtd - p2.lgtd;
    double c1 = a1 * p1.lgtd + b1 * p1.lttd;
    double a2 = q2.lttd - q1.lttd;
    double b2 = q1.lgtd - q2.lgtd;
    double c2 = a2 * q1.lgtd + b2 * q1.lttd;
    double determinant = a1 * b2 - a2 * b1;
    if (fabs(determinant) < 1e-6)
    {
        return studio_point();  // 没有交点或线段重叠
    }
    double x = (b2 * c1 - b1 * c2) / determinant;
    double y = (a1 * c2 - a2 * c1) / determinant;
    if (on_segment(studio_point(x, y), p1, p2) && on_segment(studio_point(x, y), q1, q2))
    {
        return studio_point(x, y);
    }
    return studio_point();
}


// 两条线段所在的区域是否有重叠部分
bool segments_overlap(double xa, double xb, double ya, double yb)
{
    return std::max(xa, xb) >= std::min(ya, yb) && std::max(ya, yb) >= std::min(xa, xb);
}

// 计算线段是否相交
bool segments_intersect(studio_point a1, studio_point a2, studio_point b1, studio_point b2)
{
    // 快速排斥测试
    // 两条线段的覆盖入去要有重叠部分, a线段最大的x要大于b线段最小的x, a线段最小的x要小于b线段最大的x,y轴同理
    if (!segments_overlap(a1.lgtd, a2.lgtd, b1.lgtd, b2.lgtd) || !segments_overlap(a1.lttd, a2.lttd, b1.lttd, b2.lttd))
    {
        return false;
    }

    // 计算方向
    //d1 计算了线段 b1-b2 的方向相对于点 a1 的位置
    //d2 计算了线段 b1-b2 的方向相对于点 a2 的位置
    //d3 计算了线段 a1-a2 的方向相对于点 b1 的位置
    //d4 计算了线段 a1-a2 的方向相对于点 b2 的位置
    double d1 = (b2.lttd - b1.lttd) * (a1.lgtd - b1.lgtd) - (b2.lgtd - b1.lgtd) * (a1.lttd - b1.lttd);
    double d2 = (b2.lttd - b1.lttd) * (a2.lgtd - b1.lgtd) - (b2.lgtd - b1.lgtd) * (a2.lttd - b1.lttd);
    double d3 = (a2.lttd - a1.lttd) * (b1.lgtd - a1.lgtd) - (a2.lgtd - a1.lgtd) * (b1.lttd - a1.lttd);
    double d4 = (a2.lttd - a1.lttd) * (b2.lgtd - a1.lgtd) - (a2.lgtd - a1.lgtd) * (b2.lttd - a1.lttd);

    // 当 d1 * d2 < 0 时,意味着点 a1 和 a2 在线段 b1-b2 的两侧
    // 当 d3 * d4 < 0 时,意味着点 b1 和 b2 在线段 a1-a2 的两侧 
    // 如果两个条件都满足,那么线段 a1-a2 和 b1-b2 是相交的,但是如果有一个满足可能是有一点重合,

    // 平行或共线的情况
    if (d1 * d2 == 0 && d3 * d4 == 0)
    {
        // 判断点是否在线段上 a1 是否在 b1-b2 上
        if (on_segment(a1, b1, b2))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else if ((d1 * d2 < 0) && (d3 * d4 < 0)) // 相交
    {
        return true;
    }
    else // 线段a上的一个点在线段b上,或者线段b的延长线上
    {
        // 求相交点,如果相交点为线段的起点返回true
        studio_point intersect = line_intersection(a1, a2, b1, b2);
        // 如果交点为线段b的起始点
        if ((std::abs(intersect.lgtd - b1.lgtd) <= 1e-8) && (std::abs(intersect.lttd - b1.lttd) <= 1e-8))
        {
            return true;
        }
        else
        {
            return false;
        }

        int a = 0;

    }
    
}

// 判断点是否在环内
bool isPointInRing(const studio_point& point, const studio_ring& ring)
{
    int intersections = 0;
    studio_point ray_end(point.lgtd + 10000, point.lttd);  // 向右引一条射线  假设地图宽度不超过10000单位

    // 外环
    for (size_t i = 0, n = ring.points.size(); i < n; ++i)
    {
        const studio_point& start = ring.points[i];
        const studio_point& end = ring.points[(i + 1) % n];
        if (start == end)
        {
            continue;
        }
        if (point == start || point == end)
        {
            return true;
        }
        if (segments_intersect(point, ray_end, start, end))
        {
            intersections++;
        }
    }

    return intersections % 2 != 0;
}

bool intersect(const studio_poly& mpoly, const studio_point& point)
{
    int intersections = 0;
    studio_point ray_end(point.lgtd + 1000, point.lttd);  // 向右引一条射线 1000单位

    // 外环
    bool is_in_outer_ring = isPointInRing(point, mpoly.outer_ring);
    if (is_in_outer_ring)
    {
        // 内环
        for (const auto& inner : mpoly.inner_rings)
        {
            if (isPointInRing(point, inner)) // 在内环内
            {
                return false; // 如果这个点在一个内环内就属于在面外
            }
        }
        return true; // 点在外环内,且不在任何一个内环内
    }
    else
    {
        return false;
    }
}
相关推荐
Kenneth風车3 分钟前
【机器学习(七)】分类和回归任务-K-近邻 (KNN)算法-Sentosa_DSML社区版
人工智能·算法·低代码·机器学习·分类·数据分析·回归
m0_631270402 小时前
标准C++(二)
开发语言·c++·算法
沫刃起2 小时前
Codeforces Round 972 (Div. 2) C. Lazy Narek
数据结构·c++·算法
爱coding的橙子2 小时前
CCF-CSP认证考试准备第十五天 202303-3 LDAP
算法
QXH2000003 小时前
Leetcode—环形链表||
c语言·数据结构·算法·leetcode·链表
小灰灰爱代码4 小时前
C++——判断year是不是闰年。
数据结构·c++·算法
小灰灰爱代码4 小时前
C++——求3个数中最大的数(分别考虑整数、双精度数、长整数数的情况),用函数重载方法。
数据结构·c++·算法
爱coding的橙子6 小时前
CCF-CSP认证考试准备第十七天
数据结构·c++·算法
常某某的好奇心6 小时前
56 - I. 数组中数字出现的次数
算法
hungry12346 小时前
CF EDU 169
算法