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

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

// 判断点是否在线段上
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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值