如何将3D点B移至A、C之间并使AB与BC距离为原距离平均值?
问题需求与现有问题
固定3D点A与C,需将点B移动至A、C之间的区域,使得移动后AB与BC的距离均等于原AB、BC距离的平均值。当前使用的代码会导致点位置翻转,且多次执行仅能近似达到目标效果,寻求正确实现思路。
现有代码:
Vector3 dir_a = B - A; Vector3 dir_b = B - C; float averageDistance = (dir_a.magnitude + dir_b.magnitude) / 2; dir_a.Normalize(); dir_b.Normalize(); B -= (averageDistance) * (dir_a + dir_b);
问题分析与解决方案
现有代码的核心问题
- 向量方向逻辑错误:
dir_a是从A指向B的向量,dir_b是从C指向B的向量,两者相加的方向通常是远离AC中点的外侧方向,用B减去该向量会导致点向不可控的方向偏移,甚至出现翻转。 - 计算逻辑不符合几何规则:直接用平均值乘以向量和调整位置的方式,没有遵循“AB和BC均等于平均值”的几何逻辑,只能通过多次迭代近似,无法一步到位得到正确结果。
正确实现思路
要让移动后的B'满足AB' = BC' = 原AB与BC的平均值,且位于A、C之间的区域,需基于几何圆交点逻辑实现:
- 计算原AB、BC的距离,得到目标平均值
avgDist。 - 计算AC线段的中点
midAC和AC的总长度acLength。 - 验证可行性:若
avgDist < acLength/2,说明以A、C为圆心avgDist为半径的圆无交点,无法满足AB'=BC'=avgDist,此时退而求其次将B'设为AC中点(保证AB'=BC')。 - 若
avgDist >= acLength/2,计算垂直于AC方向的偏移长度(基于勾股定理),再结合AC中点得到符合要求的B'位置。
正确代码实现
// 计算原距离与目标平均值 float distAB = Vector3.Distance(A, B); float distBC = Vector3.Distance(B, C); float avgDist = (distAB + distBC) / 2; // 计算AC的中点与总长度 Vector3 midAC = (A + C) / 2; float acLength = Vector3.Distance(A, C); Vector3 newB; if (avgDist < acLength / 2f) { // 无法满足双距离等于平均值,取AC中点保证AB=BC newB = midAC; } else { // 计算垂直于AC的单位向量(避免与AC共线) Vector3 acDir = C - A; Vector3 perpendicularDir; if (Mathf.Abs(Vector3.Dot(acDir.normalized, Vector3.up)) < 0.99f) { perpendicularDir = Vector3.Cross(acDir, Vector3.up).normalized; } else { perpendicularDir = Vector3.Cross(acDir, Vector3.right).normalized; } // 计算垂直方向的偏移长度(勾股定理) float offsetLength = Mathf.Sqrt(avgDist * avgDist - (acLength / 2f) * (acLength / 2f)); // 生成新的B点位置(可替换为-perpendicularDir选择另一侧) newB = midAC + perpendicularDir * offsetLength; } // 更新B点位置 B = newB;
补充说明
若需求为将B'严格移动到AC线段上(而非区域内),则仅当avgDist * 2 == acLength时存在符合AB'=BC'=avgDist的点;否则可选择:
- 让
AB'=avgDist,此时BC'=acLength - avgDist - 让
BC'=avgDist,此时AB'=acLength - avgDist - 直接取AC中点
内容的提问来源于stack exchange,提问作者DragonGamer
相关产品推荐
相关产品推荐

