Хорошо, я думаю, что я близок к этому, но я испытываю ограничение в моем понимании двоичных данных.
Я анализирую некоторые данные 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
Что это на самом деле распаковывает включает 5 дополнительные элементы массива, вместо 4 я бы ожидал для многоточечной с двумя точками (2×2), и значения совершенно ненормальные. Например, значение, которое я ожидаю, должно быть где-то в диапазоне 40 с чем-то — независимо от того, что кажется, что-то вроде -1.0977282851114052e-218
,
Как правильно распаковать MULTIPOINT
? Мой инстинкт говорит, что я нарезаю байты там, где я не должен, или преобразую их в неподходящий тип, но я не уверен, какими они должны быть.
Взглянул немного, но нашел ссылка для форматов 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)')))
дополнительные байты не добавляются.
Других решений пока нет …