如何在ThreeJS中检测一条THREE.Line是否处于另一条THREE.Line的起止点之间
如何检测一条THREE.Line是否完全处于另一条THREE.Line的线段范围内
你的现有代码是用来检测两条线段是否相交的,所以线条交叉时会返回true,但这不符合你需要的「line1完全处于line2的起止点构成的线段内」的需求——简单说,你要的是判断line1是line2的子线段,而非仅仅相交。
实现思路
要实现这个判断,必须满足两个核心条件:
- line1和line2共线(否则不可能存在包含关系);
- line1的两个端点都落在line2的线段范围内。
我们可以利用Three.js内置的Vector3方法简化计算,避免手动编写复杂的线性代数公式:
type Point = THREE.Vector3; function isLineContained(line1Start: Point, line1End: Point, line2Start: Point, line2End: Point): boolean { // 1. 判断两条线段是否共线 const line2Dir = line2End.clone().sub(line2Start); // 计算line1起点到line2起点的向量与line2方向向量的叉乘 const crossStart = line2Dir.clone().cross(line1Start.clone().sub(line2Start)); // 计算line1终点到line2起点的向量与line2方向向量的叉乘 const crossEnd = line2Dir.clone().cross(line1End.clone().sub(line2Start)); // 叉乘结果非零则不共线,直接返回false // 使用isZero()处理浮点精度误差,而非直接判断===0 if (!crossStart.isZero() || !crossEnd.isZero()) { return false; } // 2. 判断line1的两个端点是否都在line2的线段上 const line2LengthSq = line2Dir.lengthSq(); // 计算点积,得到端点在line2方向上的投影长度(相对于line2起点) const dotStart = line1Start.clone().sub(line2Start).dot(line2Dir); const dotEnd = line1End.clone().sub(line2Start).dot(line2Dir); // 投影长度需在0到line2的长度平方之间(对应线段的起止范围) const isStartInRange = dotStart >= 0 && dotStart <= line2LengthSq; const isEndInRange = dotEnd >= 0 && dotEnd <= line2LengthSq; return isStartInRange && isEndInRange; } // 测试示例 const line1Start = new THREE.Vector3(0, 0, 0); const line1End = new THREE.Vector3(10, 0, 0); // 测试1:line1部分超出line2范围,返回false const line2Start = new THREE.Vector3(5, 0, 0); const line2End = new THREE.Vector3(15, 0, 0); console.log(isLineContained(line1Start, line1End, line2Start, line2End)); // false // 测试2:line1完全在line2范围内,返回true const line3Start = new THREE.Vector3(6, 0, 0); const line3End = new THREE.Vector3(12, 0, 0); console.log(isLineContained(line3Start, line3End, line2Start, line2End)); // true
关键细节说明
- 共线判断:叉乘的几何意义是判断两个向量是否垂直,若叉乘结果为零向量,则说明两个向量共线。使用Three.js的
isZero()方法可以自动处理浮点运算的精度误差,避免因微小数值偏差导致误判。 - 点在线段上的判断:通过点积计算端点在目标线段方向上的投影长度,若投影长度在0到目标线段的长度平方之间,则说明该点落在目标线段的范围内(使用长度平方而非长度可以避免开方运算,提升性能)。
内容的提问来源于stack exchange,提问作者user16938897
相关产品推荐
相关产品推荐

