SASGIS

Веб-картография и навигация

lonlatarr="ADDdJAaB...b8EQAAwX" ...

Форум для обсуждения деталей разработки программы SAS.Планета

Модераторы: vdemidov, Tolik

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение Banzay » 03 апр 2015, 14:52

zed писал(а):Это было очень неудачное решение на заре развития программы. Писать её начинали студенты-программисты, поэтому вот такое наследие: и мусорные 4 байта и монструозный Extended.

Благодарю за пояснение! Понимаю, что всегда бывают недочеты, приятно, что при их наличии SAS.Планета разрослась в такой полезный и многофункциональный инструмент! Жалко, только, что для реализации различных ярлыков на карте нельзя использовать KMZ-файлы, в силу не полной поддержи их средствами SAS.Планета. Из-за этого пришлось изобретать велосипед, хотя можно было проще реализовывать задачу средствами стороннего ПО. :)
Banzay
Новичок
 
Сообщения: 2
ICQ: 238208421
Зарегистрирован: 02 апр 2015, 00:21
Откуда: РФ, Саратов
Благодарил (а): 1 раз.
Поблагодарили: 0 раз.

Не прошло и года... вроде как удалось победить lonlatarr

Сообщение Cheetos » 03 апр 2015, 19:53

1. В uses добавляем EDBase64
2. Объявляем следующие типы:
Код: Выделить всё
type
  TExtendedPoint = packed record
    X: Extended;
    Y: Extended;
    Reserved: LongWord;
  end;

type
  TDoublePoint = record
    X: Double;
    Y: Double;
  end;

3. Юзаем функцию LonLatArr, где в качестве параметра передаем координаты точки в градусах:
Код: Выделить всё
function LonLatArr(DP: TDoublePoint): String;
var
  AStream: TMemoryStream;
  S: AnsiString;
  ExtPoint: TExtendedPoint;
begin
  try
    AStream:=TMemoryStream.Create;
    ExtPoint.X := DP.X;
    ExtPoint.Y := DP.Y;
    ExtPoint.Reserved:=0;
    AStream.Write(ExtPoint, SizeOf(ExtPoint));
    AStream.Position:=0;
    SetString(S, PAnsiChar(AStream.Memory), AStream.Size);
    Result:=Base64Encode(S);
  finally
    AStream.Free;
  end;
end;
Последний раз редактировалось Cheetos 03 апр 2015, 20:21, всего редактировалось 1 раз.
Аватара пользователя
Cheetos
Новичок
 
Сообщения: 11
Зарегистрирован: 30 мар 2015, 20:03
Откуда: РФ, Тула
Благодарил (а): 2 раз.
Поблагодарили: 0 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение Cheetos » 03 апр 2015, 20:03

to zed:
1. Выражаю огромную благодарность за оказанную помощь.
2. В отношении директивы {$A4} для решения конкретной задачи - она не обязательна - packed record ее игнорирует.
Аватара пользователя
Cheetos
Новичок
 
Сообщения: 11
Зарегистрирован: 30 мар 2015, 20:03
Откуда: РФ, Тула
Благодарил (а): 2 раз.
Поблагодарили: 0 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение Cheetos » 03 апр 2015, 20:17

Banzay писал(а):
zed писал(а):Это было очень неудачное решение на заре развития программы. Писать её начинали студенты-программисты, поэтому вот такое наследие: и мусорные 4 байта и монструозный Extended.

Благодарю за пояснение! Понимаю, что всегда бывают недочеты, приятно, что при их наличии SAS.Планета разрослась в такой полезный и многофункциональный инструмент! Жалко, только, что для реализации различных ярлыков на карте нельзя использовать KMZ-файлы, в силу не полной поддержи их средствами SAS.Планета. Из-за этого пришлось изобретать велосипед, хотя можно было проще реализовывать задачу средствами стороннего ПО. :)

Можно :)
Аватара пользователя
Cheetos
Новичок
 
Сообщения: 11
Зарегистрирован: 30 мар 2015, 20:03
Откуда: РФ, Тула
Благодарил (а): 2 раз.
Поблагодарили: 0 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение zed » 03 апр 2015, 22:28

Banzay писал(а):нельзя использовать KMZ-файлы, в силу не полной поддержи их средствами SAS.Планета

Ну так присылайте пул-реквесты, глядишь и поддержка появится ;)
Cheetos писал(а):3. Юзаем функцию LonLatArr

По-моему, можно проще:
Код: Выделить всё
function LonLatArr(DP: TDoublePoint): String;
var
  ExtPoint: TExtendedPoint;
begin
  ExtPoint.X := DP.X;
  ExtPoint.Y := DP.Y;
  ExtPoint.Reserved := 0;
  Result := Base64Encode(PAnsiChar(@ExtPoint), SizeOf(ExtPoint));
end;

Но это если всего одна точка. А вообще, имейте в виду, что SAS умеет оперировать мультиполигонами и полилиниями (особенно это стоит учитывать при чтении lonlatarr, а то могут быть сюрпризы). Код сериализации геометрии живёт в юните Src/MarksDB/SML/u_GeometryToStreamSML.pas, десериализация: Src/MarksDB/SML/u_GeometryFromStreamSML.pas
zed
Гуру
 
Сообщения: 2888
Зарегистрирован: 16 авг 2008, 20:21
Благодарил (а): 89 раз.
Поблагодарили: 568 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение Cheetos » 03 апр 2015, 23:42

zed писал(а):По-моему, можно проще:
Код: Выделить всё
function LonLatArr(DP: TDoublePoint): String;
var
  ExtPoint: TExtendedPoint;
begin
  ExtPoint.X := DP.X;
  ExtPoint.Y := DP.Y;
  ExtPoint.Reserved := 0;
  Result := Base64Encode(PAnsiChar(@ExtPoint), SizeOf(ExtPoint));
end;

Совершенству нет предела :)

zed писал(а):Но это если всего одна точка. А вообще, имейте в виду, что SAS умеет оперировать мультиполигонами и полилиниями (особенно это стоит учитывать при чтении lonlatarr, а то могут быть сюрпризы).

В рамках поставленной задачи (получение строки LonLatArr из координат точки) этого более чем достаточно
Аватара пользователя
Cheetos
Новичок
 
Сообщения: 11
Зарегистрирован: 30 мар 2015, 20:03
Откуда: РФ, Тула
Благодарил (а): 2 раз.
Поблагодарили: 0 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение OverPaw » 11 окт 2019, 10:35

Cheetos, zed, спасибо за алгоритм, но непосредственно сам ваш код в FreePascal у меня не заработал.
Пришлось немного допилить - взять что-то от каждого и адаптировать к встроенной библиотеке Base64.
Привожу рабочий вариант для FreePascal 3.0.4 с примером конвертации координат.
Код: Выделить всё
uses Base64;

type
  TExtendedPoint = packed record
    X: Extended;
    Y: Extended;
    Reserved: LongWord;
  end;

type
  TDoublePoint = record
    X: Double;
    Y: Double;
  end;

function LonLatArr(DP: TDoublePoint): String;
var
  S: AnsiString;
  ExtPoint: TExtendedPoint;
begin
    ExtPoint.X := DP.X;
    ExtPoint.Y := DP.Y;
    ExtPoint.Reserved:=0;
    SetString(S, PAnsiChar(@ExtPoint), SizeOf(ExtPoint));
    LonLatArr := EncodeStringBase64(S);
end;

var
  lonlat: TDoublePoint;
begin
  lonlat.X := 47.817875;
  lonlat.Y := 52.022758;
  writeln(LonLatArr(lonlat));
  readln();
end.
Аватара пользователя
OverPaw
Новичок
 
Сообщения: 24
Зарегистрирован: 12 янв 2013, 13:14
Откуда: Киев
Благодарил (а): 14 раз.
Поблагодарили: 3 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение stepanxxx » 20 фев 2025, 23:49

Уже несколько дней пытаюсь самостоятельно конвертировать SML в KML на Python для автоматизации одного из процессов. Данные хранятся в SML, и основная загвоздка — в массиве lonlatarr. Изучил тему вдоль и поперек, но пока безуспешно.

Может, кто-то сталкивался с подобным и знает, как корректно извлечь координаты из lonlatarr? Буду благодарен за любые идеи!
stepanxxx
Новичок
 
Сообщения: 15
Зарегистрирован: 19 фев 2014, 11:48
Благодарил (а): 3 раз.
Поблагодарили: 1 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение mate » 21 фев 2025, 11:40

Из python вам будет гораздо проще работать с метками в sqlite3 формате, т.к. там данные хранятся в WKB формате. В python есть готовая либа для него: https://github.com/thehappycheese/parse_wkb

Что касается SML, то в python вам придётся напрячься, для преобразования 80-битного float в нормальный 64-битный double.
mate
Новичок
 
Сообщения: 22
Зарегистрирован: 14 июн 2018, 11:52
Благодарил (а): 0 раз.
Поблагодарили: 8 раз.

Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...

Сообщение mate » 21 фев 2025, 11:52

Хотя, нейронки вот что-то похожее на правду пишут (не проверял). По крайней мере, есть от чего исходить:

Copilot:
Код: Выделить всё
import math

# Пример 80-битного числа (в виде строки байтов)
float80_bytes = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

def convert_80bit_to_double(float80_bytes):
    # Разбор 80-битного числа на составляющие
    sign = (float80_bytes[9] & 0x80) >> 7
    exponent = ((float80_bytes[9] & 0x7F) << 8) | float80_bytes[8]
    mantissa = float80_bytes[:8]  # 64-битная мантисса

    # Преобразование мантиссы в дробное число
    mantissa_value = int.from_bytes(mantissa, byteorder='little') / (2**64)

    # Вычисление 64-битного числа
    value = ((-1) ** sign) * (2 ** (exponent - 16383)) * mantissa_value
    return value

# Преобразование и вывод результата
float64 = convert_80bit_to_double(float80_bytes)
print(float64)


ChatGPT:

Чтобы преобразовать 80-битное представление с плавающей точкой (например, формат `long double` в C) в 64-битное представление (`double`) в Python без использования сторонних библиотек, можно вручную извлечь компоненты числа (знак, экспоненту и мантиссу) из 80-битного формата и затем подогнать их под 64-битный формат. В 64-битном формате мантисса имеет меньше бит, а экспонента должна быть приведена к другому диапазону.

Вот шаги, которые вам нужно выполнить:

1. Прочитайте 80-битное число, представленное в виде 10 байт.
2. Извлеките следующие компоненты:
- Знак (1 бит).
- Экспонента (15 бит).
- Мантисса (64 бита).
3. Преобразуйте эти компоненты в 64-битный формат, изменив экспоненту и мантиссу, чтобы соответствовать стандарту IEEE 754 для 64-битных чисел.
4. Получите итоговое 64-битное число.

Пример кода для конверсии из 80-битного формата в 64-битный:

Код: Выделить всё
def float80_to_double(bytes_80):
    # Проверяем, что вход — это 10 байт (80 бит)
    if len(bytes_80) != 10:
        raise ValueError("Input must be 10 bytes long for 80-bit float")

    # Разбираем 10 байт на компоненты 80-битного числа:
    sign = (bytes_80[9] >> 7) & 0x01  # 1 бит
    exponent = ((bytes_80[9] & 0x7F) << 8) | bytes_80[8]  # 15 бит
    mantissa = (bytes_80[7] << 56) | (bytes_80[6] << 48) | (bytes_80[5] << 40) | \
               (bytes_80[4] << 32) | (bytes_80[3] << 24) | (bytes_80[2] << 16) | \
               (bytes_80[1] << 8) | bytes_80[0]  # 64 бита

    # Смещаем экспоненту для 64-битного формата (например, с 15 бит на 11 бит)
    # Стандарт IEEE 754 для 64-битных чисел: экспонента имеет смещение 1023
    exponent_64 = exponent - 16383 + 1023

    # Обрабатываем выходные данные:
    # Если экспонента выходит за пределы 64-битного диапазона, например, слишком мала или велика
    if exponent_64 <= 0:
        return 0.0  # Нормализованный выходной результат
    if exponent_64 >= 0x7FF:
        return float('inf') if sign == 0 else float('-inf')

    # Преобразуем мантиссу и экспоненту в 64-битный формат
    mantissa_64 = mantissa >> 11  # Оставляем только верхние 52 бита мантиссы
    result = (sign << 63) | (exponent_64 << 52) | mantissa_64

    # Преобразуем в число
    return struct.unpack('d', struct.pack('Q', result))[0]

import struct

# Пример 80-битного числа (10 байт)
bytes_80 = bytearray([0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])

# Преобразуем в 64-битное число
double_value = float80_to_double(bytes_80)
print(double_value)


Этот код:
1. Преобразует 80-битный формат (который представлен 10 байтами) в структуру с плавающей точкой 64-бит.
2. Выполняет преобразование с учетом мантиссы и экспоненты в стандарт IEEE 754.

Пожалуйста, учитывайте, что в реальных приложениях точность может быть потеряна при таком преобразовании, поскольку 64 бита имеют меньшую точность и диапазон, чем 80 бит.
mate
Новичок
 
Сообщения: 22
Зарегистрирован: 14 июн 2018, 11:52
Благодарил (а): 0 раз.
Поблагодарили: 8 раз.

Пред.

Вернуться в Раздел для разработчиков программы SAS.Планета

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1