如果一个立方体 C 有8个角(不是轴对齐)和一个随机点 P ,我可以做的不仅仅是检查所有角落并选择角落距离 P 最远的距离是否可以通过考虑立方体的对称性来减少检查次数?
答案 0 :(得分:4)
将点P
转换为立方体的原理基础,即它在轴向上对齐(调用新点Q
),原点是世界空间中立方体的中心
要查找此框架中的最远点F
:以X轴为例,如果
Q.x > 0
然后F.x = -L
,其中L
是多维数据集的边长Q.x < 0
然后F.x = L
Q.x == 0
(严格abs(Q.x) < EPSILON
),然后是F.x = 0
对其他两个轴也执行步骤2
F
转换回到世界空间。这将在您想要的立方体上给出最远点。 / LI>
醇>
编辑:让我们看看为什么这会更有效率。
原始方法:8 X平方距离计算= 8 X(3次浮点乘法+ 2次加法)
新方法:2次矩阵乘法= 2次X(9次乘法+ 6次加法)
如您所见,新方法使用较少的乘法和加法。
答案 1 :(得分:2)
将随机点的坐标转换为与立方体对齐的局部坐标系。这需要9次乘法和9次加法。
如果本地系统以立方体为中心,则三个符号测试将告诉您最远的角落。
通过 locus 方法可以很好地理解这个问题。
如果考虑随机点的所有位置导致相同的答案(即相同的角指数;这是顶点的最远Voronoi图),则在由立方体的三个二等分平面定义的八个八分圆中划分空间。在八个区域中说明一点需要三次二进制测试(Lg(8)
)。有问题的测试告诉了这个点位于哪一侧,这需要评估仿射表达式aX+bY+cZ+d
。
在&#34;代数决策树&#34;模型,这可能是最佳的。
<强>更新强>:
由于只有标志很重要,你可以对系数进行标准化,使其中一个系数为单位,并且备用乘法(aX+bY+cZ+d>0 -> X+b'Y+c'Z+d>0'
)。您还可以交换添加项以进行比较(X+bY+cZ+d>0 -> X+bY+cZ>d'
)。因此,共有6次乘法,6次加法和3次比较。
[对于数值稳定性,应除以最大系数。不幸的是,这导致表达式依赖于它。这可以通过编写二十七个(!)索引计算函数(见下文)并通过指针调用正确的函数来规避。]
假设系数已经预先计算,下面的表达式给出了角落索引,范围为[0,7]
:
(X + b*Y + c*Z > d) + ((X + b'*Y + c'*Z > d') << 1) + ((X + b"*Y + c"*Z > d") << 2)
幸运的是,编译器可以通过条件赋值以无分支方式计算它,需要15个触发器和5个操作。
答案 2 :(得分:0)
最远的角落满足|xc-xp|
或|yc-yp|
或|zc-zp|
的至少一个“delta”最大值。
测试每个“delta”,存储“候选人”。如果一个角的delta大于或等于另一个候选者的相同delta,则该角是“候选者”。
如果先前的候选人在其“最大条件”中被击败,则将其从候选人名单中删除。例如,如果角落4成为候选者,因为其delta-y是最大值,但现在角落6具有更大的delta-y(其他增量不是角落4的原因),则角落4不再是候选者。
第一个测试角有三个最大值,因此需要击败三次(在x,y和z上)才能离开候选列表。
请注意,成为候选人的考试是d1>=d2
而不只是d1>d2
现在只为候选人测试距离(平方距离足够)。
请注意,如果所有角落位于立方体的中心,则它们距离点的距离可以相同。解决方案不仅可以是一个角落,而且可以是两个,四个或八个。
答案 3 :(得分:0)
@spug触发了我的认识,我已经拥有了我需要的大部分代码。
我以前开发过一种解决立方体上最近点(不一定是角落)的最佳方法。该代码只需要进行少量修改即可返回多维数据集中最近的角落。从逻辑上讲,立方体上最远的点是最近角落的对角。
原理是将点投影到三个主轴上并测试投影沿每个轴的距离。如果它大于一半,则将该轴的索引设置为false,否则将其设置为true。在为三个轴执行此操作后,您可以使用三个布尔变量来选择角点。
在分析超过1000万个随机点后,可以获得以下数据。
朴素线性搜索算法 - 643ms 快速算法 - 481ms
我最终使用的C#代码是
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 FurthestPointFromFast(Vector3 q)
{
//BasisVectors( TransformMatrix, out var vx, out var vy, out var vz );
var origin = BoxCorners.V000;
// Get the pre-calculated principle
// axes of the box with origin at V000
Vector3 vx = BoxCorners.Px;
Vector3 vy = BoxCorners.Py;
Vector3 vz = BoxCorners.Pz;
// Get the pre-calculated prinicple
// axes lengths squared of the box at V000
double lx = BoxCorners.Lx2;
double ly = BoxCorners.Ly2;
double lz = BoxCorners.Lz2;
var d = q - origin;
double tx = Vector3.Dot( d, vx );
double ty = Vector3.Dot( d, vy );
double tz = Vector3.Dot( d, vz );
bool ix = tx < lx / 2;
bool iy = ty < ly / 2;
bool iz = tz < lz / 2;
return ix
? (iy
? (iz
? BoxCorners.V111
: BoxCorners.V110)
: (iz
? BoxCorners.V101
: BoxCorners.V100))
: (iy
? (iz
? BoxCorners.V011
: BoxCorners.V010)
: (iz
? BoxCorners.V001
: BoxCorners.V000));
}
其中BoxCorners的实例来自以下类。假设一个盒子相对于对它进行的检查的数量是相对静态的,因此计算出的值(例如盒子的边长)与每个角的坐标一起存储。
public class BoxCorners
{
public Vector3 V111;
public Vector3 V110;
public Vector3 V101;
public Vector3 V100;
public Vector3 V011;
public Vector3 V010;
public Vector3 V001;
public Vector3 V000;
// These are the vectors starting at the box origin (V000)
// They are precalculated and usefull in other algorithms
#region Principle Axis
public Vector3 Origin;
public Vector3 Px;
public Vector3 Py;
public Vector3 Pz;
/// <summary>
/// Px length squared
/// </summary>
public double Lx2;
/// <summary>
/// Py length squared
/// </summary>
public double Ly2;
/// <summary>
/// Pz length squared
/// </summary>
public double Lz2;
#endregion
public BoxCorners(Vector3 v000, Vector3 v001, Vector3 v010, Vector3 v011, Vector3 v100, Vector3 v101, Vector3 v110, Vector3 v111)
{
V000 = v000;
V001 = v001;
V010 = v010;
V011 = v011;
V100 = v100;
V101 = v101;
V110 = v110;
V111 = v111;
Origin = V000;
Px = (V100 - Origin);
Py = (V010 - Origin);
Pz = (V001 - Origin);
Lx2 = Px.LengthSquared();
Ly2 = Py.LengthSquared();
Lz2 = Py.LengthSquared();
}
}
原始的朴素算法在
之下 [MethodImpl(MethodImplOptions.AggressiveInlining)]
void Acc(ref Vector3 v, ref Vector3 q, ref double max, ref Vector3 maxV)
{
var m = Vector3.DistanceSquared(v, q);
if (!(m > max))
return;
max = m;
maxV = v;
}
/// <summary>
/// Return the furthest point on the box from the point
/// </summary>
/// <param name="q"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 FurthestPointFrom(Vector3 q)
{
var max = 0.0;
var bc = BoxCorners;
var r = Vector3.Zero;
Acc(ref bc.V111, ref q, ref max, ref r);
Acc(ref bc.V110, ref q, ref max, ref r);
Acc(ref bc.V101, ref q, ref max, ref r);
Acc(ref bc.V100, ref q, ref max, ref r);
Acc(ref bc.V011, ref q, ref max, ref r);
Acc(ref bc.V010, ref q, ref max, ref r);
Acc(ref bc.V001, ref q, ref max, ref r);
Acc(ref bc.V000, ref q, ref max, ref r);
return r;
}
double numerics nuget包用于3D矢量图元。