php - 如何找到邻近梅登黑德网格的定位器代码?

标签 php algorithm gps

我正在尝试创建带有围绕单个 Maidenhead grid 的图 block 的 map ,但是我不知道如何计算单个 maidenhead 网格周围的 9 个网格。

例如,我有一个定位器 JO22OI60KE,我根据给定的坐标计算它,并且我想要此网格周围的其他(示例中为绿色)九个定位器。

Maidenhead grid

我环顾四周,但我看到的实现都集中在从单个纬度和经度中获取梅登黑德。 a extended "square"内我可以计算它的邻居,但一旦你处于边缘(也就是说,触摸一个新的子方 block ),它就超出了我的能力。

最佳答案

Cliff 的注释:https://en.wikipedia.org/wiki/Maidenhead_Locator_System

  • MLS 坐标中的每对字符都是网格中的一个单元格,后续的每个网格都包含在前一个网格内。
  • 每对交替使用字母和数字基数:18、10、24、GOTO 10,以达到您想要的精度。
  • 虽然规范案例很重要,但事实并非如此。

所以我们可以将 JO22OI60KE 分解为 (J,O), (2,2), (O,I), (6,0), (K,E) 再到 (10,15), (2,2), (15,9), (6,0), (11,5)

我在 the lib I wrote [包含在下面]中采用的方法是将坐标分解为数字对,然后应用从最不重要到最重要的任何转换(由一组偏移量表示),同时保留“进位”对.

但是,将所有内容乘以 259,200 x 259,200 [ 18*10*12*10*12 ] 网格,进行简单的数学转换,然后使用更多数学将其重新格式化回 MLS 坐标可能会更简单。这也将大大简化纬度/经度之间的转换,因为这只是更简单的数学运算。

生活和学习。某件事的第一次迭代通常只擅长教你应该如何做它。 ́\_(ツ)_/́

代码:

包含在内是因为链接可能会失效,从而导致答案毫无用处。请检查 the repo 是否有 PR/变更。也列在 Packagist 上,

class Coordinate {
    const ENC_FIELD        = 0;
    const ENC_SQUARE       = 1;
    const ENC_SUBSQUARE    = 2;

    const ENC_MAX = [
        self::ENC_FIELD => 18,
        self::ENC_SQUARE => 10,
        self::ENC_SUBSQUARE => 24
    ];

    const ENC_CHARS = [
        self::ENC_FIELD => 'abcdefghijklmonpqr',
        self::ENC_SQUARE => '0123456789',
        self::ENC_SUBSQUARE => 'abcdefghijklmonpqrstuvwx'
    ];

    // The spec only covers the first 4 pairs, the 4th pair "extended subsquare" uses the same encoding as "square"
    // Non-standard extensions of the spec are to be implemented as extensions of this class.
    protected static $encode_order = [ self::ENC_FIELD, self::ENC_SQUARE, self::ENC_SUBSQUARE, self::ENC_SQUARE ];

    protected $pairs = [];
    protected $precision;

    public function __construct($pairs) {
        foreach($pairs as $pair) {
            $this->addPair($pair);
        }
        $this->precision = count($pairs);
    }

    public function transform($offsets) {
        $offset_count = count($offsets);
        $pair_count = $this->precision;
        $encoding_count = count(static::$encode_order);

        if( $offset_count > $pair_count ) {
            throw new \Exception('Number of offsets greater than the number of coordinate pairs');
        }

        $carry = [0, 0];
        $new_pairs = [];

        // process the smallest offset first so that we don't have to specify a full array all the time
        // and also so that carries can be efficiently handled
        for( $o=1,$c=$pair_count; $o<=$c; $o++ ) {
            $offset_index = $offset_count - $o;
            $pair_index   = $this->precision - $o;

            $cur_pair = $this->pairs[$pair_index];
            if( $offset_index < 0 ) {
                $cur_offset = $carry;
            } else {
                $cur_offset = $offsets[$offset_index];

                // apply carry
                $cur_offset = [
                    $cur_offset[0] + $carry[0],
                    $cur_offset[1] + $carry[1]
                ];
            }

            $new_lat = $this->rollover($cur_pair->lat + $cur_offset[0], static::ENC_MAX[static::$encode_order[$pair_index]]);
            $new_lng = $this->rollover($cur_pair->lng + $cur_offset[1], static::ENC_MAX[static::$encode_order[$pair_index]]);

            $carry = [ $new_lat[1], $new_lng[1] ];
            $new_pair = new Pair( $new_lat[0], $new_lng[0] );
            array_unshift($new_pairs, $new_pair);
        }
        return new static($new_pairs);
    }

    public function toString() {
        $output = '';
        for( $i=0; $i<$this->precision; $i++ ) {
            $output .= $this->encodeAs($this->pairs[$i]->lat, static::$encode_order[$i]);
            $output .= $this->encodeAs($this->pairs[$i]->lng, static::$encode_order[$i]);
        }
        return $output;
    }

    public function __toString() {
        return $this->toString();
    }

    protected function rollover($value, $base) {
        if( $value < 0 ) {
            $result = ($value % $base) ? $base + ($value % $base) : 0;
            $carry = (int)ceil(abs($value) / $base) * -1;
        } else if( $value >= $base ) {
            $result = $value % $base;
            $carry = (int)floor($value / $base);
        } else {
            $result = $value;
            $carry = 0;
        }

        return [ $result, $carry ];
    }

    protected function addPair(Pair $pair) {
        $this->pairs[] = $pair;
    }

    public static function fromString($input, $pad=true) {
        $pairs = [];
        $raw_pairs = array_map('str_split', str_split($input, 2));
        for( $i=0,$c=count($raw_pairs); $i<$c; $i++ ) {
            if( ! isset(static::$encode_order[$i]) ) {
                throw new \Exception("No decoding specified for pair index $i");
            }
            $encoding = static::$encode_order[$i];
            $pairs[] = new Pair(
                self::decodeAs($raw_pairs[$i][0], $encoding),
                self::decodeAs($raw_pairs[$i][1], $encoding)
            );
        }
        if( $pad ) {
            for( $c=count(static::$encode_order); $i<$c; $i++ )
            $pairs[] = new Pair(0,0);
        }
        return new static($pairs);
    }

    public static function decodeAs($str, $encoding) {
        $value = strpos(self::ENC_CHARS[$encoding], strtolower($str));
        if( $value === false ) {
            throw new \Exception("Invalid character $str for encoding $encoding");
        }
        return $value;
    }

    public static function encodeAs($int, $encoding) {
        return self::ENC_CHARS[$encoding][$int];
    }
}

class Pair {
    protected $lat, $lng;

    public function __construct($lat, $lng) {
        $this->lat = $lat;
        $this->lng = $lng;
    }

    public function __get($name) {
        return $this->$name;
    }

    public function __set($name, $value) {
        throw new Exception('Immutable');
    }
}

关于php - 如何找到邻近梅登黑德网格的定位器代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57420945/

相关文章:

algorithm - 存储消息的修订更改

android - 如何在应用程序中使用蓝牙 GPS 模块?

elasticsearch - 在bbox中获取前N个加权GPS点

php - WordPress 如何使用 native mail() 函数发送电子邮件,而该函数本身不起作用?

javascript - 如何将 1 添加到 javaScript 变量?

java - 最小化利润,工作安排与最后期限

c# - 如何改善团队创建逻辑?

ios - MKReverseGeocoder不返回SubAdministrativeArea

javascript - woocommerce:如何从 Woocommerce REST API 中排除某些具有特定标签 ID 的产品

php - 不能通过调用返回函数在 php 中返回 2 个变量?