hypership / geo
管理3D坐标以在星系中导航
Requires (Dev)
- phpunit/phpunit: ~9.5
README
介绍
此库提供在3D系统中表示和操作地理对象的功能。
它最初是为了表示星系中的多个天体而构建的。
它需要PHP 8.1来使用枚举。
表示坐标的类
这些类允许在不同的3D坐标系中表示一个点。
每个类都允许转换到其他坐标系。
Point3D
表示一个3D点,由(x, y, z)笛卡尔坐标标识。
PointSpherical
表示一个3D点,由(r, θ, φ)球坐标标识,如物理学中使用的,遵循ISO 80000-2:2019约定
- r表示径向距离
- θ表示倾角
- φ表示方位角
此类可以使用θ代替倾角表示高度,但在将其转换为圆柱或笛卡尔坐标之前,需要将θ切换回倾角
$point->theta += M_PI_2 $cylindricalPoint = $point->toCylindrical()
PointPolarZ
表示一个3D点,由(ρ, φ, z)圆柱坐标标识
- (ρ, φ)表示类似于2D的极坐标
- ρ表示径向距离
- φ表示方位角
- z表示高度或轴向坐标
此表示法遵循ISO 31-11:1992标准。
表示坐标的替代方案
Octocube
将3D坐标映射到一个立方体,分为8个部分。
每个部分称为扇区,编号为1到8
_____ _______
/ 5 / 6 / |
/- - -/- - -/ |
/_____/____ / | |
| | | |/|
| 7 | 8 | / | 2
|_____|_____|/| |
| | | |/
| 3 | 4 | /
|_____|_____|/
点(0, 0, 0)位于立方体中心。
*使用八面体来表示八分体
正如二维平面可以划分为象限一样,三维空间可以划分为八分体。请参阅https://en.wikipedia.org/wiki/Octant_(solid_geometry)。
要获取八分体的符号列表,而不是其编号,可以使用方法getBaseVector
。
获取离中心更远的点
如果您有一个点P,并想获取另一个点,该点保证会离中心更远,并且永远不会达到另一个八分体(即该点将属于同一个八分体),则可以使用
$point = new Point3D(-7, 4, -5);
$sector = Octocube::getSectorFromPoint3D($point);
echo "Point belongs to sector C", $sector;
$vector = Octocube::getBaseVector($sector);
$point->translate(...$vector);
echo $point;
此代码将输出
Point belongs to sector C1
xyz: [-8.00, 5.00, -6.00]
此技术在地图构建器中已过测试,在需要无限期增加构建内容的情况下。
辅助类
数学
方法
- equals(a, b, Ɛ):使用公式
|a - b| < Ɛ
比较两个浮点数a
和b
。 - normalizeAngle(a):将角度
a
归一化到[0, 2π[区间。 - normalizeAngle(a, λ):将角度
a
归一化到[λ, λ + 2π[区间。
常量
- M_EPSILON:Ɛ的默认值。
陷阱
不要使用==或===运算符比较浮点数
在比较两个浮点数时,我们的库会注意使用|a - b| < Ɛ
,并提供一个Math::equals
方法。
在您的代码中,您也需要这样做。例如,您想避免这种场景
$point = new PointSpherical(...); // Some transformations for $point if ($point->phi === 0.0) { // No inclination }
您可以使用if (Math::equals($point->phi, 0.0)) {}
。
三角学和浮点数会产生很大的误差范围
需要非常小心的一种情况是涉及大量的三角学运算。在我们的库中有一个地方特别会发生这种情况:PointSpherical::distance多次将r.r'与余弦和正弦相乘。您的点越远,您乘以的舍入误差就越多,包括由浮点数和cos/sin函数引入的。
此类代码的示例
$point_a = new PointSpherical(116.645456, 2.131662, 1.893856); $point_b = new PointSpherical(113.703512, 2.165501, -0.726525); $distance = $point_a->distance($point_b);
此距离有一个10^-5的误差范围。
如果您需要计算距离,使用Point3D可以获得更高的精度。PointPolarZ的距离方法也相当精确。