lonlatarr="ADDdJAaB...b8EQAAwX" ...
- Cheetos
- Новичок
- Сообщения: 11
- Зарегистрирован: 30 мар 2015, 20:03
- Откуда: РФ, Тула
- Благодарил (а): 2 раза
В продолжение данной темы...
Несмотря на обильное наличие ответов, вопрос так до конца и не решен.
Дано: Координаты точки TDoublePoint
Необходимо: Получить строку типа string, соответствующую значению lonlatarr в Marks.sml
Решение совсем близко: например, надо "APh9sCqGnJgEQAAYK/XdS4XUBEA4+BIA", имею "APB9sCqGnJgEQAAYK/XdS4XUBEA=".
Пишу на Delphi, любитель. Решив данную задачу обязуюсь выложить ответ здесь на форуме.
Для решения требуются ответы на следующие вопросы:
1. Как и/или где определен тип TExtendedPoint?
2. Какие функции/процедуры используются при кодировании Base64? Свои или сторонние? Если свои, то где их найти?
Дано: Координаты точки TDoublePoint
Необходимо: Получить строку типа string, соответствующую значению lonlatarr в Marks.sml
Решение совсем близко: например, надо "APh9sCqGnJgEQAAYK/XdS4XUBEA4+BIA", имею "APB9sCqGnJgEQAAYK/XdS4XUBEA=".
Пишу на Delphi, любитель. Решив данную задачу обязуюсь выложить ответ здесь на форуме.
Для решения требуются ответы на следующие вопросы:
1. Как и/или где определен тип TExtendedPoint?
2. Какие функции/процедуры используются при кодировании Base64? Свои или сторонние? Если свои, то где их найти?
-
zed
- Гуру
- Сообщения: 2888
- Зарегистрирован: 16 авг 2008, 20:21
- Благодарил (а): 89 раз
- Поблагодарили: 568 раз
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
Уже по-моему всё давно разложено по полочкам и вопросов быть не должно.Cheetos писал(а):Несмотря на обильное наличие ответов, вопрос так до конца и не решен.
1. В юните src\MarksDB\SML\t_GeometryPointSML.pasCheetos писал(а):1. Как и/или где определен тип TExtendedPoint?
2. Какие функции/процедуры используются при кодировании Base64? Свои или сторонние? Если свои, то где их найти?
2. Стандартный base64, например, можете взять отсюда Includes\EDBase64.pas
- Cheetos
- Новичок
- Сообщения: 11
- Зарегистрирован: 30 мар 2015, 20:03
- Откуда: РФ, Тула
- Благодарил (а): 2 раза
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
1. Создаю новый файл.
2. Кидаю на форму Button1 и Memo1.
3. Подключаю в uses EDBase64.
4. Описываю следующие типы:
5. Создаю процедуру преобразования координат в строку lonlatarr:
6. В Button1 прописываю:
7. В итоге:
Должно быть:
AMDOiYxwf5YEQABQ1XmjuP/eBEA4+BIA
Получилось:
AMjOiYxwf5YEQABQ1XmjuP/eBEAAYx4C
Очень похоже, но не то. Где собака зарыта?
2. Кидаю на форму Button1 и Memo1.
3. Подключаю в uses EDBase64.
4. Описываю следующие типы:
Код: Выделить всё
type
TGeometryPointSML = packed record
X: Extended;
Y: Extended;
Reserved: LongWord; // proper record aligment for backward compatibility
end;
PGeometryPointSML = ^TGeometryPointSML;
type
TDoublePoint = record
X: Double;
Y: Double;
end;
Код: Выделить всё
procedure TForm1.Decode64( const DblPoint: TDoublePoint);
var
AStream: TMemoryStream;
VPoint: TGeometryPointSML;
S: AnsiString;
begin
try
AStream:=TMemoryStream.Create;
VPoint.X := DblPoint.X;
VPoint.Y := DblPoint.Y;
AStream.Write(VPoint, SizeOf(VPoint));
AStream.Position:=0;
SetString(S, PAnsiChar(AStream.Memory), AStream.Size);
Memo1.Lines.Add(Base64Encode(S));
Memo1.Lines.Add('AMDOiYxwf5YEQABQ1XmjuP/eBEA4+BIA');
finally
AStream.Free;
end;
end;Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
DP: TDoublePoint;
begin
DP.X:=37.62445277777778;
DP.Y:=55.74972777777778;
Decode64(DP);
end;Должно быть:
AMDOiYxwf5YEQABQ1XmjuP/eBEA4+BIA
Получилось:
AMjOiYxwf5YEQABQ1XmjuP/eBEAAYx4C
Очень похоже, но не то. Где собака зарыта?
-
zed
- Гуру
- Сообщения: 2888
- Зарегистрирован: 16 авг 2008, 20:21
- Благодарил (а): 89 раз
- Поблагодарили: 568 раз
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
А с чего вы решили, что у координат именно столько знаков после запятой? По-моему, тут проблема с точностью округления.
- vdemidov
- Гуру
- Сообщения: 1687
- Зарегистрирован: 12 дек 2008, 13:10
- Откуда: Киев
- Благодарил (а): 191 раз
- Поблагодарили: 157 раз
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
А еще не забываем о 4-х байтах мусора, которые появляются из-за неупакованности структуры.
Чтобы понять программу, вы должны стать одновременно и машиной, и программой.
- Cheetos
- Новичок
- Сообщения: 11
- Зарегистрирован: 30 мар 2015, 20:03
- Откуда: РФ, Тула
- Благодарил (а): 2 раза
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
1. Координаты взяты из файла marks.sml (для точки lonL=LonR, latT=LatB)zed писал(а):А с чего вы решили, что у координат именно столько знаков после запятой? По-моему, тут проблема с точностью округления.
2. Если бы была проблема с округлением, то в результате я бы получил точку с координатами отличными от заданной, но близкую к ней.
- Cheetos
- Новичок
- Сообщения: 11
- Зарегистрирован: 30 мар 2015, 20:03
- Откуда: РФ, Тула
- Благодарил (а): 2 раза
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
1. Про какую неупакованную структуру идет речь?vdemidov писал(а):А еще не забываем о 4-х байтах мусора, которые появляются из-за неупакованности структуры.
2. Sas.Планета как-то умудряется прочитать эти данные
-
zed
- Гуру
- Сообщения: 2888
- Зарегистрирован: 16 авг 2008, 20:21
- Благодарил (а): 89 раз
- Поблагодарили: 568 раз
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
Там текстовое округлённое представление, а в lonlatarr лежит сырая бинарь. Вы уж если хотите сравнить, то создавайте в SAS тестовую точку вручную, т.е. координаты вводите сами, с клавиатуры, а затем эти же координаты из строки преобразуйте в Double и сравнивайте с тем, что вышло в sml.Cheetos писал(а):Координаты взяты из файла marks.sml (для точки lonL=LonR, latT=LatB)
Вы забыли проинициализировать поле VPoint.Reserved и там мусор. Точно так же и SAS его не инициализирует, так что хвост и не сойдётся.Cheetos писал(а):Про какую неупакованную структуру идет речь?
Плюс, не забывайте про директиву {$A4}, а то Delphi XE, по-умолчанию уже выравнивает по 8 байт, а не по 4 как D2007.
P.S. Коль вы юзаете Delphi, то мне вообще не понятны ваши движения - почему не взять DataSet и работать с sml так же как и SAS, без ненужной ручной мороки с парсингом и кодированием.
-
Banzay
- Новичок
- Сообщения: 2
- Зарегистрирован: 02 апр 2015, 00:21
- Откуда: РФ, Саратов
- Благодарил (а): 1 раз
- Контактная информация:
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
Так получилось, что по работе потребовалось формировать sml-файлы из большой базы с координатами. Но, в силу специфики предприятия, средств для разработки серьезного ПО нет, а если и удастся разработать ПО на стороне, то по работе использовать его не будет возможности из-за политик безопасности. Для реализации задачи использовал "костыль" - VBA, встроенный в MS Excel.RGF писал(а):гуру, приведите пожалуйста если не алгоритм, то хотя бы кусок кода, в котором происходит кодирование из широты/долготы в lonlatarr
Т.к. в самом VBA не имеется встроенного типа данных с плавающей точкой, аналога Extended, пришлось изобретать его... но прежде, пришлось постигнуть теорию представления чисел с плавающей точкой в машинном коде, которую напрочь забыл с институтской скамьи.
Результатом стал алгоритм, который описывает подробное преобразование из переменной типа Double, в код lonlatarr, который может стать интересным, осваивающим этот алгоритм с нуля. Естественно, никаких претензий на оптимальность алгоритма нет, над этим буду работать в перспективе, поэтому прошу меня не критиковать за
Итак, алгоритм состоит из нескольких этапов:
- 1. Разложение числа с плавающей точкой в массив 80-байт, каждый байт которого является битом в бинарном представлении числа с плавающей точкой формата Extended;
2. Объединение двух битовых массивов конвертированных координат в один 192-байтовый массив;
3. Преобразование 192-байтового массива в строку lonlatarr
Код: Выделить всё
Option Explicit
Private Sub DblToByteArray(ByVal Dig As Double, ByRef Data() As Byte)
'=========================================================
' Процедура преобразования Double-числа в битовый массив
'=========================================================
Const CNT = 80
Dim tDATA(1 To CNT) As Byte
Dim D As Double
Dim i As Long
Dim j As Long
Dim A As Long
Dim Bt As Byte
Dim B As Double
Dim S As String
Dim Exp As Long
'===== Проверка знака числа =====
If Dig < 0 Then
Data(1) = 1
D = Abs(Dig)
Else
D = Dig
End If
'===== Проверка размерности числа =====
If D > 1 Then
'== Представление числа |X| > 1 ==
'== Разложение на биты целой части числа ==
A = Fix(D)
i = 1
Do While A > 1
tDATA(i) = A Mod 2
A = A \ 2
i = i + 1
Loop
tDATA(i) = 1
For j = 1 To i
Data(17 + i - j) = tDATA(j)
Next j
'== Вычисление значения экспоненты и разложение его на биты ==
Exp = 16384 + i - 2
i = 17 + i
j = 16
Do While Exp > 1 And j > 1
Data(j) = Exp Mod 2
Exp = Exp \ 2
j = j - 1
Loop
Data(j) = 1
'== Разложение на биты дробной части числа ==
A = Round((D - Fix(D)) * 1000000, 0)
Do While i <= 80
A = A * 2
If A > 1000000 Then
Data(i) = 1
A = Fix(A - 1000000)
Else
Data(i) = 0
End If
i = i + 1
Loop
ElseIf Dig <= 0.000001 Then
'== Представление числа |X|=0 (условно |X| <= 0.000001 )==
For i = 1 To 80
Data(i) = 0
Next i
Else
'== Представление числа 0<|X|<1 ==
'== Вычисление значения экспоненты и разложение его на биты ==
'== Вычисление смещения ==
A = Round((D - Fix(D)) * 1000000, 0)
j = 1
Do While A < 1000000
A = A * 2
j = j + 1
Loop
Data(17) = 1
A = Fix(A - 1000000)
'=========================
Exp = 16384 - (j + 1)
j = 16
Do While Exp > 1 And j > 1
Data(j) = Exp Mod 2
Exp = Exp \ 2
j = j - 1
Loop
Data(j) = 1
'== Разложение на биты дробной части числа ==
i = 18
Do While i <= 80
A = A * 2
If A > 1000000 Then
Data(i) = 1
A = Fix(A - 1000000)
Else
Data(i) = 0
End If
i = i + 1
Loop
End If
'== инверсия байтов ==
For i = 0 To 4
For j = 1 To 8
tDATA(j) = Data(i * 8 + j)
Next j
For j = 1 To 8
Data(i * 8 + j) = Data(79 - (i + 1) * 8 + j)
Next j
For j = 1 To 8
Data(80 - (i + 1) * 8 + j) = tDATA(j)
Next j
Next i
End Sub
Private Function ByteArrToBase64(ByRef XCoord() As Byte, ByRef YCoord() As Byte) As String
'============================================================
' Формирование строки lonlatarr из битовых массивов
'============================================================
Dim BinDATA(1 To 192) As Byte
Dim tB64()
Dim i As Long
Dim j As Long
Dim B64 As String
Dim A As Byte
tB64 = Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", _
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", _
"j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", _
"2", "3", "4", "5", "6", "7", "8", "9", "+", "/")
i = 1
'==== Составление единого массива 192 бит ====
For j = 1 To 80
BinDATA(i) = XCoord(j)
i = i + 1
Next j
For j = 1 To 80
BinDATA(i) = YCoord(j)
i = i + 1
Next j
'=============================================
'==== формирование строки lonlatarr ====
For i = 1 To 192 Step 6
A = 32 * BinDATA(i) + 16 * BinDATA(i + 1) + 8 * BinDATA(i + 2) + 4 * BinDATA(i + 3) + 2 * BinDATA(i + 4) + 1 * BinDATA(i + 5)
B64 = B64 & tB64(A)
Next i
'=======================================
ByteArrToBase64 = B64
End Function
Private Function CoordToBase64(ByVal XCoord As Double, ByVal YCoord As Double) As String
'============================================================
' Формирование кода lonlatarr из двух переменных типа Double
'============================================================
Dim X(1 To 80) As Byte
Dim Y(1 To 80) As Byte
DblToByteArray XCoord, X()
DblToByteArray YCoord, Y()
CoordToBase64 = ByteArrToBase64(X(), Y())
End Function
Private Sub CommandButton2_Click()
With Worksheets(1)
.Cells(2, 3).NumberFormat = "@"
.Cells(2, 3) = CoordToBase64(.Cells(2, 1), .Cells(2, 2))
End With
End Sub
Единственное, что для меня осталось загадкой по итогам реализации алгоритма, так это то, почему для формирования lonlatarr используется 24 байта данных (4 из которых - мусор), а не 21 (1 байт - мусор), ведь 21 байт дают устойчивое представление в виде BASE64 кода, с меньшим количеством символов.
P.S. В ходе изучения теории преобразования чисел с плавающей точкой, пришел к выводу, что преобразовать из других типов в аналог Extended будет весьма затруднительным в силу того, что у Extended "1" до точки явная, в то время как у других типов она не явная и в битовое представление записывается лишь код дробной части нормализованного числа в бинарном представлении, плюс, характеристика у Extended составляет 15 бит, что значительно больше других типов. Озвученное не дает возможности использовать простое копирование байтов из памяти, например, средствами CopyMemory (что по-началу было опробовано) и добавлением в "хвост" нулевых байтов.
- Вложения
-
- ConvertToBase64.zip
- Алгоритм конвертации кода lonlatarr в битовый массив средствами MS Excel + макрос по конвертации двух координат в код lonlatarr
- (41.22 КБ) 389 скачиваний
Последний раз редактировалось Banzay 03 апр 2015, 23:53, всего редактировалось 4 раза.
-
zed
- Гуру
- Сообщения: 2888
- Зарегистрирован: 16 авг 2008, 20:21
- Благодарил (а): 89 раз
- Поблагодарили: 568 раз
Re: lonlatarr="ADDdJAaB...b8EQAAwX" ...
Это было очень неудачное решение на заре развития программы. Писать её начинали студенты-программисты, поэтому вот такое наследие: и мусорные 4 байта и монструозный Extended.Banzay писал(а):почему для формирования lonlatarr используется 24 байта данных (4 из которых - мусор)