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

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

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;
    }
}
相关推荐
此生只爱蛋1 分钟前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
咕咕吖33 分钟前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎1 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu1 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!1 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚2 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
为什么这亚子2 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
3 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
~yY…s<#>3 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
幸运超级加倍~4 小时前
软件设计师-上午题-16 算法(4-5分)
笔记·算法