11.02_点线关系

点线关系

问题描述

点线关系处理平面上点与直线/线段之间的基本关系,包括点到线的距离、点在线的位置等。常用于几何判定和距离计算问题。

基本操作

算法思想

  1. 使用向量表示直线方向
  2. 基于叉积判断方向
  3. 适用于位置和距离计算
  4. 时间复杂度

代码实现

class Line {
public:
    Point p1, p2;  // 直线上两点
    
    Line(Point p1 = Point(), Point p2 = Point()) : p1(p1), p2(p2) {}
    
    // 点到直线距离
    double distanceToLine(const Point& p) const {
        return abs((p2 - p1).cross(p - p1)) / p1.distance(p2);
    }
    
    // 点到线段距离
    double distanceToSegment(const Point& p) const {
        if (p2 - p1).dot(p - p1) <= 0) return p1.distance(p);
        if ((p1 - p2).dot(p - p2) <= 0) return p2.distance(p);
        return distanceToLine(p);
    }
    
    // 判断点在直线上
    bool onLine(const Point& p) const {
        return abs((p2 - p1).cross(p - p1)) < EPS;
    }
    
    // 判断点在线段上
    bool onSegment(const Point& p) const {
        return onLine(p) && 
               p.x >= min(p1.x, p2.x) && p.x <= max(p1.x, p2.x) &&
               p.y >= min(p1.y, p2.y) && p.y <= max(p1.y, p2.y);
    }
};
class Line {
    Point p1, p2;  // 直线上两点
    static final double EPS = 1e-10;
    
    Line(Point p1, Point p2) {
        this.p1 = p1;
        this.p2 = p2;
    }
    
    // 点到直线距离
    double distanceToLine(Point p) {
        return Math.abs(p2.subtract(p1).cross(p.subtract(p1))) / p1.distance(p2);
    }
    
    // 点到线段距离
    double distanceToSegment(Point p) {
        if (p2.subtract(p1).dot(p.subtract(p1)) <= 0) return p1.distance(p);
        if (p1.subtract(p2).dot(p.subtract(p2)) <= 0) return p2.distance(p);
        return distanceToLine(p);
    }
    
    // 判断点在直线上
    boolean onLine(Point p) {
        return Math.abs(p2.subtract(p1).cross(p.subtract(p1))) < EPS;
    }
    
    // 判断点在线段上
    boolean onSegment(Point p) {
        return onLine(p) && 
               p.x >= Math.min(p1.x, p2.x) && p.x <= Math.max(p1.x, p2.x) &&
               p.y >= Math.min(p1.y, p2.y) && p.y <= Math.max(p1.y, p2.y);
    }
}
class Line:
    def __init__(self, p1: Point = Point(), p2: Point = Point()):
        self.p1 = p1
        self.p2 = p2
        self.EPS = 1e-10
    
    # 点到直线距离
    def distance_to_line(self, p: Point) -> float:
        return abs((self.p2 - self.p1).cross(p - self.p1)) / self.p1.distance(self.p2)
    
    # 点到线段距离
    def distance_to_segment(self, p: Point) -> float:
        if (self.p2 - self.p1).dot(p - self.p1) <= 0:
            return self.p1.distance(p)
        if (self.p1 - self.p2).dot(p - self.p2) <= 0:
            return self.p2.distance(p)
        return self.distance_to_line(p)
    
    # 判断点在直线上
    def on_line(self, p: Point) -> bool:
        return abs((self.p2 - self.p1).cross(p - self.p1)) < self.EPS
    
    # 判断点在线段上
    def on_segment(self, p: Point) -> bool:
        return (self.on_line(p) and
                min(self.p1.x, self.p2.x) <= p.x <= max(self.p1.x, self.p2.x) and
                min(self.p1.y, self.p2.y) <= p.y <= max(self.p1.y, self.p2.y))

时间复杂度分析

操作 时间复杂度 空间复杂度
点到直线距离
点到线段距离
点在直线判断
点在线段判断

应用场景

  1. 距离计算
  2. 位置判断
  3. 相对方向
  4. 几何构造
  5. 碰撞检测

注意事项

  1. 浮点数精度
  2. 除零判断
  3. 边界情况
  4. 平行处理
  5. 数值稳定性

常见变形

  1. 点到折线距离
class Solution {
public:
    // 计算点到折线的最短距离
    double distanceToPolyline(const Point& p, const vector<Point>& points) {
        double minDist = DBL_MAX;
        for (int i = 0; i < points.size() - 1; i++) {
            Line segment(points[i], points[i + 1]);
            minDist = min(minDist, segment.distanceToSegment(p));
        }
        return minDist;
    }
    
    // 判断点是否在折线上
    bool onPolyline(const Point& p, const vector<Point>& points) {
        for (int i = 0; i < points.size() - 1; i++) {
            Line segment(points[i], points[i + 1]);
            if (segment.onSegment(p)) return true;
        }
        return false;
    }
};
class Solution {
    // 计算点到折线的最短距离
    public double distanceToPolyline(Point p, Point[] points) {
        double minDist = Double.MAX_VALUE;
        for (int i = 0; i < points.length - 1; i++) {
            Line segment = new Line(points[i], points[i + 1]);
            minDist = Math.min(minDist, segment.distanceToSegment(p));
        }
        return minDist;
    }
    
    // 判断点是否在折线上
    public boolean onPolyline(Point p, Point[] points) {
        for (int i = 0; i < points.length - 1; i++) {
            Line segment = new Line(points[i], points[i + 1]);
            if (segment.onSegment(p)) return true;
        }
        return false;
    }
}
class Solution:
    # 计算点到折线的最短距离
    def distance_to_polyline(self, p: Point, points: List[Point]) -> float:
        min_dist = float('inf')
        for i in range(len(points) - 1):
            segment = Line(points[i], points[i + 1])
            min_dist = min(min_dist, segment.distance_to_segment(p))
        return min_dist
    
    # 判断点是否在折线上
    def on_polyline(self, p: Point, points: List[Point]) -> bool:
        return any(Line(points[i], points[i + 1]).on_segment(p)
                  for i in range(len(points) - 1))
  1. 点到直线投影
class Solution {
public:
    // 计算点在直线上的投影点
    Point projectToLine(const Point& p, const Line& line) {
        Point dir = line.p2 - line.p1;
        double t = dir.dot(p - line.p1) / dir.dot(dir);
        return line.p1 + Point(dir.x * t, dir.y * t);
    }
    
    // 计算点关于直线的对称点
    Point reflectPoint(const Point& p, const Line& line) {
        Point proj = projectToLine(p, line);
        return proj * 2 - p;
    }
};
class Solution {
    // 计算点在直线上的投影点
    public Point projectToLine(Point p, Line line) {
        Point dir = line.p2.subtract(line.p1);
        double t = dir.dot(p.subtract(line.p1)) / dir.dot(dir);
        return line.p1.add(new Point(dir.x * t, dir.y * t));
    }
    
    // 计算点关于直线的对称点
    public Point reflectPoint(Point p, Line line) {
        Point proj = projectToLine(p, line);
        return new Point(
            2 * proj.x - p.x,
            2 * proj.y - p.y
        );
    }
}
class Solution:
    # 计算点在直线上的投影点
    def project_to_line(self, p: Point, line: Line) -> Point:
        dir = line.p2 - line.p1
        t = dir.dot(p - line.p1) / dir.dot(dir)
        return line.p1 + Point(dir.x * t, dir.y * t)
    
    # 计算点关于直线的对称点
    def reflect_point(self, p: Point, line: Line) -> Point:
        proj = self.project_to_line(p, line)
        return Point(2 * proj.x - p.x, 2 * proj.y - p.y)
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论

相关推荐

风的叶脉:不知道但我想要鞭打你( '-' )ノ)`-' ) 加油
点赞 评论 收藏
分享
03-30 19:30
石家庄学院 Java
野蛮的柯基在游泳:都能入股了,还得是Java
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客企业服务