2.21(计算几何入门)

点和线

struct Line { // 直线
    Point p1, p2; // 线上的两个点 
    Line() {} 
    // 直接用两个点来构造直线 
    Line(Point p1, Point p2) : p1(p1), p2(p2) {} 
    // 根据一个点和倾斜角angle确定直线,0≤angle≤pi 
    Line(Point p, double angle) { 
        p1 = p; 
        if (sgn(angle - pi / 2) == 0) 
            p2 = (p1 + Point(0, 1)); 
        else
            p2 = (p1 + Point(1, tan(angle))); 
    }
    // ax + by + c = 0 
    Line(double a, double b, double c) { 
        if (sgn(a) == 0) {
            p1 = Point(0, -c / b); 
            p2 = Point(1, -c / b); 
        } 
        else if (sgn(b) == 0) { 
            p1 = Point(-c / a, 0); 
            p2 = Point(-c / a, 1); 
        } 
        else { 
            p1 = Point(0, -c / b); 
            p2 = Point(1, (-c - a) / b); 
        } 
    } 
};
线段的表示
typedef Line Segment;
点和直线的位置关系

用直线v上的两点p1和p2与点p构成两个向量,用叉积的正负判断方向,得到相对的位置关系

int Point_line_relation(Point p, Line v) {
    int c = sgn(Cross(p - v.p1, v.p2 - v.p1)); 
    if (c < 0) // 1:p在v的左边 
        return 1; 
    if (c > 0) // 2:p在v的右边 
        return 2; 
    return 0; // 0:p在v上 
}
点和线段的位置关系

判断点p是否在线段v上,先用叉积判断是否共线,然后用点积看p和v的两个端点产生的角是否为钝角

bool Point_on_seg(Point p, Line v) { // 0为点不在线段v上;1为点在线段v上 
    return sgn(Cross(p - v.p1, v.p2 - v.p1)) == 0 && sgn(Dot(p - v.p1, p - v.p2)) <= 0; 
}
点到直线的距离
double Dis_point_line(Point p, Line v) { 
     return fabs(Cross(p - v.p1, v.p2 - v.p1)) / Dist(v.p1, v.p2); 
}
点在直线上的投影
Point Point_line_proj(Point p, Line v) { // 点p在直线v上的投影 
    double k = Dot(v.p2 - v.p1, p - v.p1) / Len2(v.p2 - v.p1); 
    return v.p1 + (v.p2 - v.p1) * k; 
}
点关于直线的对称点
Point Point_line_symmetry(Point p, Line v) { // 点p关于直线v的对称点 
    Point q = Point_line_proj(p, v); 
    return Point(2 * q.x - p.x, 2 * q.y - p.y); 
}
点到线段的距离

对于点p到线段v(p1,p2)的距离,在一下3个距离中取最小值:从p出发对线段v做垂线,如果交点在v上,这个距离就是最小值;p到p1的距离,p到p2的距离

double Dis_point_seg(Point p, Segment v) { 
    if (sgn(Dot(p - v.p1, v.p2 - v.p1)) < 0 || sgn(Dot(p - v.p2, v.p1 - v.p2)) < 0) 
        return min(Dist(p, v.p1), Dist(p, v.p2)); 
    return Dis_point_line(p, v); 
}
两条直线的位置关系
int Line_relation(Line v1, Line v2) { 
    if (sgn(Cross(v1.p2 - v1.p1, v2.p2 - v2.p1)) == 0) { 
        if (Point_line_relation(v1.p1, v2) == 0) 
            return 1; // 1:重合 
        else
            return 0; // 0:平行 
    }
    return 2; // 2:相交 
}
求两条直线的交点
Point Cross_point(Point a, Point b, Point c, Point d) { // Line: ab, Line: cd 
    double s1 = Cross(b - a, c - a); 
    double s2 = Cross(b - a, d - a); 
    return Point(c.x * s2 - d.x * s1, c.y * s2 - d.y * s1) / (s2 - s1); 
}
判断两个线段是否规范相交

这里利用叉积有正负的特点。如果一条线段的两端在另一条线段的两侧,那么两个端点与另一线段产生的两个叉积的正负相反,也就是说两个叉积相乘为负。如果两条线段互相满足这一点,那么就是规范相交的。

规范相交:交点在线段内部

非规范相交:交点在某条线段的端点

bool Cross_segment(Point a, Point b, Point c, Point d) { 
    // 规范相交 
    double c1 = Cross(b - a, c - a), c2 = Cross(b - a, d - a); 
    double d1 = Cross(d - c, a - c), d2 = Cross(d - c, b - c); 
    return sgn(c1) * sgn(c2) < 0 && sgn(d1) * sgn(d2) < 0; // 1: 相交,0: 不相交 

    // 非规范相交 
    return max(a.x, b.x) >= min(c.x, d.x) && max(c.x, d.x) >= min(a.x, b.x) && 
           max(a.y, b.y) >= min(c.y, d.y) && max(c.y, d.y) >= min(a.y, b.y) && 
           sgn(Cross(b - a, c - a)) * sgn(Cross(b - a, d - a)) <= 0 && 
           sgn(Cross(d - c, a - c)) * sgn(Cross(d - c, b - c)) <= 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值