跳到主要内容

直线

一、计算直线解析式

1.1 斜截式 y = kx + b

bool get_line_slope_intercept(int x1, int y1, 
int x2, int y2,
double &k, double &b) {
if (x1 == x2)
return false; // 垂直线, 无法表示为斜截式
k = (y2 - y1) * 1.0 / (x2 - x1);
b = y1 - k * x1;
return true;
}
C++

因为需要讨论斜率不存在, 以及精度损失. 因此我们一般 不使用 这个刁毛.

1.2 一般式 Ax + By + C = 0

// 返回直线 Ax + By + C = 0 中的 A, B, C
void get_line_general_form(int x1, int y1,
int x2, int y2,
int &A, int &B, int &C) {
A = y2 - y1;
B = x1 - x2;
C = x2 * y1 - x1 * y2;
}
C++

1.2.1 推导: 向量叉乘法

核心思想:

一条直线上任意一点,与给定的两个点构成的向量,它们是共线的,那共线的两个向量叉积就为 0。

我们用这条直线上任意一点 (x,y)(x, y) 来构造向量,考虑:

  • 向量1: v1=(x2x1,y2y1)\vec{v_1} = (x_2 - x_1, y_2 - y_1), 即 AB 向量
  • 向量2: v2=(xx1,yy1)\vec{v_2} = (x - x_1, y - y_1), 即 AM 向量(任意点)

如果点 (x,y)(x, y) 在直线上, 那么

v1×v2=0\vec{v_1} \times \vec{v_2} = 0

叉乘公式(二维):

(x2x1)(yy1)(y2y1)(xx1)=0(x_2 - x_1)(y - y_1) - (y_2 - y_1)(x - x_1) = 0

展开整理:

(x2x1)y(x2x1)y1(y2y1)x+(y2y1)x1=0(x_2 - x_1)y - (x_2 - x_1)y_1 - (y_2 - y_1)x + (y_2 - y_1)x_1 = 0

我们把它整理成 Ax+By+C=0Ax + By + C = 0 形式:

  • A=y2y1A = y_2 - y_1
  • B=x1x2B = x_1 - x_2
  • C=x2y1x1y2C = x_2 y_1 - x_1 y_2

就推出来了!

记忆方法:

A = y2 - y1;
B = x1 - x2;
C = x2 * y1 - x1 * y2;
// => A = Δy,B = -Δx,C = -叉积

// 叉积
// = (x1, y1) x (x2, y2)
// = x1 * y2 - x2 * y1
cpp

1.2.2 板子

tuple<int, int, int> getLine(
vector<int> const& a,
vector<int> const& b
) {
int x1 = a[0], y1 = a[1];
int x2 = b[0], y2 = b[1];
int A = y2 - y1;
int B = x1 - x2;
int C = x2 * y1 - x1 * y2;

int g = gcd(gcd(abs(A), abs(B)), abs(C));
if (g) {
A /= g, B /= g, C /= g;
}

// 保证符号一致性
if (A < 0 || (A == 0 && B < 0)) {
A = -A; B = -B; C = -C;
}

return {A, B, C};
}
C++

Tip

因为计算的tuple<int, int, int>是不唯一的, 也就是不是最简的, 因此我们需要使用 gcd\gcd 归一化!

请作者喝奶茶:
Alipay IconQR Code
Alipay IconQR Code
本文遵循 CC CC 4.0 BY-SA 版权协议, 转载请标明出处
Loading Comments...