曲线曲面求交解析方案-平面+曲线
文章目录
- 曲线曲面求交解析方案-平面+曲线
-
- [一. 通用约定](#一. 通用约定)
-
- [1. 输入对象](#1. 输入对象)
- [2. 容差规则](#2. 容差规则)
- [3. 结果规则](#3. 结果规则)
- [二. 直线与平面求交](#二. 直线与平面求交)
-
- [1. 有限线段的端点距离分类](#1. 有限线段的端点距离分类)
- [2. 穿越时的精确交点](#2. 穿越时的精确交点)
- [3. 无限直线情况](#3. 无限直线情况)
- [三. 圆/椭圆与平面求交](#三. 圆/椭圆与平面求交)
-
- [1. 为什么不直接用两平面交线与圆/椭圆求交](#1. 为什么不直接用两平面交线与圆/椭圆求交)
- [2. 统一参数表达](#2. 统一参数表达)
- [3. 先处理平面平行/共面](#3. 先处理平面平行/共面)
- [4. 非平行时用最大/最小有向距离分类](#4. 非平行时用最大/最小有向距离分类)
- [5. 交点数量分类](#5. 交点数量分类)
-
- [5.1 无交](#5.1 无交)
- [5.2 一个切触/容差接触点](#5.2 一个切触/容差接触点)
- [5.3 两个交点](#5.3 两个交点)
- [6. 容差模糊区处理](#6. 容差模糊区处理)
- [7. 伪代码](#7. 伪代码)
- [附录 A:椭圆到平面的最大/最小有向距离点推导](#附录 A:椭圆到平面的最大/最小有向距离点推导)
- [附录 B:两个交点参数 `t = phi ± acos(-D / S)` 的推导](#附录 B:两个交点参数
t = phi ± acos(-D / S)的推导)
本文档单独记录直线、圆、椭圆与平面的解析求交方案。核心目标是用原始曲线到目标平面的有向距离做稳定分类,避免浅夹角情况下直接构造两平面交线导致的容差漏交。
一. 通用约定
1. 输入对象
曲线对象:
LGKLine3dLGKCircle3dLGKEllipse3d
曲面对象:
LGKPlane
2. 容差规则
- 平行、垂直等方向关系使用系统角度容差
LGKConstants::AngleTolerance。 - 点到平面、点到曲线相交判断使用调用方传入的长度容差,例如曲线曲面求交 option 中的
m_tol。 - 参数范围过滤不能只用参数差扩张,应最终回到空间距离校验。
- 所有候选点加入结果前必须同时满足:
- 在曲线参数范围内;
- 在平面参数范围内,如果平面被上层裁剪为有界参数域;
- 点在原始曲线和原始平面上。
3. 结果规则
离散交点至少记录:
- 3D 交点坐标;
- 曲线参数
curveParam; - 平面参数
uv; - 求交类型:普通交点
Simple或切触/容差接触Tangent。
如果曲线整体位于平面内,数学结果是重合区间,不是离散交点。当前点求交接口若不能直接返回 overlap,可暂时返回空点结果;后续应通过 overlap 结果扩展表达。
二. 直线与平面求交
适用对象:LGKLine3d 或有限线段与平面。
直线/线段与平面求交应优先使用点到平面的有向距离做分类,而不是先直接套代数公式。原因是有向距离分类可以自然处理无交、穿越、端点接触和重合,并且和圆/椭圆-平面求交的"先看距离范围,再生成交点"的思路一致。
1. 有限线段的端点距离分类
设线段为:
text
L(t) = P0 + t (P1 - P0), t ∈ [0, 1]
平面为:
text
n · (X - Q) = 0
其中 n 是单位法向。计算两个端点到平面的有向距离:
text
d0 = n · (P0 - Q)
d1 = n · (P1 - Q)
用 d0、d1 和长度容差 tol 分类:
d0 > tol && d1 > tol:两个端点都在平面正侧,无交;d0 < -tol && d1 < -tol:两个端点都在平面负侧,无交;|d0| <= tol && |d1| <= tol:整条线段在平面容差内,返回重合区间;- 只有一个端点满足
|di| <= tol:返回该端点作为端点接触; d0、d1一正一负:线段穿过平面,计算精确交点。
2. 穿越时的精确交点
当端点有向距离异号时,交点参数由线性插值得到:
text
t = d0 / (d0 - d1)
交点为:
text
P = P0 + t (P1 - P0)
这个公式来自:
text
d(t) = (1 - t) d0 + t d1
令 d(t) = 0:
text
(1 - t) d0 + t d1 = 0
得到:
text
t = d0 / (d0 - d1)
候选点加入结果前仍应检查:
t是否位于[0, 1];|n · (P - Q)| <= tol;- 如果上层使用无限直线或射线,按对应参数域规则过滤。
3. 无限直线情况
如果输入是无限直线:
text
L(t) = O + t D
计算:
text
den = n · D
num = n · (O - Q)
|den| <= angleTol且|num| <= tol:直线位于平面内,返回重合直线;|den| <= angleTol且|num| > tol:直线平行平面,无交;- 否则:
text
t = -num / den
P = O + t D
对于有限线段,即使底层用无限直线公式生成候选点,最终也应回到端点有向距离和参数域做过滤。线段场景下,端点距离分类是更稳定、更直接的主流程。
三. 圆/椭圆与平面求交
适用对象:LGKCircle3d / LGKEllipse3d 与平面。
圆和椭圆都是位于自身平面内的完整平面曲线。与另一个平面求交时,数学上可以转化为"曲线所在平面与目标平面的交线"再与圆/椭圆求交;但是在几何内核中,直接把两平面交线作为主判据会有小角度容差问题。因此本方案优先使用圆/椭圆上点到目标平面的最大/最小有向距离进行分类。
1. 为什么不直接用两平面交线与圆/椭圆求交
设曲线所在平面为 Pi_c,目标平面为 Pi。当二者不平行时,精确数学交点一定落在:
text
L = Pi_c ∩ Pi
因此直接计算 L,再做 L 与圆/椭圆求交,看起来最自然。但当两个平面夹角很小时,这个方案会变得不稳定:
- 两平面交线的位置对平面法向和点位误差非常敏感。夹角越小,同样的平面距离误差会在交线位置上放大得越明显。
L与圆/椭圆的求交通常是严格的曲线内判定。如果交线因为数值误差被推离曲线,可能得到"无交"。- 但从原始几何角度看,圆/椭圆上某个点到目标平面的距离可能已经在长度容差内,这应该被识别为容差接触或切触。
- 因此,小角度时"交线没有精确碰到圆/椭圆"不等价于"圆/椭圆与目标平面在容差意义下无交"。
换句话说,线-圆/线-椭圆适合作为交点生成手段,但不适合作为浅夹角情况下的唯一存在性判据。
更稳定的判据是直接考察曲线上所有点到目标平面的有向距离范围:
text
dMin <= d(t) <= dMax
如果整个距离范围都在目标平面一侧,则无交;如果极值距离在容差内,则有一个切触/容差接触点;如果最小值和最大值异号,则有两个交点。这个判据直接作用在原始曲线和目标平面上,不需要构造病态的两平面交线。
2. 统一参数表达
椭圆参数式:
text
E(t) = C + a cos(t) U + b sin(t) V
其中:
C:椭圆中心;U、V:椭圆所在平面内的两个正交单位轴;a、b:两个半轴长度;N = U × V:椭圆所在平面法向;t:椭圆参数,完整椭圆通常取[0, 2pi)。
圆是椭圆的特例:
text
a = b = R
目标平面为:
text
n · (X - P0) = 0
其中 n 是单位法向,P0 是平面上一点。
3. 先处理平面平行/共面
先判断曲线所在平面和目标平面是否平行:
text
|N × n| <= angleTol
或等价地使用 abs(N · n) 接近 1。
如果平行,则判断中心到目标平面的有向距离:
text
D = n · (C - P0)
|D| <= tol:曲线整体位于目标平面内,返回重合类型,参数区间为完整圆/椭圆参数域,或弧段自身参数域;|D| > tol:平行不共面,无交。
4. 非平行时用最大/最小有向距离分类
非平行时,曲线上点到目标平面的有向距离为:
text
d(t) = n · (E(t) - P0)
它可以写成:
text
d(t) = D + A cos(t) + B sin(t)
其中:
text
D = n · (C - P0)
A = a (n · U)
B = b (n · V)
令:
text
S = sqrt(A^2 + B^2)
phi = atan2(B, A)
则最大/最小有向距离和对应参数为:
text
dMax = D + S, tMax = phi
dMin = D - S, tMin = phi + pi
对应空间点为:
text
PMax = E(tMax)
PMin = E(tMin)
这一步对圆和椭圆都成立,不需要再按平面夹角是否大于 45° 分支。圆的最大/最小点退化为沿目标平面法向在圆平面内投影方向的两个点;椭圆的最大/最小点是椭圆在该方向上的支撑点,受半轴长度影响。
5. 交点数量分类
使用 dMin、dMax 和长度容差 tol 分类:
5.1 无交
text
dMin > tol
或:
text
dMax < -tol
说明整条圆/椭圆都在目标平面同一侧,无交。
5.2 一个切触/容差接触点
如果:
text
|dMin| <= tol
则最小距离点 PMin = E(phi + pi) 是切触/容差接触点。
如果:
text
|dMax| <= tol
则最大距离点 PMax = E(phi) 是切触/容差接触点。
这里推荐直接返回极值点,而不是再依赖两平面交线与圆/椭圆求交。因为这个分支正是浅夹角下最容易被交线法漏掉的情况。
5.3 两个交点
如果:
text
dMin < -tol && dMax > tol
说明曲线一部分在目标平面正侧,一部分在负侧,必然有两个交点。
两个交点参数可以直接解析得到:
text
theta = acos(clamp(-D / S, -1, 1))
t1 = phi + theta
t2 = phi - theta
再计算:
text
P1 = E(t1)
P2 = E(t2)
候选点加入结果前仍需:
- 对周期参数做归一化;
- 如果是圆弧/椭圆弧,检查参数范围;
- 用点到目标平面的空间距离做最终验证;
- 按 3D 点距离去重;
- 根据切向与平面法向关系标记普通交点或切触点。
6. 容差模糊区处理
可能出现以下接近退化的情况:
S非常小:非平行判断和距离函数矛盾,通常说明两个平面几乎平行、输入轴不规范或曲线退化;dMin和dMax都在容差内:数学上非平行完整非退化椭圆不应整体在平面内,但在容差意义下整条曲线可能都接近目标平面;- 两个解析交点非常接近:接近相切,应按空间距离去重,并优先返回切触类型。
这些情况不应通过宽泛异常或静默空结果掩盖。建议保留明确分支:要么按近似重合/容差接触返回,要么降级到通用数值校验,并在调试日志中暴露原因。
7. 伪代码
text
IntersectEllipsePlane(E, Plane)
{
C = E.center
U = normalize(E.axisU)
V = normalize(E.axisV)
a = E.radiusU
b = E.radiusV
N = normalize(U × V)
n = normalize(Plane.normal)
P0 = Plane.origin
if IsParallel(N, n, angleTol):
D = n · (C - P0)
if abs(D) <= tol:
return Coincident(E, E.interval)
return Empty
D = n · (C - P0)
A = a * (n · U)
B = b * (n · V)
S = hypot(A, B)
if S <= tol:
return HandleNearParallelOrDegenerateCase()
phi = atan2(B, A)
dMin = D - S
dMax = D + S
if dMin > tol or dMax < -tol:
return Empty
result = EmptyResult
if abs(dMin) <= tol:
t = NormalizePeriod(phi + pi)
result.AddTouch(E(t), t)
if abs(dMax) <= tol:
t = NormalizePeriod(phi)
result.AddTouch(E(t), t)
if result not empty:
result.UniqueBy3dDistance(tol)
return result
// dMin < -tol && dMax > tol
q = clamp(-D / S, -1, 1)
theta = acos(q)
t1 = NormalizePeriod(phi + theta)
t2 = NormalizePeriod(phi - theta)
result.AddIfValid(E(t1), t1)
result.AddIfValid(E(t2), t2)
result.UniqueBy3dDistance(tol)
return result
}
附录 A:椭圆到平面的最大/最小有向距离点推导
椭圆参数式为:
text
E(t) = C + a cos(t) U + b sin(t) V
平面有向距离为:
text
d(t) = n · (E(t) - P0)
代入椭圆参数式:
text
d(t)
= n · (C - P0)
+ a (n · U) cos(t)
+ b (n · V) sin(t)
记:
text
D = n · (C - P0)
A = a (n · U)
B = b (n · V)
则:
text
d(t) = D + A cos(t) + B sin(t)
D 是常数,不影响极值点。只需要求:
text
g(t) = A cos(t) + B sin(t)
的极值。对 g(t) 求导:
text
g'(t) = -A sin(t) + B cos(t)
极值点满足:
text
-A sin(t) + B cos(t) = 0
即:
text
B cos(t) = A sin(t)
使用 atan2 避免 A = 0 的除零问题,得到:
text
phi = atan2(B, A)
并有:
text
cos(phi) = A / S
sin(phi) = B / S
S = sqrt(A^2 + B^2)
因此在 t = phi 时:
text
g(phi) = A cos(phi) + B sin(phi)
= A^2 / S + B^2 / S
= S
这是最大值;在 t = phi + pi 时:
text
g(phi + pi) = -S
这是最小值。所以:
text
dMax = D + S, tMax = phi
dMin = D - S, tMin = phi + pi
几何上,最大点相对椭圆中心的向量为:
text
E(tMax) - C
= a cos(phi) U + b sin(phi) V
= (a^2 (n · U) / S) U + (b^2 (n · V) / S) V
因此椭圆最大距离点是按 a^2、b^2 加权的支撑点。圆的情况下 a = b = R,该方向退化为目标平面法向在圆平面内的投影方向。
附录 B:两个交点参数 t = phi ± acos(-D / S) 的推导
交点满足点在目标平面上:
text
d(t) = 0
也就是:
text
D + A cos(t) + B sin(t) = 0
令:
text
S = sqrt(A^2 + B^2)
phi = atan2(B, A)
则:
text
cos(phi) = A / S
sin(phi) = B / S
由余弦差角公式:
text
cos(t - phi) = cos(t) cos(phi) + sin(t) sin(phi)
代入上式:
text
cos(t - phi)
= cos(t) A / S + sin(t) B / S
两边乘以 S:
text
S cos(t - phi) = A cos(t) + B sin(t)
因此距离函数可以写为:
text
d(t) = D + S cos(t - phi)
交点条件变成:
text
D + S cos(t - phi) = 0
即:
text
cos(t - phi) = -D / S
令:
text
q = clamp(-D / S, -1, 1)
theta = acos(q)
余弦方程在一个周期内有两个解:
text
t - phi = theta
t - phi = -theta
所以两个交点参数为:
text
t1 = phi + theta
t2 = phi - theta
也就是:
text
t = phi ± acos(-D / S)
当 |D| = S 时,theta 为 0 或 pi,两个参数退化为同一个空间点,对应切触;实现上应由 dMin/dMax 的极值容差分支提前处理。