Page 1 of 1
A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 7:24 am
by ZX80
Hello, all.
Original Delphi code:
Code: Select all
type
TGeoidGrid = Array[0..719, 0..1439] of SmallInt;
var
GeoidData: TGeoidGrid;
dH,H,H0: Double;
// Reading the WW15MGH.DAC file
Procedure LoadGeoidFile(const FileName: string);
var
fs: TFileStream;
i, j: Integer;
tmp: SmallInt;
begin
//create a stream To Read the file
fs:= TFileStream.Create('WW15MGH.DAC', fmOpenRead Or fmShareDenyWrite);
try
//go through all the rows (latitude) And columns (longitude)
For i := 0 To 719 do
For j := 0 To 1439 do
begin
//Reading 2 bytes (SmallInt) from the stream
fs.Read(tmp, SizeOf(SmallInt));
//Convert byte order (Big Endian into Little Endian)
tmp:=((tmp And $FF) shl 8) Or ((tmp And $FF00) shr 8);
//save the value into an Array
GeoidData[i,j]:=tmp;
End;
finally
//Release of the stream
fs.Free;
End;
End;
I didn't like ReadWord() here (this is an analogue of TFileStream.) and decided to use
infratec's code.
Code: Select all
EnableExplicit
Define.i File, i, j, result = #False
Define *File, *Ptr.Word, *FileEnd
Define Filename$
Dim GeoidData.w(719, 1439)
;Filename$ = OpenFileRequester("Choose a file", "", "All|*.*", 0)
Filename$ = "c:\WW15MGH.DAC"
If Filename$
File = ReadFile(#PB_Any, Filename$)
If File
*File = AllocateMemory(Lof(File), #PB_Memory_NoClear)
If *File
If ReadData(File, *File, MemorySize(*File)) = MemorySize(*File)
result = #True
EndIf
EndIf
CloseFile(File)
EndIf
EndIf
If result = #True
*Ptr = *File
;Temporary limited. The file size is 2 Mb.
*FileEnd = *File + 1000 ;+ MemorySize(*File) - 1
While *Ptr <= *FileEnd
;Convert byte order (Big Endian into Little Endian)
GeoidData(i, j) = ((*Ptr\w & $FF) << 8) | ((*Ptr\w & $FF00) >> 8)
*Ptr + 2 ; SizeOf(Word) = 2 bytes
i+1 : j+1
Wend
FreeMemory(*File)
EndIf
Can someone verify this ? Particular doubt regarding the Endian transformation. Is this right or not ?
Thank you.
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 10:57 am
by infratec
*FileEnd can only be
Code: Select all
*FileEnd = *File + MemorySize(*File) - 1
+ 1000 results in an InvalidMemoryAccess or at least is outside of the buffer.
And you should use
because it is unsigned.
And your code to assign the values to the array is wrong.
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 11:08 am
by infratec
Code: Select all
EnableExplicit
Define.i File, i, j, result, FileSize
Define *File, *Ptr.Word
Define Filename$
Dim GeoidData.w(719, 1439)
;Filename$ = OpenFileRequester("Choose a file", "", "All|*.*", 0)
Filename$ = "WW15MGH.DAC"
If Filename$
*File = #Null
FileSize = FileSize(Filename$)
If FileSize >= 720 * 1440 * 2 ; 2.073.600
File = ReadFile(#PB_Any, Filename$)
If File
*File = AllocateMemory(FileSize, #PB_Memory_NoClear)
If *File
If ReadData(File, *File, FileSize) = FileSize
result = #True
Else
Debug "Was not able to read complete file"
EndIf
Else
Debug "Was not able to allocate memory"
EndIf
CloseFile(File)
Else
Debug "Was not able to read file"
EndIf
If result = #True
*Ptr = *File
;Temporary limited. The file size is 2 Mb.
For i = 0 To 719
For j = 0 To 1439
;Convert byte order (Big Endian into Little Endian)
GeoidData(i, j) = ((*Ptr\w & $FF) << 8) | ((*Ptr\w & $FF00) >> 8)
*Ptr + 2 ; SizeOf(Word) = 2 bytes
Next j
Next i
EndIf
If *File
FreeMemory(*File)
EndIf
Else
Debug "File too small (not valid): " + Str(FileSize)
EndIf
EndIf
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 11:15 am
by SMaag
GeoidData(i, j) = ((*Ptr\w & $FF) <<

| ((*Ptr\w & $FF00) >>
& $FF and & $FF00 is switchted!
if work with 16Bit values the & $FF .. is not needed
Code: Select all
GeoidData(i, j) = ((*Ptr\w) << 8) | ((*Ptr\w) >> 8)
; or use Macro
Macro BSwap16(_WordValue)
((_WordValue<<8 | _WordValue>>8) & $FFFF)
EndMacro
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 1:18 pm
by breeze4me
SMaag wrote: Sat Feb 07, 2026 11:15 am
GeoidData(i, j) = ((*Ptr\w & $FF) <<

| ((*Ptr\w & $FF00) >>
& $FF and & $FF00 is switchted!
if work with 16Bit values the & $FF .. is not needed
Code: Select all
GeoidData(i, j) = ((*Ptr\w) << 8) | ((*Ptr\w) >> 8)
; or use Macro
Macro BSwap16(_WordValue)
((_WordValue<<8 | _WordValue>>8) & $FFFF)
EndMacro
As shown below, the right shift operation on signed integers requires caution.
This is because the sign bit is extended due to the arithmetic right shift.
Code: Select all
Macro BSwap16(_WordValue)
((_WordValue<<8 | _WordValue>>8) & $FFFF)
EndMacro
a.w = $F1F2
b.u = ((a) << 8) | ((a) >> 8)
Debug Hex(b) ; FFF1
b = BSwap16(a)
Debug Hex(b) ; FFF1
b = ((a) << 8) | (((a) >> 8) & $FF)
Debug Hex(b) ; F2F1
c.u = $F1F2
d.u = ((c) << 8) | ((c) >> 8)
Debug Hex(d) ; F2F1
d = BSwap16(c)
Debug Hex(d) ; F2F1
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 1:39 pm
by SMaag
oohhh!! Yes! with negative values and ShiftRight we have to mask out irrelevant Bytes
Code: Select all
; Swaps the 2 Bytes of a 16Bit value
; use it : result = BSwap16(x); x=[0..$FFFF])
; because of Arithmetic right Shift we need to Mask out irrelevant Bits
Macro BSwap16(_WordValue)
((_WordValue & $FF00)<<8 | (_WordValue & $FF )>>8))
EndMacro
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 2:17 pm
by mk-soft
Use bswap16/32/64 for ASM and C-backend.
Link:
viewtopic.php?t=77563
Code: Select all
Procedure bswap16(value.u)
CompilerIf #PB_Compiler_Backend = #PB_Backend_C
!return __builtin_bswap16(v_value);
CompilerElse
!xor eax,eax
!mov ax, word [p.v_value]
!rol ax, 8
ProcedureReturn
CompilerEndIf
EndProcedure
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 6:17 pm
by ZX80
Thank you all for your answers.
infratec wrote:
And you should use
*Ptr.Unicode
because it's an unsigned number.
Sorry, but the Smallint type in Delphi is a 16-bit (2-byte) signed integer data type. It can store integers in the range of -32768 to 32767. The equivalent in PureBasic is (from the help file):
Word .w 2 bytes -32768 to +32767
Essentially, the file "WW15MGH.DAC" is data on corrections, which can be either negative or positive.
Because of this, it seems to me that the file is still not being read accurately.
Could you take a look ?
https://github.com/nicolas-van/egm96-un ... W15MGH.DAC
Here is the rest of the program
Code: Select all
Procedure Show()
Protected f.d, a.d, b.d, e.d
f = 1.0 / ValD(GetGadgetText(#Edit8)) ;polar compression
a = ValD(GetGadgetText(#Edit7)) ;Big axle shaft
b = a * (1 - f) ;Small axle shaft
e = 2 * f - f * f ;square of eccentricity
; loading a geoid file
; ...
SetGadgetText(#Edit9, StrD(b))
SetGadgetText(#Edit10, StrD(e))
CheckBox1Click()
EndProcedure
; Converting WGS-84 to ECEF coordinates
Procedure Button1Click()
Protected a.d, e.d
Protected B.d, L.d
Protected x.d, y.d, z.d, N.d ;abscissa, ordinate, applicate (in meters)
;latitude and longitude (in degrees)
B = ValD(GetGadgetText(#Edit2))
L = ValD(GetGadgetText(#Edit1))
; height correction
If GetGadgetState(#CheckBox1)
H0 = ValD(GetGadgetText(#Edit3)) ;orthometric height
H = ValD(GetGadgetText(#Edit11)) ;geodetic height
Else
H = ValD(GetGadgetText(#Edit3))
H0 = ValD(GetGadgetText(#Edit11))
EndIf
; degrees to radians
B = Radian(B)
L = Radian(L)
e = ValD(GetGadgetText(#Edit10));square of eccentricity
a = ValD(GetGadgetText(#Edit7)) ;Big axle shaft
; radius of curvature of the first vertical
N = a / Sqr(1 - e * Pow(Sin(B), 2))
; ECEF coordinates
x = (N + H) * Cos(B) * Cos(L)
y = (N + H) * Cos(B) * Sin(L)
z = (N * (1 - e) + H) * Sin(B)
; result
SetGadgetText(#Edit4, StrD(x)) ;abscissa
SetGadgetText(#Edit5, StrD(y)) ;ordinate
SetGadgetText(#Edit6, StrD(z)) ;applicate
EndProcedure
Procedure Button2Click()
Protected a.d, e.d
Protected B.d, B0.d, L.d
Protected x.d, y.d, z.d
Protected N.d, p.d
e = ValD(GetGadgetText(#Edit10))
a = ValD(GetGadgetText(#Edit7))
x = ValD(GetGadgetText(#Edit4))
y = ValD(GetGadgetText(#Edit5))
z = ValD(GetGadgetText(#Edit6))
; longitude
L = ATan2(y, x)
; auxiliary parameter
p = Sqr(x * x + y * y) ; p:=sqrt(Sqr(x)+Sqr(y)) in the original
; initial latitude value
B = ATan2(z, p * (1 - e))
; iterations for calculating latitude
Repeat
B0 = B
N = a / Sqr(1 - e * Sin(B) * Sin(B))
B = ATan2(z + e * N * Sin(B), p)
Until Abs(B0 - B) < ValD(GetGadgetText(#ComboBox1)) ; continue until we get the required accuracy
; geodetic height
H = p * Cos(B) + z * Sin(B) - a * Sqr(1 - e * Sin(B) * Sin(B))
; radians to degrees
L = Degree(L)
B = Degree(B)
; geoid height
dH = GetGeoidHeight(B, L)
; orthometric height
H0 = H - dH
; output of coordinates
SetGadgetText(#Edit2, StrD(B))
SetGadgetText(#Edit1, StrD(L))
; height correction
If GetGadgetState(#CheckBox1)
SetGadgetText(#Edit3, StrD(H0))
SetGadgetText(#Edit11, StrD(H))
Else
SetGadgetText(#Edit3, StrD(H))
SetGadgetText(#Edit11, StrD(H0))
EndIf
SetGadgetText(#Edit12, StrD(dH))
EndProcedure
Re: A piece of code Delphi into PB
Posted: Sat Feb 07, 2026 6:53 pm
by infratec
I corrected my listing above.
It works now with the file from github, but ...
the filesize is not correct.
From the array size it should be 2.073.600, but it is 2.076.480
Ok, from the readme:
https://github.com/nicolas-van/egm96-un ... readme.txt
There are 721 records in the file, but the last record is ignored.
Re: A piece of code Delphi into PB
Posted: Sun Feb 08, 2026 2:39 pm
by ZX80
infratec, thanks. It works.
infratec wrote: Sat Feb 07, 2026 6:53 pm
the filesize is not correct.
From the array size it should be 2.073.600, but it is 2.076.480
You're right ! But...
We have what we have.
In addition:
The correction range is from -106 meters to +85 meters. The amendment depends on the area you are in. It will be different for areas with iron ore and... for example over the ocean. The gravity also changes (also depends on the local density of rocks).
In conclusion:
This means that if you choose the wrong correction, the accuracy will be very poor ! I meant the accuracy of determining coordinates.