Как распаковать данные многоточечной геометрии MySQL в PHP? - PullRequest
0 голосов
/ 10 октября 2018

Хорошо, я думаю, что я близок к этому, но у меня есть ограничение в моем понимании двоичных данных.

Я анализирую некоторые данные MySQL, вставленные как геометрические типы, используя PHP unpack() как мой синтаксический анализатор, и все шло гладко, пока я не начал пытаться распаковывать сложные типы геометрии (например, MULTIPOINT).

Для типа данных POINT у меня был хороший успех при использовании шаблона распаковкиэто просто игнорирует первый блок, а затем дает мне ассоциативный массив type, order, lat и lon:

$coords = unpack('x/x/x/x/corder/Ltype/dlat/dlon', $point);
// >>> [
//       'order' => 1,
//       'type' => 1,
//       'lat' => (expected value),
//       'lon' => (expected value)
//     ];

Естественно, применяя точно такой же шаблон к MULTIPOINTгеометрия не работает одинаково.Он получает order, а type становится 4, но значения lat и lon совсем не такие, как я ожидал.Итак, любопытно посмотреть, как все это выглядело, я изменил шаблон, чтобы просто изобразить все это как «двойные (размер и представление, зависящие от машины)»:

$coords = unpack('x/x/x/x/corder/Ltype/d*', $multipoint);
// >>> mayhem

Что включает в себя распаковка пять дополнительных элементов массива вместо 4, которые я ожидал бы для многоточечной с двумя точками (2x2), и значения были совершенно ненормальными.Например, значение, которое я ожидаю, должно быть где-то в диапазоне 40 с чем-то - независимо от того, что, кажется, читается что-то вроде -1.0977282851114052e-218.

Как правильно распаковать MULTIPOINT? Мой инстинкт говорит, что я нарезаю байты там, где я не должен или приводю их к неподходящему типу, но я не уверен, какими они должны быть.

1 Ответ

0 голосов
/ 10 октября 2018

Немного посмотрел, но я нашел ссылку на форматы WKB различной геометрии.Как я и догадался, посмотрев на вывод

SELECT HEX(ST_GeomFromText('MULTIPOINT(1 1, 2 2, 3 3)'))

, есть количество точек после заказа и типа.Проблема заключается в том, что порядок и тип повторно объявляются для каждой точки , а unpack не имеет концепции повторения группы байтов.Поэтому вам нужно вытянуть байты для каждой точки и снова запустить unpack для них.Очевидно, что это станет более активным, когда вы попытаетесь учесть больше пространственных типов.

<?php
$multipoint_wkb = hex2bin("000000000104000000030000000101000000000000000000F03F000000000000F03F010100000000000000000000400000000000000040010100000000000000000008400000000000000840");

function unpack_multipoint($multipoint)
{
    $data = unpack("x4/corder/Ltype/Lcount", $multipoint);
    for ($i = 0; $i < $data["count"]; $i++) {
        // the header is 1+4+8 bytes and each point record is 1+4+8+8 bytes
        $offset = ($i * 21) + 13;
        $return[] = unpack("corder/Ltype/dlat/dlon", $multipoint, $offset);
    }
    return $return;
}

print_r(unpack_multipoint($multipoint_wkb));

Стоит отметить, что эти 4 NUL-байта вставляются MySQL, но не являются частью реального геометрического объекта.,Я оставил их на месте для вашего вопроса, но если вы извлекаете данные с помощью функции ST_AsWKB:

SELECT HEX(ST_AsWKB(ST_GeomFromText('MULTIPOINT(1 1, 2 2, 3 3)')))

, дополнительные байты не добавляются.

...