Php 如何找到相邻Maidenhead栅格的定位码?

Php 如何找到相邻Maidenhead栅格的定位码?,php,algorithm,gps,Php,Algorithm,Gps,我正在尝试创建一个围绕单个贴图的贴图,但是我不知道如何计算围绕单个maidenhead网格的9个网格 例如,我有一个locatorJO22OI60KE,我根据给定的坐标计算它,我希望其他的(示例中的绿色)九个定位器围绕这个网格 我已经环顾了很多地方,但我看到的实现都集中在从一个纬度和经度获得少女头。我可以计算它的邻居,但一旦你在边缘(也就是说,触摸一个新的子正方形),它就超出了我的能力。克里夫的注释: MLS坐标中的每对字符都是网格中的一个单元,每个后续网格都包含在前一个网格中 每一对在字母

我正在尝试创建一个围绕单个贴图的贴图,但是我不知道如何计算围绕单个maidenhead网格的9个网格

例如,我有一个locator
JO22OI60KE
,我根据给定的坐标计算它,我希望其他的(示例中的绿色)九个定位器围绕这个网格


我已经环顾了很多地方,但我看到的实现都集中在从一个纬度和经度获得少女头。我可以计算它的邻居,但一旦你在边缘(也就是说,触摸一个新的子正方形),它就超出了我的能力。

克里夫的注释:

  • 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)

我采用的方法[包括在下面]是将坐标分解为它们的数字对,然后应用任何变换[由一组偏移量表示],从最低有效到最高,同时保留一个“进位”对

但是,将所有内容相乘到
259200 x 259200
[
18*10*12*10*12
]网格,进行简单的数学变换,然后使用更多的数学重新格式化回MLS坐标可能会更简单。这也将大大简化lat/lng的转换,因为这只是更简单的数学

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

代码: 包括,因为链接可能会死亡,这使得答案无效。请检查是否有PRs/更改。也列出在

类坐标{
常量ENC_字段=0;
常数平方=1;
const ENC_SUBSQUARE=2;
常数ENC_MAX=[
self::ENC_字段=>18,
self::ENC_SQUARE=>10,
self::ENC_SUBSQUARE=>24
];
const ENC_CHARS=[
self::ENC_字段=>'abcdefghijklmonpqr',
self::ENC_SQUARE=>“0123456789”,
self::ENC_SUBSQUARE=>“abcdefghijklmonpqrstuvwx”
];
//规范仅涵盖前4对,第4对“扩展子正方形”使用与“正方形”相同的编码
//规范的非标准扩展将作为此类的扩展来实现。
受保护的静态$encode_顺序=[self::ENC_字段,self::ENC_正方形,self::ENC_子正方形,self::ENC_正方形];
受保护的$pairs=[];
受保护的精度;
公共函数构造($pairs){
foreach($pairs作为$pair){
$this->addPair($pair);
}
$this->precision=count($pairs);
}
公共职能转变($offset){
$offset\u count=计数($offset);
$pair\u count=$this->precision;
$encoding\u count=count(静态::$encode\u顺序);
如果($offset\u count>$pair\u count){
抛出新\异常(“偏移数大于坐标对数”);
}
$carry=[0,0];
$new_pairs=[];
//首先处理最小的偏移量,这样我们就不必一直指定完整的数组
//同时也可以有效地处理运载工具
对于($o=1,$c=$pair\u count;$oprecision-$o;
$cur_pair=$this->pairs[$pair_index];
如果($offset_index<0){
$cur_offset=$carry;
}否则{
$cur_offset=$offset[$offset_index];
//套利
$cur_offset=[
$cur_偏移量[0]+$carry[0],
$cur_偏移量[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],静态::ENC_MAX[静态::$encode_order[$pair_index]]);
$carry=[$new_lat[1],$new_lng[1];
$new_pair=新对($new_lat[0],$new_lng[0]);
数组\u取消移位($new\u pairs,$new\u pairs);
}
返回新的静态数据($new_pairs);
}
公共函数toString(){
$output='';
对于($i=0;$i精度;$i++){
$output.=$this->encodeAs($this->pairs[$i]->lat,static::$encode_order[$i]);
$output.=$this->encodeAs($this->pairs[$i]->lng,static::$encode_order[$i]);
}
返回$output;
}
公共函数{
返回$this->toString();
}
受保护的功能滚动($value,$base){
如果($value<0){
$result=($value%$base)?$base+($value%$base):0;
$carry=(int)ceil(资产净值/$base)*-1;
}如果($value>=$base),则为else{
$result=$value%$base;
$carry=(int)地板($value/$base);
}否则{
$result=$value;
$carry=0;
}
返回[$result,$carry];
}
受保护的函数addPair(Pair$Pair){
$this->pairs[]=$pair;
}
公共静态函数fromString($input,$pad=true){
$pairs=[];
$raw_pairs=array_map('str_split',str_split($input,2));
对于($i=0,$c=count($raw_pairs);$ilng=$lng;
}
公共函数获取($name){
返回$this->$name;
}
公共函数集($name,$value){
抛出新异常(“不可变”);
}
}

令人震惊的是,这没有一个内置的。你查过一个参考实现吗?你对哪一部分有问题?我到处找了很多,但他们都关注GET
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');
    }
}