我正在尝试创建带有围绕单个 Maidenhead grid 的图 block 的 map ,但是我不知道如何计算单个 maidenhead 网格周围的 9 个网格。
例如,我有一个定位器 JO22OI60KE
,我根据给定的坐标计算它,并且我想要此网格周围的其他(示例中为绿色)九个定位器。
我环顾四周,但我看到的实现都集中在从单个纬度和经度中获取梅登黑德。 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/