【问题标题】:Calculate distance between two points in 3D space with two coordinate layers使用两个坐标层计算 3D 空间中两点之间的距离
【发布时间】:2015-04-19 20:44:34
【问题描述】:

我需要计算 3D 空间中两点之间的距离。我使用的坐标系是 Int64 来获取扇区,并且在每个扇区内 Int32 用于获取本地位置。所以本质上它是一个 Int96 位坐标系。

如果没有大量 if 语句检查边界,我不确定这将如何工作,因此可能有更聪明的方法。

谁能帮忙?

PS! Double 中的精度损失是可以接受的。我不能使用不安全的代码。 BigInteger 不是一个选项,因为代码必须在 Unity 中运行。

样本可以是:

public struct SectorPos
{
    public readonly Int64 X;
    public readonly Int64 Y;
    public readonly Int64 Z;

    public SectorPos(Int64 x, Int64 y, Int64 z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}
public struct LocalPos
{
    public readonly Int32 X;
    public readonly Int32 Y;
    public readonly Int32 Z;

    public LocalPos(Int32 x, Int32 y, Int32 z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

struct Pos
{
    public readonly SectorPos Sector;
    public readonly LocalPos Local;

    public Pos(SectorPos sector, LocalPos local)
    {
        Sector = sector;
        Local = local;
    }
}

void Test()
{
    // Should be 1:
    Double d1 = Distance(new Pos(new SectorPos(0, 0, 0), 
                                 new LocalPos(Int32.MaxValue, 0, 0)), 
                         new Pos(new SectorPos(0, 1, 0), 
                                 new LocalPos(Int32.MinValue, 0, 0)));
    // Should be -1: (EDIT: Should be 1 of course)
    Double d2 = Distance(new Pos(new SectorPos(0, -2, 0), 
                                 new LocalPos(Int32.MaxValue, 0, 0)), 
                         new Pos(new SectorPos(0, -3, 0), 
                                 new LocalPos(Int32.MinValue, 0, 0)));
    // Should be Int32.MaxValue+1:
    Double d3 = Distance(new Pos(new SectorPos(1, 0, 0), 
                                 new LocalPos(Int32.MaxValue, 0, 0)), 
                         new Pos(new SectorPos(3, 0, 0), 
                                 new LocalPos(Int32.MinValue, 0, 0))); 
}

【问题讨论】:

  • 为什么不使用BigInteger而不是将定位划分为扇区和本地?
  • 抱歉忘了说代码也必须在 Unity 上运行(没有 BigInteger)。不使用 BigInteger 的第二个原因是我需要两个位置层,因此将它们作为单独的数字保存在结构中很有用。 IE。大多数(本地)计算仅使用 LocalPos。

标签: c# 3d


【解决方案1】:

我假设Sector X=1, Local X=int.MinValueSector X=0, Local X=int.MaxValue 大致相同。

这意味着1的每个扇区步长的实际大小是int.MaxValue*2

要获得绝对 X 位置,您可以使用secX * int.MaxValue * 2 + locX

通过在double 上执行这些操作来避免溢出(而不是在最后尝试转换为double)。

所以把这个放在一起,你可以试试:

public struct AbsolutePos
{
    private const double SEC_FACTOR = int.MaxValue * 2d;
    public readonly double X;
    public readonly double Y;
    public readonly double Z;

    public AbsolutePos(SectorPos secPos, LocalPos locPos)
    {
        X = secPos.X * SEC_FACTOR + locPos.X;
        Y = secPos.Y * SEC_FACTOR + locPos.Y;
        Z = secPos.Z * SEC_FACTOR + locPos.Z;
    }

    public double Distance(AbsolutePos pos)
    {
        // implement 3d distance calculation normally here
    }
}

struct Pos
{
    ...

    public AbsolutePos GetAbsPos()
    {
        return new AbsolutePos(this.Sector, this.Local);
    }
}

那么你可以把它当作:

var pos1 = new Pos(new SectorPos(0, 0, 0), 
                   new LocalPos(Int32.MaxValue, 0, 0));
var pos2 = new Pos(new SectorPos(0, 1, 0), 
                   new LocalPos(Int32.MinValue, 0, 0));
var distance = pos1.GetAbsolutePos().Distance(pos2.GetAbsolutePos());

您可能希望将最终距离除以SEC_FACTOR,具体取决于您希望如何看待它。

【讨论】:

  • 谢谢。没有这样想。相当低的CPU方式,这很好。这种方法的唯一问题是任何接近 SectorPos 边缘 (Int64.MinValue/Int64.MaxValue) 的计算总是非常不准确,而不是仅在非常远的距离结果上不准确。
  • 为了准确,只需切换到使用decimal 而不是double。两者都可以安全地表示手头的数字范围。我很少使用double
  • 谢谢。我明确地过度考虑了这一点。十进制是 128 位的,可以保存所有 Int64 数字。这样,问题就应该得到解决。 (快速测试显示 Decimal 能够保持 Int64 的上限和下限。)
  • 是的,它也可以容纳Int64的上限* Int32的上限+ Int32的上限然后一些。
猜你喜欢
  • 2020-02-12
  • 1970-01-01
  • 1970-01-01
  • 2015-08-16
  • 1970-01-01
  • 2018-06-12
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
相关资源
最近更新 更多