计算机图形学:线段的交点计算及代码实现


在计算机图形学、几何计算和工程领域中,经常需要计算两条线段的交点。本文将详细介绍线段交点计算的原理、公式推导过程以及代码实现。

原理

要计算两条线段的交点,我们首先需要确定这两条线段是否相交。线段可以由两个端点定义,设线段 A B AB AB的端点为 A ( x 1 , y 1 ) A(x_1, y_1) A(x1,y1) B ( x 2 , y 2 ) B(x_2, y_2) B(x2,y2),线段 C D CD CD的端点为 C ( x 3 , y 3 ) C(x_3, y_3) C(x3,y3) D ( x 4 , y 4 ) D(x_4, y_4) D(x4,y4)

推导过程

  1. 确定线段的方程:线段(AB)和(CD)可以表示为参数方程:
    A B : { x = x 1 + t ( x 2 − x 1 ) y = y 1 + t ( y 2 − y 1 ) ( 0 ≤ t ≤ 1 ) AB: \begin{cases} x = x_1 + t(x_2 - x_1) \\ y = y_1 + t(y_2 - y_1) \end{cases} \quad (0 \leq t \leq 1) AB:{x=x1+t(x2x1)y=y1+t(y2y1)(0t1)

    C D : { x = x 3 + s ( x 4 − x 3 ) y = y 3 + s ( y 4 − y 3 ) ( 0 ≤ s ≤ 1 ) CD: \begin{cases} x = x_3 + s(x_4 - x_3) \\ y = y_3 + s(y_4 - y_3) \end{cases} \quad (0 \leq s \leq 1) CD:{x=x3+s(x4x3)y=y3+s(y4y3)(0s1)

  2. 设置交点条件:如果线段相交,那么存在 t t t s s s使得:
    x 1 + t ( x 2 − x 1 ) = x 3 + s ( x 4 − x 3 ) x_1 + t(x_2 - x_1) = x_3 + s(x_4 - x_3) x1+t(x2x1)=x3+s(x4x3)
    y 1 + t ( y 2 − y 1 ) = y 3 + s ( y 4 − y 3 ) y_1 + t(y_2 - y_1) = y_3 + s(y_4 - y_3) y1+t(y2y1)=y3+s(y4y3)

  3. 解方程组:解这个方程组得到 t t t s s s
    t = ( x 3 − x 1 ) ( y 4 − y 3 ) − ( y 3 − y 1 ) ( x 4 − x 3 ) ( x 2 − x 1 ) ( y 4 − y 3 ) − ( y 2 − y 1 ) ( x 4 − x 3 ) t = \frac{(x3 - x1)(y4 - y3) - (y3 - y1)(x4 - x3)}{(x2 - x1)(y4 - y3) - (y2 - y1)(x4 - x3)} t=(x2x1)(y4y3)(y2y1)(x4x3)(x3x1)(y4y3)(y3y1)(x4x3)
    s = ( x 3 − x 1 ) ( y 2 − y 1 ) − ( y 3 − y 1 ) ( x 2 − x 1 ) ( x 2 − x 1 ) ( y 4 − y 3 ) − ( y 2 − y 1 ) ( x 4 − x 3 ) s = \frac{(x3 - x1)(y2 - y1) - (y3 - y1)(x2 - x1)}{(x2 - x1)(y4 - y3) - (y2 - y1)(x4 - x3)} s=(x2x1)(y4y3)(y2y1)(x4x3)(x3x1)(y2y1)(y3y1)(x2x1)
    如果 t t t s s s都在 [ 0 , 1 ] [0, 1] [0,1]区间内,那么线段相交。

  4. 计算交点:交点的坐标为:
    P ( x 1 + t ( x 2 − x 1 ) , y 1 + t ( y 2 − y 1 ) ) P\left(x_1 + t(x_2 - x_1), y_1 + t(y_2 - y_1)\right) P(x1+t(x2x1),y1+t(y2y1))

代码实现

Python代码

def line_intersection(A, B, C, D):
    x1, y1 = A
    x2, y2 = B
    x3, y3 = C
    x4, y4 = D

    # 计算分母
    denominator = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3)
    if denominator == 0:
        return None  # 线段平行或重合

    # 计算t和s
    t = ((x3 - x1) * (y4 - y3) - (y3 - y1) * (x4 - x3)) / denominator
    s = ((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) / denominator

    # 检查t和s是否在[0, 1]区间内
    if 0 <= t <= 1 and 0 <= s <= 1:
        return (x1 + t * (x2 - x1), y1 + t * (y2 - y1))
    else:
        return None  # 线段不相交

C++代码

#include <iostream>

struct Point {
    double x, y;
};

Point line_intersection(Point A, Point B, Point C, Point D) {
    double x1 = A.x, y1 = A.y;
    double x2 = B.x, y2 = B.y;
    double x3 = C.x, y3 = C.y;
    double x4 = D.x, y4 = D.y;

    // 计算分母
    double denominator = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3);
    if (denominator == 0) {
        return {0, 0};  // 线段平行或重合
    }

    // 计算t和s
    double t = ((x3 - x1) * (y4 - y3) - (y3 - y1) * (x4 - x3)) / denominator;
    double s = ((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) / denominator;

    // 检查t和s是否在[0, 1]区间内
    if (0 <= t && t <= 1 && 0 <= s && s <= 1) {
        return {x1 + t * (x2 - x1), y1 + t * (y2 - y1)};
    } else {
        return {0, 0};  // 线段不相交
    }
}

应用示例

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

def line_intersection(A, B, C, D):
    x1, y1 = A
    x2, y2 = B
    x3, y3 = C
    x4, y4 = D

    # 计算分母
    denominator = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3)
    if denominator == 0:
        return None  # 线段平行或重合

    # 计算t和s
    t = ((x3 - x1) * (y4 - y3) - (y3 - y1) * (x4 - x3)) / denominator
    s = ((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) / denominator

    # 检查t和s是否在[0, 1]区间内
    if 0 <= t <= 1 and 0 <= s <= 1:
        return (x1 + t * (x2 - x1), y1 + t * (y2 - y1))
    else:
        return None  # 线段不相交

# 手动定义线段
segments = [
    ((0.3, 0.3), (0.8, 0.8), (0.2, 0.8), (0.8, 0.2)),
    ((0.2, 0.2), (0.8, 0.2), (0.5, 0.5), (0.8, 0.5)),
    ((0.1, 0.1), (0.7, 0.7), (0.6, 0.22), (0.8, 0.2)),
    ((0.3, 0.3), (0.7, 0.7), (0.4, 0.84), (0.8, 0.2)),
    ((0.2, 0.5), (0.8, 0.4), (0.6, 0.8), (0.7, 0.2)),
    ((0.2, 0.3), (0.8, 0.8), (0.5, 0.2), (0.8, 0.2))
]


fig, ax = plt.subplots()
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_aspect('equal')

# 初始化绘图
line1, = ax.plot([], [], 'b-', animated=True)
line2, = ax.plot([], [], 'b-', animated=True)
point, = ax.plot([], [], 'ro', animated=True)
text = ax.text(0.5, 0.9, '', transform=ax.transAxes, ha='center')

def init():
    line1.set_data([], [])
    line2.set_data([], [])
    point.set_data([], [])
    text.set_text('')
    return line1, line2, point, text

def animate(i):
    A, B, C, D = segments[i]
    intersection = line_intersection(A, B, C, D)

    line1.set_data([A[0], B[0]], [A[1], B[1]])
    line2.set_data([C[0], D[0]], [C[1], D[1]])

    if intersection:
        line1.set_color('r')
        line2.set_color('r')
        point.set_data([intersection[0]], [intersection[1]])
        text.set_text(f'Intersection: ({intersection[0]:.2f}, {intersection[1]:.2f})')
    else:
        line1.set_color('b')
        line2.set_color('b')
        point.set_data([], [])  # 修改这里
        text.set_text('No Intersection')

    return line1, line2, point, text

ani = FuncAnimation(fig, animate, init_func=init, frames=len(segments), interval=500, blit=True)

# 保存动图
ani.save('line_segments.gif', writer='pillow', fps=1)

plt.show()

运行效果如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艰默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值