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

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

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;
    }
}
相关推荐
NAGNIP34 分钟前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo40 分钟前
半开区间和开区间的两个二分模版
算法
moonlifesudo43 分钟前
300:最长递增子序列
算法
CoovallyAIHub6 小时前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
CoovallyAIHub6 小时前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉
聚客AI1 天前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm
大怪v1 天前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法
惯导马工1 天前
【论文导读】ORB-SLAM3:An Accurate Open-Source Library for Visual, Visual-Inertial and
深度学习·算法
骑自行车的码农1 天前
【React用到的一些算法】游标和栈
算法·react.js
博笙困了1 天前
AcWing学习——双指针算法
c++·算法