轮回/普朗克

该包最新版本(v0.1.1)没有提供许可证信息。

一个用于处理任意维度空间中任意精度网格的PHP库。

v0.1.1 2015-08-27 19:52 UTC

This package is auto-updated.

Last update: 2024-09-29 03:52:31 UTC


README

该项目当前针对5.5.X、5.6.X和7.X版本进行单元测试,除非所有测试都通过,否则不接受合并。

安装

要安装,只需使用composer要求包

composer require samsara/planck "~0.1"

或者将其包含在您的composer.json文件中

{
    "require": {
        "samsara/planck": "~0.1"
    }
}

项目命名空间为Samsara\Planck\*。您可以在Packagist上查看项目。

概念

当前概念

网格

本项目中的网格概念是一个扩展AbstractGrid并实现GridInterface的对象。网格具有多个轴,取决于网格旨在表示的空间维度。因此,三维网格将有三条轴。

每个轴都有一个独立定义的范围(最大和最小有效值)。网格本身并不在每个可能的节点上明确且详尽地定义。(对于100x100x100的三维网格,这将是一个包含一百万个元素的数组)。相反,网格为您提供了定义特定位置发生的事情的工具,或者定义在整个区域内发生的事情(使用节点事件)。

网格可以嵌套。您可以将网格对象分配给占据另一个网格中的节点,当您这样做时,子网格表示该特定节点内的细分。这允许您在网格内定义任意精细的位置,因此命名项目为普朗克。

所有位置都有一个地址。格式是

AXIS1.AXIS2.AXISN:AXIS1.AXIS2.AXISN:...

点号(或句点)分隔网格中的不同轴,冒号分隔子网格。这种链中最左侧的地址表示父网格,由于网格可以无限嵌套,地址可以有任意多的子网格部分,用冒号分隔。

这是一个三维网格嵌套三次的地址示例

24.13.76:12.12.10:9.0.20

然而,在同一个网格中,以下地址同样有效

24.13.76

尽管您有一个精确到两个或三个子网格的网格,您不必使用特定的地址。您可以在任何您觉得有用的特定性下查询网格。

节点

网格中的每个地址都可能包含一个子网格。但它还包含一个表示该位置属性的节点对象。节点对象是一个简单的键/值实例,可以用来存储有关该地址的信息。

一个节点本身只存储关于该特定地址的信息,任何子地址都没有相同的信息。为了处理这种情况,我们必须查看节点事件。

节点事件

节点事件表示一个特定地址的键/值实例,它将由所有子地址继承。它的工作方式与节点非常相似,它们都扩展了AbstractNode类。但是,当事件附加到节点时,它将在您直接从网格查询地址属性时自动被考虑,并且它将覆盖该节点上同名属性。

事件及其值无限期继承,这种覆盖行为也继承。

未来概念

运算符

GitHub问题

计划增加的功能之一是添加一种新的对象类型,称为操作符。这些操作符将对网格执行操作。例如,一个计划中的操作符是欧几里得数学操作符,它将能够执行诸如计算表示某种欧几里得空间的网格之间的地址距离等操作。

投影器

GitHub问题

另一个计划中的功能是投影器,它将一维网格投影到低维。这主要用于表示球面或类似性质的东西。计划中的初始投影列表可以在相关的GitHub问题(#8)中找到,包括

  • 墨卡托投影
  • 米勒圆柱投影
  • 莫勒韦德投影

这些投影最初可能是不精确的。

路线图

v1.0.0(2015年9月1日)

v1.1.0(2015年10月2日)

v1.2.0 或 v2.0.0(未来)

  • 路径查找
    • A* 算法
    • 迪杰斯特拉算法
    • 贪婪最佳优先算法

使用方法

可以直接实例化新的网格,或者使用包含的网格工厂来创建。随着项目的成熟,网格工厂将提供更多有用的方法来简化网格定义和实例化,尤其是在定义非欧几里得网格(目前没有明确支持)时。

$subGridPrototype = Samsara\Planck\Factory\GridFactory(
    GridFactory::THREE_DIMENSION,
    [
        'maxVals' => [
            ThreeDimensionGrid:AXIS_ONE   => 10,
            ThreeDimensionGrid:AXIS_TWO   => 10,
            ThreeDimensionGrid:AXIS_THREE => 10
        ]
    ]
);

$grid = Samsara\Planck\Factory\GridFactory(
    GridFactory::THREE_DIMENSION,
    [
        'name' => 'My Game World'
        'subGrid' => $subGridPrototype
    ]
);

一旦有了网格,就可以添加地址,而不必专门分配子网格。如果您这样做,网格将自动使用提供的原型网格创建所有必要的子网格,如果没有定义原型网格,它将克隆父网格。

示例

$grid->addAddress('100.20.20:2.4.3');

// This returns the Grid object which represents this address.
$subGrid = $grid->getLocation('100.20.20:2.4.3');

您还可以开始添加节点。

$node = new Samsara\Planck\Node\Node();
$node->set('traversible', true);

$grid->attachNode($node, '100.20.20:2.4.3');

稍后您可以询问那个地址。

$properties = $grid->getNodeProperties('100.20.20:2.4.3');

echo $properties['traversible']; // true

或者您可以在附加后编辑节点。

$grid->getNode('100.20.20:2.4.3')
    ->set('traversible', false)
    ->set('conditions', 'calm');

扩展

所有网格都必须扩展AbstractGrid并实现GridInterface

namespace MyNamespace;

use Samsara\Planck\Core\AbstractGrid;
use Samsara\Planck\Core\GridInterface;

class FourDimensionGrid extends AbstractGrid implements GridInterface
{
    const AXIS_ONE      = 'x';
    const AXIS_TWO      = 'y';
    const AXIS_THREE    = 'z';
    const AXIS_FOUR     = 'a';

    protected $maxVals = [
        self::AXIS_ONE      => 100,
        self::AXIS_TWO      => 10,
        self::AXIS_THREE    => 10,
        self::AXIS_FOUR     => 50
    ];

    protected $minVals = [
        self::AXIS_ONE      => 0,
        self::AXIS_TWO      => 0,
        self::AXIS_THREE    => 0,
        self::AXIS_FOUR     => -50
    ];

    public function __construct($name, $address = '', GridInterface $protoSubGrid = null, array $maxVals = null, array $minVals = null)
    {
        if (!is_null($maxVals) && count($maxVals)) {
            foreach ($maxVals as $key => $val) {
                switch ($key) {
                    case self::AXIS_ONE:
                    case self::AXIS_TWO:
                    case self::AXIS_THREE:
                    case self::AXIS_FOUR:
                        if (is_numeric($val)) {
                            $this->maxVals[$key] = (int) $val;
                        } else {
                            throw new \Exception('Cannot use non-numeric values for maximum grid values.');
                        }
                        break;

                    default:
                        throw new \Exception('Cannot set maximum values for axis that doesn\'t exist');
                        break;
                }
            }
        }

        if (!is_null($minVals) && count($minVals)) {
            foreach ($minVals as $key => $val) {
                switch ($key) {
                    case self::AXIS_ONE:
                    case self::AXIS_TWO:
                    case self::AXIS_THREE:
                    case self::AXIS_FOUR:
                        if (is_numeric($val)) {
                            $this->maxVals[$key] = (int) $val;
                        } else {
                            throw new \Exception('Cannot use non-numeric values for minimum grid values.');
                        }
                        break;

                    default:
                        throw new \Exception('Cannot set minimum values for axis that doesn\'t exist');
                        break;
                }
            }
        }

        parent::__construct($name, $address, $protoSubGrid);
    }

    protected function isValidAddress($address)
    {
        if (is_string($address)) {
            $parts = explode('.', $address);
            if (count($parts) == 4) {
                foreach ($parts as $key => $val) {
                    if (!is_numeric($val)) {
                        return false;
                    }

                    switch ($key) {
                        case 0:
                            if ($val > $this->maxVals[self::AXIS_ONE] || $val < $this->minVals[self::AXIS_ONE]) {
                                return false;
                            }
                            break;

                        case 1:
                            if ($val > $this->maxVals[self::AXIS_TWO] || $val < $this->minVals[self::AXIS_TWO]) {
                                return false;
                            }
                            break;

                        case 2:
                            if ($val > $this->maxVals[self::AXIS_THREE] || $val < $this->minVals[self::AXIS_THREE]) {
                                return false;
                            }
                            break;

                        case 3:
                            if ($val > $this->maxVals[self::AXIS_FOUR] || $val < $this->minVals[self::AXIS_FOUR]) {
                                return false;
                            }
                            break;
                    }
                }

                return true;
            }
        }

        return false;
    }
}

贡献

请确保拉取请求符合以下指南

  • 在拉取请求中创建的新文件必须有一个相应的单元测试文件,或者必须被现有的测试文件覆盖。
  • 您的合并不得使项目的测试覆盖率低于85%。
  • 您的合并不得使项目的测试覆盖率下降超过5%。
  • 您的合并必须通过Tracis-CI为PHP 5.5.X、5.6.X和PHP 7.X构建测试。

有关更多信息,请参阅贡献部分