在三维解析几何中,点到平面的距离是一个基本问题,它不仅在数学理论中占有重要地位,在计算机图形学、机器人运动规划、物理仿真等领域也有广泛应用。给定一个点 P(x0,y0,z0)P(x_0, y_0, z_0)P(x0,y0,z0) 和一个平面 Π:Ax+By+Cz+D=0\Pi: Ax + By + Cz + D = 0Π:Ax+By+Cz+D=0(其中 A,B,CA, B, CA,B,C 不全为零),点 PPP 到平面 Π\PiΠ 的垂直距离 ddd 可以通过一个简洁的公式计算。

公式与几何解释
距离公式为
d=∣Ax0+By0+Cz0+D∣A2+B2+C2 d = \frac{|Ax_0 + By_0 + Cz_0 + D|}{\sqrt{A^2 + B^2 + C^2}} d=A2+B2+C2 ∣Ax0+By0+Cz0+D∣
几何上,向量 n=(A,B,C)\mathbf{n} = (A, B, C)n=(A,B,C) 是平面的法向量。分子 ∣Ax0+By0+Cz0+D∣|Ax_0 + By_0 + Cz_0 + D|∣Ax0+By0+Cz0+D∣ 表示将点坐标代入平面方程后的绝对值,它等于 ∣n⋅(P−P0)∣|\mathbf{n} \cdot (P - P_0)|∣n⋅(P−P0)∣,其中 P0P_0P0 是平面上任意一点。分母 ∥n∥=A2+B2+C2\|\mathbf{n}\| = \sqrt{A^2 + B^2 + C^2}∥n∥=A2+B2+C2 是法向量的长度。因此,距离恰好是向量 P0P→\overrightarrow{P_0P}P0P 在法向量方向上的投影长度。
公式推导概要
设 QQQ 是平面上的投影点,则 PQ→\overrightarrow{PQ}PQ 与 n\mathbf{n}n 平行。由于 QQQ 满足平面方程,有 AxQ+ByQ+CzQ+D=0A x_Q + B y_Q + C z_Q + D = 0AxQ+ByQ+CzQ+D=0。又因为 PQ→=λn\overrightarrow{PQ} = \lambda \mathbf{n}PQ =λn,代入点坐标关系可得
d=∣λ∣∥n∥=∣Ax0+By0+Cz0+D∣∥n∥ d = |\lambda| \|\mathbf{n}\| = \frac{|Ax_0 + By_0 + Cz_0 + D|}{\|\mathbf{n}\|} d=∣λ∣∥n∥=∥n∥∣Ax0+By0+Cz0+D∣
该推导不依赖于具体选定的 QQQ 点,因此公式具有普遍性。
数值计算示例
取点 P(1,2,3)P(1, 2, 3)P(1,2,3) 和平面 2x−y+2z+1=02x - y + 2z + 1 = 02x−y+2z+1=0。则
d=∣2⋅1−2+2⋅3+1∣22+(−1)2+22=∣2−2+6+1∣3=73≈2.3333 d = \frac{|2\cdot1 - 2 + 2\cdot3 + 1|}{\sqrt{2^2 + (-1)^2 + 2^2}} = \frac{|2 - 2 + 6 + 1|}{3} = \frac{7}{3} \approx 2.3333 d=22+(−1)2+22 ∣2⋅1−2+2⋅3+1∣=3∣2−2+6+1∣=37≈2.3333
下面提供三个独立可运行的代码片段,分别使用 Python、C++ 和 JavaScript 实现该计算。每个代码块均包含完整的输入输出,无需任何外部依赖(标准库即可)。
Python 实现
python
import math
def point_to_plane_distance(point, plane_coeffs):
"""
计算点到平面的距离。
point: (x0, y0, z0)
plane_coeffs: (A, B, C, D) 对应 Ax + By + Cz + D = 0
"""
x0, y0, z0 = point
A, B, C, D = plane_coeffs
numerator = abs(A * x0 + B * y0 + C * z0 + D)
denominator = math.sqrt(A * A + B * B + C * C)
if denominator == 0:
raise ValueError("平面方程系数 (A,B,C) 不能同时为零")
return numerator / denominator
if __name__ == "__main__":
point = (1.0, 2.0, 3.0)
plane = (2.0, -1.0, 2.0, 1.0)
d = point_to_plane_distance(point, plane)
print(f"点 {point} 到平面 {plane[0]}x + {plane[1]}y + {plane[2]}z + {plane[3]} = 0 的距离为: {d:.6f}")
# 输出示例: 点 (1.0, 2.0, 3.0) 到平面 2x + -1y + 2z + 1 = 0 的距离为: 2.333333
C++ 实现
cpp
#include <iostream>
#include <cmath>
double point_to_plane_distance(double x0, double y0, double z0,
double A, double B, double C, double D) {
double numerator = std::abs(A * x0 + B * y0 + C * z0 + D);
double denominator = std::sqrt(A * A + B * B + C * C);
if (denominator == 0.0) {
throw std::invalid_argument("平面法向量长度为零");
}
return numerator / denominator;
}
int main() {
double x0 = 1.0, y0 = 2.0, z0 = 3.0;
double A = 2.0, B = -1.0, C = 2.0, D = 1.0;
double d = point_to_plane_distance(x0, y0, z0, A, B, C, D);
std::cout << "点 (" << x0 << ", " << y0 << ", " << z0 << ") 到平面 "
<< A << "x + " << B << "y + " << C << "z + " << D << " = 0 的距离为: "
<< d << std::endl;
return 0;
}
JavaScript (Node.js 或浏览器环境) 实现
javascript
function pointToPlaneDistance(point, planeCoefs) {
const [x0, y0, z0] = point;
const [A, B, C, D] = planeCoefs;
const numerator = Math.abs(A * x0 + B * y0 + C * z0 + D);
const denominator = Math.sqrt(A * A + B * B + C * C);
if (denominator === 0) {
throw new Error("平面法向量长度为零");
}
return numerator / denominator;
}
// 示例运行
const point = [1.0, 2.0, 3.0];
const plane = [2.0, -1.0, 2.0, 1.0];
const distance = pointToPlaneDistance(point, plane);
console.log(`点 (${point[0]}, ${point[1]}, ${point[2]}) 到平面 ${plane[0]}x + ${plane[1]}y + ${plane[2]}z + ${plane[3]} = 0 的距离为: ${distance.toFixed(6)}`);
深度讨论:符号与退化情况
当 A,B,CA, B, CA,B,C 不全为零时,分母为正数,距离总是非负实数。如果点恰好位于平面上,则分子为零,距离为零。若将平面方程乘以一个非零常数 kkk,新方程 kAx+kBy+kCz+kD=0kAx + kBy + kCz + kD = 0kAx+kBy+kCz+kD=0 表示同一平面,代入公式后分子分母同时放大 ∣k∣|k|∣k∣ 倍,距离不变,这保证了公式的几何不变性。
值得注意的退化情形:若 A=B=C=0A = B = C = 0A=B=C=0,则 DDD 必须也为零才能表示一个平面(否则无意义),此时公式分母为零,因此使用该公式前应确保输入有效。在实际编程中,总是检查法向量长度是否为零。
应用拓展
该距离公式可以直接推广到更高维空间:在 Rn\mathbb{R}^nRn 中,超平面 n⋅x+D=0\mathbf{n} \cdot \mathbf{x} + D = 0n⋅x+D=0 到点 p\mathbf{p}p 的距离为 ∣n⋅p+D∣/∥n∥|\mathbf{n} \cdot \mathbf{p} + D| / \|\mathbf{n}\|∣n⋅p+D∣/∥n∥。这一形式在机器学习中的支持向量机(SVM)里计算几何间隔时也会用到。
通过上述讨论与独立可运行的代码实现,我们不仅掌握了点到平面距离的计算方法,也理解了其背后的线性代数本质。