LazMapViewer: Remove duplicate distance calculation in TGPSPoint. Had to move some general-purpose geo-math routines to a new units mvGeoMath. Old functions kept in mvEngine, but marked as deprecated.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9337 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-04-15 23:11:21 +00:00
parent e545177bc3
commit 93167ada8b
20 changed files with 820 additions and 980 deletions

View File

@ -7,8 +7,8 @@ interface
uses uses
Classes, SysUtils, LazFileUtils, Classes, SysUtils, LazFileUtils,
LCLIntf, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLIntf, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls, Grids, Buttons, mvMapViewer, mvTypes, mvEngine, Types, mvGpsObj, ExtCtrls, Grids, Buttons, Types,
mvDrawingEngine; mvMapViewer, mvTypes, mvGeoMath, mvEngine, mvGpsObj, mvDrawingEngine;
type type
{ TMainForm } { TMainForm }

View File

@ -6,9 +6,10 @@ object MainForm: TMainForm
Caption = 'Flights - LazMapViewer' Caption = 'Flights - LazMapViewer'
ClientHeight = 662 ClientHeight = 662
ClientWidth = 942 ClientWidth = 942
ShowHint = True
LCLVersion = '3.99.0.0'
OnCreate = FormCreate OnCreate = FormCreate
OnDestroy = FormDestroy OnDestroy = FormDestroy
ShowHint = True
object MapView: TMapView object MapView: TMapView
Left = 0 Left = 0
Height = 662 Height = 662
@ -27823,192 +27824,33 @@ object MainForm: TMainForm
MapCenter.Longitude = -87.9081388888889 MapCenter.Longitude = -87.9081388888889
MapCenter.Latitude = 41.9769444444444 MapCenter.Latitude = 41.9769444444444
POIImage.Data = { POIImage.Data = {
36170000424D36170000000000003600000028000000200000002E0000000100 4503000089504E470D0A1A0A0000000D49484452000000200000002E08060000
2000000000000017000064000000640000000000000000000000FFFFFF00FFFF 0049701B840000030C49444154789CB5983B68145114867F4410C54644B0107C
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 152262A7A4D2C2DA3422DAD8D868631510B1D1688855409104A2088634819056
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD560000FC4CFFFF B00C488845626C82C55662A29204C40DC96ED66CD6F38F77976B76E6DCC7CC14
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 077667CEF9FFEF3EE6CC03AD560B3EB1021C6C023777805189598955892D13AB
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF E6D8287398EBABEB4CA803A745F895C47A92EE11CC650D6BA3012AC03E1119E4
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 087D8D5340383B83D40A0210F29352381F6B9C02F2899A5E000DE09C142C1765
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F1110000FEE70000FEE10000 6E412C535B05A801C72571A968730B62891EA90066CDE7CA32B720E6EC3DD101
EA0CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 901303012215893772C93D62F0378F05D40FFC07201BE4841CAC7B147EF8035C
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF CADAD13CC71C0F9D3A3D3B007260C451B023237DDC0FEC715DD7CC612E6B1C9A
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 2309C077E080FCA96AC99C66DFCED68EA44607A8D21BDBC03547E2B4CFC8D366
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE9A0000FFFF0000FFFF0000 82B59A36BD39FDC35A92AC6B4FA8B9B5277A1C831B26C08C92B0186B6E5D5D8B
FE8FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 8AFE0C137EBA364A4E80CC0D4E6F26D494CD773F2F40A2910D5023404301E82B
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 00A04F016810604D49182A60098614FD3568B7DD6483E607D036F93C13C69484
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF A6CF534D5698A7A9A6A23FC635BAEDB856C7738C7E5CD3A637D68123DA46644F
FF00FFFFFF00FFFFFF00FFFFFF000000FB3E0000FEFE0000FFFF0000FFFF0000 978E753DD49C35DAFD809EF46E934E39666153047B03CC7B59E3D09C6AFDFB97
FEFC0000FB35FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF B4CC0B1E77AFA6C4CB2A7038CB98E798A3AD7B7B56E9D90130B330A115D9CD43
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF E29DC41359C3BB0CFE36C7329BDA2E8D89B66F07600B38E3222F22CC9575AA0B
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF C0CCC2D3B20164C61EDA9E5DEB28100B258EFEE36EBF2E00D33C9CCF8711E61B
FF00FFFFFF00FFFFFF000000DB070000FED70000FFFF0000FFFF0000FFFF0000 9BC0312780B9813C2861EAEFA579A5024C037B85F87381A39FCD7AAC4B0530BD
FFFF0000FECF0000C004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF E1A2146E1760DE9057B2F3593E99006643BE2800E099E6A102F04383087CCD61
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 5EF906EC8F06307DFD6AA4396F62575CFA4E00B3149311006F7DB4BD003680A3
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 22F82BC07C45BB69050398DE7027E09ABFE5ABEB0D605EB57CDE7CDFFB6A0601
FF00FFFFFF00FFFFFF000000FE800000FFFF0000FFFF0000FFFF0000FFFF0000 30E48E7956FB68C5769BF52DA81000B321FB95A90F7E910906309F72BEA48C7E
FFFF0000FFFF0000FD75FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 812DBC740086B4E9CBF6231C5B365B778C561480598AD716C0F3589D6880DFC0
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 2131FEC1561DF26DB83000866CBA1B49ABCEA1F117D2B9A057721AC774000000
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 0049454E44AE426082
FF00FFFFFF000000F9290000FEF90000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEF50000F821FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00000080020000FEC30000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FEB8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000FD660000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FD5CFFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
F5180000FEEF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEEA0000F213FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
FEAA0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE9FFFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FC4C0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFE0000FC42FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000EA0C0000FEE10000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEDB0000E309FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE900000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE86FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FB350000FEFC0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFA0000
FA2DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000C0040000FED00000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FEC700008002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000FD770000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FD6CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF000000F8230000FEF80000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FEF50000F61CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF000000FECF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEC8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000FE820000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FD79FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000F9270000FEFD0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FEFD0000F822FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000FEA70000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FEF70000FEB50000FE810000FD670000FD670000
FE810000FEB50000FEF70000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEA7FFFFFF00FFFFFF00FFFFFF000000
FB340000FEFE0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FEFD0000FE920000F213FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000F2130000FE920000FEFD0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEFE0000FB34FFFFFF00FFFFFF000000
FEAC0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FEF60000FC4DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000FC4D0000FEF60000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEACFFFFFF000000F3150000
FEFA0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFE0000
FC54FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FC540000FEFE0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFA0000F3150000FD610000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEA2FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FEA20000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FD610000FEA00000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFD0000F823FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F8230000FEFD0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEA00000FECD0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEC5FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FEC50000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FECD0000FEEC0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE8CFFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE8C0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEEC0000FEFA0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FD72FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD720000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFA0000FEF70000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FD75FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD750000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEF70000FEE80000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE95FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE950000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEE80000FEC50000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FED5FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FED50000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEC50000FE940000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FB37FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FB370000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE940000FC520000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEC00000
8002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000080020000FEC00000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FC520000E60A0000
FEF20000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FD7EFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD7E0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEF20000E60AFFFFFF000000
FE950000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FEFE0000FD7F00008002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00000080020000FD7F0000FEFE0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE95FFFFFF00FFFFFF000000
F8200000FEF80000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEC30000FB3DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000FB3D0000FEC30000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEF80000F820FFFFFF00FFFFFF00FFFF
FF000000FE830000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEDB0000FE9C0000FD7E0000FD7E0000
FE9C0000FEDB0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FE83FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000DB070000FECC0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FECC0000DB07FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000F71F0000FEE40000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEE40000F71FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF000000FA2B0000FEE50000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FEE50000FA2BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000F8210000FECD0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FECE0000F821FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000DB070000FE850000FEF90000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEF90000FE850000
DB07FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F8230000
FE990000FEF30000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEF30000FE990000F823FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000EA0C0000FD570000FE980000FEC70000FEEB0000FEF90000FEF90000
FEEB0000FEC70000FE980000FD570000EA0CFFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
} }
POIImages = ilPOIs POIImages = ilPOIs
POIImagesWidth = 32 POIImagesWidth = 32
@ -28031,8 +27873,8 @@ object MainForm: TMainForm
TabOrder = 1 TabOrder = 1
object PgData: TTabSheet object PgData: TTabSheet
Caption = 'Tracking' Caption = 'Tracking'
ClientHeight = 627 ClientHeight = 634
ClientWidth = 312 ClientWidth = 310
object ZoomTrackBar: TTrackBar object ZoomTrackBar: TTrackBar
AnchorSideLeft.Control = PgData AnchorSideLeft.Control = PgData
AnchorSideTop.Control = LblZoom AnchorSideTop.Control = LblZoom
@ -28041,12 +27883,12 @@ object MainForm: TMainForm
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 2 Left = 2
Height = 40 Height = 40
Top = 23 Top = 21
Width = 308 Width = 306
Min = 1 Min = 1
OnChange = ZoomTrackBarChange
Position = 4 Position = 4
TickMarks = tmBoth TickMarks = tmBoth
OnChange = ZoomTrackBarChange
Anchors = [akTop, akLeft, akRight] Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 2 BorderSpacing.Left = 2
BorderSpacing.Right = 2 BorderSpacing.Right = 2
@ -28056,9 +27898,9 @@ object MainForm: TMainForm
AnchorSideLeft.Control = PgData AnchorSideLeft.Control = PgData
AnchorSideTop.Control = PgData AnchorSideTop.Control = PgData
Left = 6 Left = 6
Height = 17 Height = 15
Top = 6 Top = 6
Width = 43 Width = 35
BorderSpacing.Left = 6 BorderSpacing.Left = 6
BorderSpacing.Top = 6 BorderSpacing.Top = 6
Caption = 'Zoom:' Caption = 'Zoom:'
@ -28071,9 +27913,9 @@ object MainForm: TMainForm
AnchorSideRight.Control = PgData AnchorSideRight.Control = PgData
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 6 Left = 6
Height = 73 Height = 70
Top = 71 Top = 69
Width = 300 Width = 298
Anchors = [akTop, akLeft, akRight] Anchors = [akTop, akLeft, akRight]
AutoSize = True AutoSize = True
BorderSpacing.Left = 6 BorderSpacing.Left = 6
@ -28081,17 +27923,17 @@ object MainForm: TMainForm
BorderSpacing.Right = 6 BorderSpacing.Right = 6
BorderSpacing.InnerBorder = 4 BorderSpacing.InnerBorder = 4
Caption = 'Mouse position' Caption = 'Mouse position'
ClientHeight = 54 ClientHeight = 50
ClientWidth = 296 ClientWidth = 294
TabOrder = 1 TabOrder = 1
object lblMouseLon: TLabel object lblMouseLon: TLabel
AnchorSideLeft.Control = gbMouse AnchorSideLeft.Control = gbMouse
AnchorSideTop.Control = lblMouseLat AnchorSideTop.Control = lblMouseLat
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
Left = 8 Left = 8
Height = 17 Height = 15
Top = 29 Top = 27
Width = 68 Width = 54
BorderSpacing.Left = 8 BorderSpacing.Left = 8
BorderSpacing.Top = 4 BorderSpacing.Top = 4
Caption = 'Longitude' Caption = 'Longitude'
@ -28101,9 +27943,9 @@ object MainForm: TMainForm
AnchorSideLeft.Control = gbMouse AnchorSideLeft.Control = gbMouse
AnchorSideTop.Control = gbMouse AnchorSideTop.Control = gbMouse
Left = 8 Left = 8
Height = 17 Height = 15
Top = 4 Top = 4
Width = 57 Width = 43
BorderSpacing.Left = 8 BorderSpacing.Left = 8
BorderSpacing.Top = 4 BorderSpacing.Top = 4
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
@ -28116,10 +27958,10 @@ object MainForm: TMainForm
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = gbMouse AnchorSideRight.Control = gbMouse
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 235 Left = 244
Height = 17 Height = 15
Top = 29 Top = 27
Width = 45 Width = 34
Alignment = taRightJustify Alignment = taRightJustify
Anchors = [akTop, akRight] Anchors = [akTop, akRight]
BorderSpacing.Top = 4 BorderSpacing.Top = 4
@ -28132,10 +27974,10 @@ object MainForm: TMainForm
AnchorSideTop.Control = gbMouse AnchorSideTop.Control = gbMouse
AnchorSideRight.Control = gbMouse AnchorSideRight.Control = gbMouse
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 235 Left = 244
Height = 17 Height = 15
Top = 4 Top = 4
Width = 45 Width = 34
Alignment = taRightJustify Alignment = taRightJustify
Anchors = [akTop, akRight] Anchors = [akTop, akRight]
BorderSpacing.Top = 4 BorderSpacing.Top = 4
@ -28152,25 +27994,25 @@ object MainForm: TMainForm
AnchorSideRight.Control = gbMouse AnchorSideRight.Control = gbMouse
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 6 Left = 6
Height = 73 Height = 70
Top = 152 Top = 147
Width = 300 Width = 298
Anchors = [akTop, akLeft, akRight] Anchors = [akTop, akLeft, akRight]
AutoSize = True AutoSize = True
BorderSpacing.Top = 8 BorderSpacing.Top = 8
BorderSpacing.InnerBorder = 4 BorderSpacing.InnerBorder = 4
Caption = 'Center' Caption = 'Center'
ClientHeight = 54 ClientHeight = 50
ClientWidth = 296 ClientWidth = 294
TabOrder = 2 TabOrder = 2
object lblCenterLon: TLabel object lblCenterLon: TLabel
AnchorSideLeft.Control = gbCenter AnchorSideLeft.Control = gbCenter
AnchorSideTop.Control = lblCenterLat AnchorSideTop.Control = lblCenterLat
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
Left = 8 Left = 8
Height = 17 Height = 15
Top = 29 Top = 27
Width = 68 Width = 54
BorderSpacing.Left = 8 BorderSpacing.Left = 8
BorderSpacing.Top = 4 BorderSpacing.Top = 4
Caption = 'Longitude' Caption = 'Longitude'
@ -28180,9 +28022,9 @@ object MainForm: TMainForm
AnchorSideLeft.Control = gbCenter AnchorSideLeft.Control = gbCenter
AnchorSideTop.Control = gbCenter AnchorSideTop.Control = gbCenter
Left = 8 Left = 8
Height = 17 Height = 15
Top = 4 Top = 4
Width = 57 Width = 43
BorderSpacing.Left = 8 BorderSpacing.Left = 8
BorderSpacing.Top = 4 BorderSpacing.Top = 4
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
@ -28195,10 +28037,10 @@ object MainForm: TMainForm
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = gbCenter AnchorSideRight.Control = gbCenter
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 235 Left = 244
Height = 17 Height = 15
Top = 29 Top = 27
Width = 45 Width = 34
Alignment = taRightJustify Alignment = taRightJustify
Anchors = [akTop, akRight] Anchors = [akTop, akRight]
BorderSpacing.Top = 4 BorderSpacing.Top = 4
@ -28211,10 +28053,10 @@ object MainForm: TMainForm
AnchorSideTop.Control = gbCenter AnchorSideTop.Control = gbCenter
AnchorSideRight.Control = gbCenter AnchorSideRight.Control = gbCenter
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
Left = 235 Left = 244
Height = 17 Height = 15
Top = 4 Top = 4
Width = 45 Width = 34
Alignment = taRightJustify Alignment = taRightJustify
Anchors = [akTop, akRight] Anchors = [akTop, akRight]
BorderSpacing.Top = 4 BorderSpacing.Top = 4
@ -28230,9 +28072,9 @@ object MainForm: TMainForm
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = plInfo AnchorSideBottom.Control = plInfo
Left = 6 Left = 6
Height = 231 Height = 246
Top = 233 Top = 225
Width = 298 Width = 296
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
AutoFillColumns = True AutoFillColumns = True
BorderSpacing.Top = 8 BorderSpacing.Top = 8
@ -28248,12 +28090,12 @@ object MainForm: TMainForm
item item
Title.Alignment = taCenter Title.Alignment = taCenter
Title.Caption = 'Latitude' Title.Caption = 'Latitude'
Width = 105 Width = 111
end end
item item
Title.Alignment = taCenter Title.Alignment = taCenter
Title.Caption = 'Longitude' Title.Caption = 'Longitude'
Width = 106 Width = 111
end> end>
FixedCols = 0 FixedCols = 0
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSelect, goSmoothScroll] Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSelect, goSmoothScroll]
@ -28262,8 +28104,8 @@ object MainForm: TMainForm
OnDblClick = sgTracksDblClick OnDblClick = sgTracksDblClick
ColWidths = ( ColWidths = (
70 70
105 111
106 111
) )
end end
object pnlFlightControl: TPanel object pnlFlightControl: TPanel
@ -28274,8 +28116,8 @@ object MainForm: TMainForm
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 0 Left = 0
Height = 50 Height = 50
Top = 577 Top = 584
Width = 312 Width = 310
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
BevelOuter = bvNone BevelOuter = bvNone
ChildSizing.LeftRightSpacing = 5 ChildSizing.LeftRightSpacing = 5
@ -28288,13 +28130,13 @@ object MainForm: TMainForm
ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 99 ChildSizing.ControlsPerLine = 99
ClientHeight = 50 ClientHeight = 50
ClientWidth = 312 ClientWidth = 310
TabOrder = 4 TabOrder = 4
object btnPlay: TSpeedButton object btnPlay: TSpeedButton
Left = 5 Left = 5
Height = 40 Height = 40
Top = 5 Top = 5
Width = 65 Width = 66
Glyph.Data = { Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100 36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000064000000640000000000000000000000000000000000 2000000000000004000064000000640000000000000000000000000000000000
@ -28334,10 +28176,10 @@ object MainForm: TMainForm
OnClick = btnPlayClick OnClick = btnPlayClick
end end
object btnPause: TSpeedButton object btnPause: TSpeedButton
Left = 75 Left = 76
Height = 40 Height = 40
Top = 5 Top = 5
Width = 65 Width = 66
Glyph.Data = { Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100 36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000064000000640000000000000000000000000000000000 2000000000000004000064000000640000000000000000000000000000000000
@ -28377,10 +28219,10 @@ object MainForm: TMainForm
OnClick = btnPauseClick OnClick = btnPauseClick
end end
object btnStop: TSpeedButton object btnStop: TSpeedButton
Left = 145 Left = 147
Height = 40 Height = 40
Top = 5 Top = 5
Width = 65 Width = 67
Glyph.Data = { Glyph.Data = {
36040000424D3604000000000000360000002800000010000000100000000100 36040000424D3604000000000000360000002800000010000000100000000100
2000000000000004000064000000640000000000000000000000000000000000 2000000000000004000064000000640000000000000000000000000000000000
@ -28420,10 +28262,10 @@ object MainForm: TMainForm
OnClick = btnStopClick OnClick = btnStopClick
end end
object btnWarp: TSpeedButton object btnWarp: TSpeedButton
Left = 215 Left = 219
Height = 40 Height = 40
Top = 5 Top = 5
Width = 92 Width = 86
Caption = 'Warp+' Caption = 'Warp+'
OnClick = btnWarpClick OnClick = btnWarpClick
end end
@ -28433,8 +28275,8 @@ object MainForm: TMainForm
AnchorSideBottom.Control = pnlFlightControl AnchorSideBottom.Control = pnlFlightControl
Left = 6 Left = 6
Height = 33 Height = 33
Top = 536 Top = 543
Width = 298 Width = 296
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
TabOrder = 5 TabOrder = 5
@ -28446,11 +28288,11 @@ object MainForm: TMainForm
AnchorSideBottom.Control = pnlWarpInfo AnchorSideBottom.Control = pnlWarpInfo
Left = 6 Left = 6
Height = 72 Height = 72
Top = 464 Top = 471
Width = 298 Width = 296
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
ClientHeight = 72 ClientHeight = 72
ClientWidth = 298 ClientWidth = 296
Color = clCream Color = clCream
ParentBackground = False ParentBackground = False
ParentColor = False ParentColor = False
@ -28459,7 +28301,7 @@ object MainForm: TMainForm
Left = 6 Left = 6
Height = 60 Height = 60
Top = 6 Top = 6
Width = 286 Width = 284
Align = alClient Align = alClient
AutoSize = False AutoSize = False
BorderSpacing.Around = 5 BorderSpacing.Around = 5
@ -28473,16 +28315,16 @@ object MainForm: TMainForm
AnchorSideBottom.Control = plInfo AnchorSideBottom.Control = plInfo
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 4 Left = 4
Height = 21 Height = 19
Top = 47 Top = 49
Width = 114 Width = 90
Anchors = [akLeft, akBottom] Anchors = [akLeft, akBottom]
BorderSpacing.Around = 3 BorderSpacing.Around = 3
Caption = 'Follow tightly' Caption = 'Follow tightly'
Checked = True Checked = True
OnChange = cbTightFollowChange
State = cbChecked State = cbChecked
TabOrder = 0 TabOrder = 0
OnChange = cbTightFollowChange
end end
end end
end end

View File

@ -71,7 +71,7 @@ implementation
{$R *.lfm} {$R *.lfm}
uses uses
LCLType, Math, FPImage, DateUtils, mvEngine; LCLType, Math, FPImage, DateUtils, mvGeoMath, mvEngine;
type type

View File

@ -5,7 +5,7 @@ unit globals;
interface interface
uses uses
Classes, SysUtils, mvEngine; Classes, SysUtils, mvGeoMath, mvEngine;
type type
TPOIMode = (pmDefaultDrawing, pmDefaultImage, pmImageList, pmCustomDrawing); TPOIMode = (pmDefaultDrawing, pmDefaultImage, pmImageList, pmCustomDrawing);

View File

@ -57,7 +57,7 @@ implementation
{$R *.lfm} {$R *.lfm}
uses uses
mvTypes, mvEngine, mvTypes, mvGeoMath, mvEngine,
globals; globals;
destructor TGPSListViewer.Destroy; destructor TGPSListViewer.Destroy;
@ -143,7 +143,7 @@ begin
// show distance between selected items // show distance between selected items
ShowMessage(Format('Distance between %s and %s is: %.2n %s.', [ ShowMessage(Format('Distance between %s and %s is: %.2n %s.', [
CoordArr[0].Name, CoordArr[1].Name, CoordArr[0].Name, CoordArr[1].Name,
CalcGeoDistance(CoordArr[0].Lat, CoordArr[0].Lon, CoordArr[1].Lat, CoordArr[1].Lon, DistanceUnit), CalcGeoDistance(CoordArr[0].Lat, CoordArr[0].Lon, CoordArr[1].Lat, CoordArr[1].Lon, DistanceUnit, esEllipsoid),
DistanceUnit_Names[DistanceUnit] DistanceUnit_Names[DistanceUnit]
])); ]));
end; end;

View File

@ -15,7 +15,7 @@ uses
Classes, SysUtils, Types, Forms, Controls, Graphics, Dialogs, ExtCtrls, Classes, SysUtils, Types, Forms, Controls, Graphics, Dialogs, ExtCtrls,
StdCtrls, ComCtrls, Buttons, IntfGraphics, PrintersDlgs, StdCtrls, ComCtrls, Buttons, IntfGraphics, PrintersDlgs,
Grids, ExtDlgs, Grids, ExtDlgs,
mvGeoNames, mvMapViewer, mvTypes, mvGpsObj, mvDrawingEngine, mvGeoMath, mvGeoNames, mvMapViewer, mvTypes, mvGpsObj, mvDrawingEngine,
{$IFDEF WITH_ADDONS}ConfigFrame_with_Addons{$ELSE}ConfigFrame{$ENDIF}; {$IFDEF WITH_ADDONS}ConfigFrame_with_Addons{$ELSE}ConfigFrame{$ENDIF};
type type

View File

@ -24,192 +24,33 @@ object MainForm: TMainForm
Font.Pitch = fpVariable Font.Pitch = fpVariable
MapProvider = 'Google Maps' MapProvider = 'Google Maps'
POIImage.Data = { POIImage.Data = {
36170000424D36170000000000003600000028000000200000002E0000000100 4503000089504E470D0A1A0A0000000D49484452000000200000002E08060000
2000000000000017000064000000640000000000000000000000FFFFFF00FFFF 0049701B840000030C49444154789CB5983B68145114867F4410C54644B0107C
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 152262A7A4D2C2DA3422DAD8D868631510B1D1688855409104A2088634819056
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD560000FC4CFFFF B00C488845626C82C55662A29204C40DC96ED66CD6F38F77976B76E6DCC7CC14
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 077667CEF9FFEF3EE6CC03AD560B3EB1021C6C023777805189598955892D13AB
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF E6D8287398EBABEB4CA803A745F895C47A92EE11CC650D6BA3012AC03E1119E4
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 087D8D5340383B83D40A0210F29352381F6B9C02F2899A5E000DE09C142C1765
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F1110000FEE70000FEE10000 6E412C535B05A801C72571A968730B62891EA90066CDE7CA32B720E6EC3DD101
EA0CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 901303012215893772C93D62F0378F05D40FFC07201BE4841CAC7B147EF8035C
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF CADAD13CC71C0F9D3A3D3B007260C451B023237DDC0FEC715DD7CC612E6B1C9A
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 2309C077E080FCA96AC99C66DFCED68EA44607A8D21BDBC03547E2B4CFC8D366
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE9A0000FFFF0000FFFF0000 82B59A36BD39FDC35A92AC6B4FA8B9B5277A1C831B26C08C92B0186B6E5D5D8B
FE8FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 8AFE0C137EBA364A4E80CC0D4E6F26D494CD773F2F40A2910D5023404301E82B
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 00A04F016810604D49182A60098614FD3568B7DD6483E607D036F93C13C69484
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF A6CF534D5698A7A9A6A23FC635BAEDB856C7738C7E5CD3A637D68123DA46644F
FF00FFFFFF00FFFFFF00FFFFFF000000FB3E0000FEFE0000FFFF0000FFFF0000 978E753DD49C35DAFD809EF46E934E39666153047B03CC7B59E3D09C6AFDFB97
FEFC0000FB35FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF B4CC0B1E77AFA6C4CB2A7038CB98E798A3AD7B7B56E9D90130B330A115D9CD43
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF E29DC41359C3BB0CFE36C7329BDA2E8D89B66F07600B38E3222F22CC9575AA0B
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF C0CCC2D3B20164C61EDA9E5DEB28100B258EFEE36EBF2E00D33C9CCF8711E61B
FF00FFFFFF00FFFFFF000000DB070000FED70000FFFF0000FFFF0000FFFF0000 9BC0312780B9813C2861EAEFA579A5024C037B85F87381A39FCD7AAC4B0530BD
FFFF0000FECF0000C004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF E1A2146E1760DE9057B2F3593E99006643BE2800E099E6A102F04383087CCD61
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 5EF906EC8F06307DFD6AA4396F62575CFA4E00B3149311006F7DB4BD003680A3
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 22F82BC07C45BB69050398DE7027E09ABFE5ABEB0D605EB57CDE7CDFFB6A0601
FF00FFFFFF00FFFFFF000000FE800000FFFF0000FFFF0000FFFF0000FFFF0000 30E48E7956FB68C5769BF52DA81000B321FB95A90F7E910906309F72BEA48C7E
FFFF0000FFFF0000FD75FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 812DBC740086B4E9CBF6231C5B365B778C561480598AD716C0F3589D6880DFC0
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 2131FEC1561DF26DB83000866CBA1B49ABCEA1F117D2B9A057721AC774000000
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF 0049454E44AE426082
FF00FFFFFF000000F9290000FEF90000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEF50000F821FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00000080020000FEC30000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FEB8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000FD660000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FD5CFFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
F5180000FEEF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEEA0000F213FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
FEAA0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE9FFFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FC4C0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFE0000FC42FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000EA0C0000FEE10000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEDB0000E309FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE900000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE86FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FB350000FEFC0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFA0000
FA2DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000C0040000FED00000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FEC700008002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000FD770000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FD6CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF000000F8230000FEF80000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FEF50000F61CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF000000FECF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEC8FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000FE820000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FD79FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000F9270000FEFD0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FEFD0000F822FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000FEA70000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FEF70000FEB50000FE810000FD670000FD670000
FE810000FEB50000FEF70000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEA7FFFFFF00FFFFFF00FFFFFF000000
FB340000FEFE0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FEFD0000FE920000F213FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000F2130000FE920000FEFD0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEFE0000FB34FFFFFF00FFFFFF000000
FEAC0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FEF60000FC4DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000FC4D0000FEF60000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEACFFFFFF000000F3150000
FEFA0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFE0000
FC54FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FC540000FEFE0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFA0000F3150000FD610000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEA2FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FEA20000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FD610000FEA00000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFD0000F823FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F8230000FEFD0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEA00000FECD0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEC5FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FEC50000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FECD0000FEEC0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE8CFFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE8C0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEEC0000FEFA0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FD72FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD720000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEFA0000FEF70000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FD75FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD750000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEF70000FEE80000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE95FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE950000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEE80000FEC50000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FED5FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FED50000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEC50000FE940000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FB37FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FB370000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE940000FC520000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEC00000
8002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000080020000FEC00000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FC520000E60A0000
FEF20000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FD7EFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD7E0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEF20000E60AFFFFFF000000
FE950000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FEFE0000FD7F00008002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00000080020000FD7F0000FEFE0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FE95FFFFFF00FFFFFF000000
F8200000FEF80000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEC30000FB3DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000FB3D0000FEC30000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEF80000F820FFFFFF00FFFFFF00FFFF
FF000000FE830000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEDB0000FE9C0000FD7E0000FD7E0000
FE9C0000FEDB0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FE83FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000DB070000FECC0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FECC0000DB07FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF000000F71F0000FEE40000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FEE40000F71FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF000000FA2B0000FEE50000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FEE50000FA2BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF000000F8210000FECD0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FECE0000F821FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000DB070000FE850000FEF90000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FEF90000FE850000
DB07FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F8230000
FE990000FEF30000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000
FFFF0000FFFF0000FFFF0000FFFF0000FEF30000FE990000F823FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
FF000000EA0C0000FD570000FE980000FEC70000FEEB0000FEF90000FEF90000
FEEB0000FEC70000FE980000FD570000EA0CFFFFFF00FFFFFF00FFFFFF00FFFF
FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00
} }
POITextBgColor = clCream POITextBgColor = clCream
UseThreads = True UseThreads = True

View File

@ -6,7 +6,7 @@ interface
uses uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
Grids, StdCtrls, ColorBox, mvMapViewer, mvGpsObj; Grids, StdCtrls, ColorBox, mvMapViewer, mvGeoMath, mvGpsObj;
type type

View File

@ -20,7 +20,7 @@
<Description Value="Component for viewing maps (Google, OpenStreetMap, etc). This is a fork of MapViewer by ti_dic (https://sourceforge.net/p/roadbook/code/ci/master/tree/mapviewer/) which itself is based on the MapViewer by Maciej Kaczkowski (https://github.com/maciejkaczkowski/mapviewer)."/> <Description Value="Component for viewing maps (Google, OpenStreetMap, etc). This is a fork of MapViewer by ti_dic (https://sourceforge.net/p/roadbook/code/ci/master/tree/mapviewer/) which itself is based on the MapViewer by Maciej Kaczkowski (https://github.com/maciejkaczkowski/mapviewer)."/>
<License Value="Modified LGPL with linking exception, like FreePascal RTL/FCL and Lazarus LCL"/> <License Value="Modified LGPL with linking exception, like FreePascal RTL/FCL and Lazarus LCL"/>
<Version Minor="2" Release="7"/> <Version Minor="2" Release="7"/>
<Files Count="21"> <Files Count="22">
<Item1> <Item1>
<Filename Value="source/mvcache.pas"/> <Filename Value="source/mvcache.pas"/>
<UnitName Value="mvCache"/> <UnitName Value="mvCache"/>
@ -108,6 +108,10 @@
<HasRegisterProc Value="True"/> <HasRegisterProc Value="True"/>
<UnitName Value="mvDE_LCL"/> <UnitName Value="mvDE_LCL"/>
</Item21> </Item21>
<Item22>
<Filename Value="source/mvgeomath.pas"/>
<UnitName Value="mvgeomath"/>
</Item22>
</Files> </Files>
<CompatibilityMode Value="True"/> <CompatibilityMode Value="True"/>
<RequiredPkgs Count="2"> <RequiredPkgs Count="2">

View File

@ -11,7 +11,7 @@ uses
mvCache, mvDownloadEngine, mvDragObj, mvEngine, mvGeoNames, mvGpsObj, mvCache, mvDownloadEngine, mvDragObj, mvEngine, mvGeoNames, mvGpsObj,
mvJobQueue, mvJobs, mvMapProvider, mvTypes, mvMapViewer, mvExtraData, mvJobQueue, mvJobs, mvMapProvider, mvTypes, mvMapViewer, mvExtraData,
mvDLEFpc, mvMapViewerReg, mvGPX, mvDrawingEngine, mvDE_IntfGraphics, mvDLEFpc, mvMapViewerReg, mvGPX, mvDrawingEngine, mvDE_IntfGraphics,
mvDLEWin, mvMapViewerPropEdits, mvLayersPropEditForm, mvDE_LCL, mvDLEWin, mvMapViewerPropEdits, mvLayersPropEditForm, mvDE_LCL, mvgeomath,
LazarusPackageIntf; LazarusPackageIntf;
implementation implementation

View File

@ -21,13 +21,7 @@ interface
uses uses
Classes, SysUtils, IntfGraphics, Controls, Math, GraphType, FPImage, Classes, SysUtils, IntfGraphics, Controls, Math, GraphType, FPImage,
mvTypes, mvJobQueue, mvMapProvider, mvDownloadEngine, mvCache, mvDragObj; mvTypes, mvGeoMath, mvJobQueue, mvMapProvider, mvDownloadEngine, mvCache, mvDragObj;
const
EARTH_EQUATORIAL_RADIUS = 6378137;
EARTH_POLAR_RADIUS = 6356752.3142;
EARTH_CIRCUMFERENCE = 2 * pi * EARTH_EQUATORIAL_RADIUS;
EARTH_ECCENTRICITY = sqrt(1 - sqr(EARTH_POLAR_RADIUS / EARTH_EQUATORIAL_RADIUS));
type type
TDrawTileEvent = procedure (const TileId: TTileId; X,Y: integer; TDrawTileEvent = procedure (const TileId: TTileId; X,Y: integer;
@ -42,8 +36,6 @@ type
TTileIdArray = Array of TTileId; TTileIdArray = Array of TTileId;
TDistanceUnits = (duMeters, duKilometers, duMiles);
{ TMapWindow } { TMapWindow }
TMapWindow = Record TMapWindow = Record
@ -215,33 +207,19 @@ type
property OnZoomChange: TNotifyEvent read FOnZoomChange write FOnZoomChange; property OnZoomChange: TNotifyEvent read FOnZoomChange write FOnZoomChange;
end; end;
function RealPoint(Lat, Lon: Double): TRealPoint; // The following functions have been moved to mvGeoMath and will be removed here sooner or later...
function NormalizeLon(const Lon: Double): Double; inline; function DMSToDeg(Deg, Min: Word; Sec: Double): Double; deprecated 'Use function in unit mvGeoMath';
function GPSToDMS(Angle: Double): string; deprecated 'Use function in unit mvGeoMath';
function GPSToDMS(Angle: Double; AFormatSettings: TFormatSettings): string; deprecated 'Use function in unit mvGeoMath';
function HaversineDist(Lat1, Lon1, Lat2, Lon2, Radius: Double): Double; function LatToStr(ALatitude: Double; DMS: Boolean): String; deprecated 'Use function in unit mvGeoMath';
function CalcGeoDistance(Lat1, Lon1, Lat2, Lon2: double; function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String; deprecated 'Use function in unit mvGeoMath';
AUnits: TDistanceUnits = duKilometers): double; function LonToStr(ALongitude: Double; DMS: Boolean): String; deprecated 'Use function in unit mvGeoMath';
function LonToStr(ALongitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String; deprecated 'Use function in unit mvGeoMath';
function TryStrToGps(const AValue: String; out ADeg: Double): Boolean; deprecated 'Use function in unit mvGeoMath';
function TryStrDMSToDeg(const AValue: String; out ADeg: Double): Boolean; deprecated 'Use function in unit mvGeoMath';
function CalcBearing(Lat1, Lon1, Lat2, Lon2: Double): Double; function ZoomFactor(AZoomLevel: Integer): Int64; deprecated 'Use function in unit mvGeoMath';
procedure CalcLatLon(const Lat1, Lon1, ADist, ABearing: Double; out Lat2, Lon2: Double);
procedure CalcMidpoint(const Lat1, Lon1, Lat2, Lon2: Double; out Lat, Lon: Double);
procedure CalcIntermedPoint(const Lat1, Lon1, Lat2, Lon2, AFrac: Double; out Lat, Lon: Double);
function DMSToDeg(Deg, Min: Word; Sec: Double): Double;
function GPSToDMS(Angle: Double): string;
function GPSToDMS(Angle: Double; AFormatSettings: TFormatSettings): string;
function LatToStr(ALatitude: Double; DMS: Boolean): String;
function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
function LonToStr(ALongitude: Double; DMS: Boolean): String;
function LonToStr(ALongitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
function TryStrToGps(const AValue: String; out ADeg: Double): Boolean;
function TryStrDMSToDeg(const AValue: String; out ADeg: Double): Boolean;
procedure SplitGps(AValue: Double; out ADegs, AMins, ASecs: Double);
function ZoomFactor(AZoomLevel: Integer): Int64;
var var
HERE_AppID: String = ''; HERE_AppID: String = '';
@ -249,8 +227,6 @@ var
OpenWeatherMap_ApiKey: String = ''; OpenWeatherMap_ApiKey: String = '';
ThunderForest_ApiKey: String = ''; ThunderForest_ApiKey: String = '';
DMS_Decimals: Integer = 1;
implementation implementation
@ -258,25 +234,6 @@ uses
Forms, TypInfo, laz2_xmlread, laz2_xmlwrite, laz2_dom, Forms, TypInfo, laz2_xmlread, laz2_xmlwrite, laz2_dom,
mvJobs, mvGpsObj; mvJobs, mvGpsObj;
const
_K = 1024;
_M = _K*_K;
_G = _K*_M;
ZOOM_FACTOR: array[0..32] of Int64 = (
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, // 0..9
_K, 2*_K, 4*_K, 8*_K, 16*_K, 32*_K, 64*_K, 128*_K, 256*_K, 512*_K, // 10..19
_M, 2*_M, 4*_M, 8*_M, 16*_M, 32*_M, 64*_M, 128*_M, 256*_M, 512*_M, // 20..29
_G, 2*_G, 4*_G // 30..32
);
function ZoomFactor(AZoomLevel: Integer): Int64;
begin
if (AZoomLevel >= Low(ZOOM_FACTOR)) and (AZoomLevel < High(ZOOM_FACTOR)) then
Result := ZOOM_FACTOR[AZoomLevel]
else
Result := round(IntPower(2, AZoomLevel));
end;
type type
{ TEnvTile } { TEnvTile }
@ -1474,492 +1431,56 @@ begin
MapWin.MapProvider := MP; // Restore the old Map Provider MapWin.MapProvider := MP; // Restore the old Map Provider
end; end;
//------------------------------------------------------------------------------ {------------------------------------------------------------------------------}
function RealPoint(Lat, Lon: Double): TRealPoint; function DMSToDeg(Deg, Min: Word; Sec: Double): Double;
begin begin
Result.Lon := Lon; Result := mvGeoMath.DMSToDeg(Deg, Min, Sec);
Result.Lat := Lat;
end;
procedure SplitGps(AValue: Double; out ADegs, AMins: Double);
begin
AValue := abs(AValue);
AMins := frac(AValue) * 60;
if abs(AMins - 60) < 1E-3 then
begin
AMins := 0;
ADegs := trunc(AValue) + 1;
end else
ADegs := trunc(AValue);
if AValue < 0 then
ADegs := -ADegs;
end;
procedure SplitGps(AValue: Double; out ADegs, AMins, ASecs: Double);
begin
SplitGps(AValue, ADegs, AMins);
ASecs := frac(AMins) * 60;
AMins := trunc(AMins);
if abs(ASecs - 60) < 1E-3 then
begin
ASecs := 0;
AMins := AMins + 1;
if abs(AMins - 60) < 1e-3 then
begin
AMins := 0;
ADegs := ADegs + 1;
end;
end;
if AValue < 0 then
ADegs := -ADegs;
end; end;
function GPSToDMS(Angle: Double): string; function GPSToDMS(Angle: Double): string;
begin begin
Result := GPSToDMS(Angle, DefaultFormatSettings); Result := mvGeoMath.GPSToDMS(Angle);
end; end;
function GPSToDMS(Angle: Double; AFormatSettings: TFormatSettings): string; function GPSToDMS(Angle: Double; AFormatSettings: TFormatSettings): string;
var
deg, min, sec: Double;
begin begin
SplitGPS(Angle, deg, min, sec); Result := mvGeoMath.GPSToDMS(Angle, AFormatSettings);
Result := Format('%.0f° %.0f'' %.*f"', [deg, min, DMS_Decimals, sec], AFormatSettings);
end; end;
function LatToStr(ALatitude: Double; DMS: Boolean): String; function LatToStr(ALatitude: Double; DMS: Boolean): String;
begin begin
Result := LatToStr(ALatitude, DMS, DefaultFormatSettings); Result := mvGeoMath.LatToStr(ALatitude, DMS);
end; end;
function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String; function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
begin begin
if DMS then Result := mvGeoMath.LatToStr(ALatitude, DMS, AFormatSettings);
Result := GPSToDMS(abs(ALatitude), AFormatSettings)
else
Result := Format('%.6f°',[abs(ALatitude)], AFormatSettings);
if ALatitude > 0 then
Result := Result + ' N'
else
if ALatitude < 0 then
Result := Result + ' S';
end; end;
function LonToStr(ALongitude: Double; DMS: Boolean): String; function LonToStr(ALongitude: Double; DMS: Boolean): String;
begin begin
Result := LonToStr(ALongitude, DMS, DefaultFormatSettings); Result := mvGeoMath.LonToStr(ALongitude, DMS);
end; end;
function LonToStr(ALongitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String; function LonToStr(ALongitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
begin begin
if DMS then Result := mvGeoMath.LonToStr(ALongitude, DMS, AFormatSettings);
Result := GPSToDMS(abs(ALongitude), AFormatSettings)
else
Result := Format('%.6f°', [abs(ALongitude)], AFormatSettings);
if ALongitude > 0 then
Result := Result + ' E'
else if ALongitude < 0 then
Result := Result + ' W';
end; end;
{ Combines up to three parts of a GPS coordinate string (degrees, minutes, seconds)
to a floating-point degree value. The parts are separated by non-numeric
characters:
three parts ---> d m s ---> d and m must be integer, s can be float
two parts ---> d m ---> d must be integer, s can be float
one part ---> d ---> d can be float
Each part can exhibit a unit identifier, such as °, ', or ". BUT: they are
ignored. This means that an input string 50°30" results in the output value 50.5
although the second part is marked as seconds, not minutes!
Hemisphere suffixes ('N', 'S', 'E', 'W') are supported at the end of the input string.
}
function TryStrToGps(const AValue: String; out ADeg: Double): Boolean; function TryStrToGps(const AValue: String; out ADeg: Double): Boolean;
const
NUMERIC_CHARS = ['0'..'9', '.', ',', '-', '+'];
var
mins, secs: Double;
i, j, len: Integer;
n: Integer;
s: String = '';
res: Integer;
sgn: Double;
begin begin
Result := false; Result := mvGeoMath.TryStrToGps(AValue, ADeg);
ADeg := NaN;
mins := 0;
secs := 0;
if AValue = '' then
exit;
len := Length(AValue);
i := len;
while (i >= 1) and (AValue[i] = ' ') do dec(i);
sgn := 1.0;
if (AValue[i] in ['S', 's', 'W', 'w']) then sgn := -1;
// skip leading non-numeric characters
i := 1;
while (i <= len) and not (AValue[i] in NUMERIC_CHARS) do
inc(i);
// extract first value: degrees
SetLength(s, len);
j := 1;
n := 0;
while (i <= len) and (AValue[i] in NUMERIC_CHARS) do begin
if AValue[i] = ',' then s[j] := '.' else s[j] := AValue[i];
inc(i);
inc(j);
inc(n);
end;
if n > 0 then begin
SetLength(s, n);
val(s, ADeg, res);
if res <> 0 then
exit;
end; end;
// skip non-numeric characters between degrees and minutes
while (i <= len) and not (AValue[i] in NUMERIC_CHARS) do
inc(i);
// extract second value: minutes
SetLength(s, len);
j := 1;
n := 0;
while (i <= len) and (AValue[i] in NUMERIC_CHARS) do begin
if AValue[i] = ',' then s[j] := '.' else s[j] := AValue[i];
inc(i);
inc(j);
inc(n);
end;
if n > 0 then begin
SetLength(s, n);
val(s, mins, res);
if (res <> 0) or (mins < 0) then
exit;
end;
// skip non-numeric characters between minutes and seconds
while (i <= len) and not (AValue[i] in NUMERIC_CHARS) do
inc(i);
// extract third value: seconds
SetLength(s, len);
j := 1;
n := 0;
while (i <= len) and (AValue[i] in NUMERIC_CHARS) do begin
if AValue[i] = ',' then s[j] := '.' else s[j] := AValue[i];
inc(i);
inc(j);
inc(n);
end;
if n > 0 then begin
SetLength(s, n);
val(s, secs, res);
if (res <> 0) or (secs < 0) then
exit;
end;
// If the string contains seconds then minutes and deegrees must be integers
if (secs <> 0) and ((frac(ADeg) > 0) or (frac(mins) > 0)) then
exit;
// If the string does not contain seconds then degrees must be integer.
if (secs = 0) and (mins <> 0) and (frac(ADeg) > 0) then
exit;
// If the string contains minutes, but no seconds, then the degrees must be integer.
Result := (mins >= 0) and (mins < 60) and (secs >= 0) and (secs < 60);
// A similar check should be made for the degrees range, but since this is
// different for latitude and longitude the check is skipped here.
if Result then
ADeg := sgn * (abs(ADeg) + mins / 60 + secs / 3600);
end;
{ Convert Lat/Lon string to degrees.
Recognized formats:
Degrees, Minutes and Seconds:
DDD°MM'SS.S"
32°18'23.1"N 122°36'52.5"W
Degrees and Decimal Minutes:
DDD° MM.MMM'
32°18.385'N 122°36.875'W
Decimal Degrees:
DDD.DDDDD°
32.30642°N 122.61458°W
+32.30642 -122.61458
}
function TryStrDMSToDeg(const AValue: String; out ADeg: Double): Boolean; function TryStrDMSToDeg(const AValue: String; out ADeg: Double): Boolean;
const
NUMERIC_CHARS = ['0'..'9', '.', ',', '-', '+'];
WS_CHARS = [' '];
var
I, Len, N: Integer;
S: String;
D, Minutes, Seconds: Double;
R: Word;
Last, Neg: Boolean;
function EOL: Boolean; inline;
begin begin
Result := Len < I; Result := mvGeoMath.TryStrDMSToDeg(AValue, ADeg);
end; end;
procedure SkipWS; inline; function ZoomFactor(AZoomLevel: Integer): Int64;
begin begin
while not EOL and (AValue[I] in WS_CHARS) do Result := mvGeoMath.ZoomFactor(AZoomLevel);
Inc(I);
end;
function NextNum: String;
begin
Result := '';
SkipWS;
while not EOL and (AValue[I] in NUMERIC_CHARS) do
begin
if AValue[I] = ','
then Result := Result + '.'
else Result := Result + AValue[I];
Inc(I);
end;
end;
begin
Result := False;
ADeg := NaN;
Len := Length(AValue);
I := 1;
// Degrees
S := NextNum;
if S = '' then
Exit;
Val(S, ADeg, R);
if R > 0 then
Exit;
// It must be the only part if negative or fractional
Neg := ADeg < 0.0;
Last := Neg or (Frac(ADeg) > 0.0);
// Eat the degree symbol if present
if not EOL and (Utf8CodePointLen(@AValue[I], 2, False) = 2)
and (AValue[I] = #$c2) and (AValue[I + 1] = #$b0)
then
Inc(I, 2);
Minutes := 0.0;
Seconds := 0.0;
N := 1;
while not (EOL or Last) and (N < 3) do
begin
S := NextNum;
if S = '' then
Break
else
begin
Val(S, D, R);
// Invalid part or negative one
if (R > 0) or (D < 0.0) then
Exit;
// No more parts when fractional
Last := Frac(D) > 0.0;
if not EOL then
case AValue[I] of
'''': // Munutes suffix
begin
Minutes := D;
Inc(I); // Eat the '
end;
'"': // Seconds suffix
begin
Seconds := D;
Last := True; // Last part
Inc(I); // Eat the "
end;
otherwise
if N = 1
then Minutes := D
else Seconds := D;
end;
end;
Inc(N);
end;
// Merge parts
ADeg := ADeg + Minutes / 60 + Seconds / 3600;
// Check for N-S and E-W designators
SkipWS;
if not (EOL or Neg) and (AValue[I] in ['S', 's', 'W', 'w', 'N', 'n', 'E', 'e']) then
begin
if AValue[I] in ['S', 's', 'W', 'w']
then ADeg := -1 * ADeg;
Inc(I);
end;
SkipWS;
// It must be entirely consumed
Result := EOL;
end;
// https://stackoverflow.com/questions/73608975/pascal-delphi-11-formula-for-distance-in-meters-between-two-decimal-gps-point
function HaversineDist(Lat1, Lon1, Lat2, Lon2, Radius: Double): Double;
var
latFrom, latTo, lonDiff: Double;
dx, dy, dz: Double;
begin
lonDiff := DegToRad(Lon1 - Lon2);
latFrom := DegToRad(Lat1);
latTo := DegToRad(Lat2);
dz := sin(latFrom) - sin(latTo);
dx := cos(lonDiff) * cos(latFrom) - cos(latTo);
dy := sin(lonDiff) * cos(latFrom);
Result := arcsin(sqrt(sqr(dx) + sqr(dy) + sqr(dz)) / 2) * Radius * 2;
end;
{ Returns the direct distance (air-line) between two geo coordinates
If latitude NOT between -90°..+90° and longitude NOT between -180°..+180°
the function returns NaN.
Usage: CalcGeoDistance(51.53323, -2.90130, 51.29442, -2.27275, duKilometers);
}
function CalcGeoDistance(Lat1, Lon1, Lat2, Lon2: double;
AUnits: TDistanceUnits = duKilometers): double;
begin
// Validate
if (Lat1 < -90.0) or (Lat1 > 90.0) then exit(NaN);
if (Lat2 < -90.0) or (Lat2 > 90.0) then exit(NaN);
Result := HaversineDist(Lat1, Lon1, Lat2, Lon2, EARTH_EQUATORIAL_RADIUS);
case AUnits of
duMeters: ;
duKilometers: Result := Result * 1E-3;
duMiles: Result := Result * 0.62137E-3;
end;
end;
{ Calculate initial bearing (in °) from the start point Lat1,Lon1 to
the end point Lat2,Lon2. No parameter checks, result normalized to 0°..360°.
}
function CalcBearing(Lat1, Lon1, Lat2, Lon2: Double): Double;
var
latFrom, latTo, lonDiff: Double;
begin
lonDiff := DegToRad(Lon2 - Lon1);
latFrom := DegToRad(Lat1);
latTo := DegToRad(Lat2);
Result := ArcTan2(Sin(lonDiff) * Cos(latTo),
Cos(latFrom) * Sin(latTo) - Sin(latFrom) * Cos(latTo) * Cos(lonDiff));
Result := RadToDeg(Result);
if Result < 0.0 then
Result := Result + 360.0;
end;
{ Calculate end point Lat2,Lon2 by given start point Lat1,Lon1, distance
ADist (in meters) and bearing ABearing (in °). No parameter checks,
result Lon2 normalized to -180°..180°.
}
procedure CalcLatLon(const Lat1, Lon1, ADist, ABearing: Double; out Lat2,
Lon2: Double);
var
latFrom, lonFrom, brng, aD: Double;
begin
latFrom := DegToRad(Lat1);
lonFrom := DegToRad(Lon1);
brng := DegToRad(ABearing);
aD := ADist / EARTH_EQUATORIAL_RADIUS;
Lat2 := ArcSin(Sin(latFrom) * Cos(aD) + Cos(latFrom) * Sin(aD) * Cos(brng));
Lon2 := lonFrom + ArcTan2(Sin(brng) * Sin(aD) * Cos(latFrom),
Cos(aD) - Sin(latFrom) * Sin(Lat2));
Lat2 := RadToDeg(Lat2);
Lon2 := NormalizeLon(RadToDeg(Lon2));
end;
{ Calculate midpoint Lat,Lon by given start point Lat1,Lon1 and end point
Lat2,Lon2. No parameter checks, result Lon normalized to -180°..180°.
}
procedure CalcMidpoint(const Lat1, Lon1, Lat2, Lon2: Double; out Lat,
Lon: Double);
var
latFrom, lonDiff, latTo, lonTo, Bx, By: Double;
begin
lonDiff := DegToRad(Lon2 - Lon1);
latFrom := DegToRad(Lat1);
latTo := DegToRad(Lat2);
lonTo := DegToRad(Lon2);
Bx := Cos(latTo) * Cos(lonDiff);
By := Cos(latTo) * Sin(lonDiff);
Lat := ArcTan2(Sin(latFrom) + Sin(latTo), Sqrt(Sqr(Cos(latFrom) + Bx) + Sqr(By)));
Lon := lonTo + ArcTan2(By, Cos(latFrom) + By);
Lat := RadToDeg(Lat);
Lon := NormalizeLon(RadToDeg(Lon));
end;
{ Calculate intermediate point Lat,Lon by given start point Lat1,Lon1, end point
Lat2,Lon2 and fraction AFrac (0.0-1.0). No parameter checks for
Lat1,Lon1,Lat2 and Lon2. Result Lon normalized to -180°..180°.
}
procedure CalcIntermedPoint(const Lat1, Lon1, Lat2, Lon2, AFrac: Double; out
Lat, Lon: Double);
var
latFrom, lonFrom, latTo, lonTo: Double;
A, B, aD, X, Y, Z: Double;
begin
if (Lat1 = Lat2) and (Lon1 = Lon2) or (AFrac < 0.001) then
begin
Lat := Lat1;
Lon := Lon1;
Exit;
end;
if AFrac > 0.999 then
begin
Lat := Lat2;
Lon := Lon2;
Exit;
end;
aD := CalcGeoDistance(Lat1, Lon1, Lat2, Lon2) / EARTH_EQUATORIAL_RADIUS;
latFrom := DegToRad(Lat1);
lonFrom := DegToRad(Lon1);
latTo := DegToRad(Lat2);
lonTo := DegToRad(Lon2);
A := Sin((1.0 - AFrac) * aD) / Sin(aD);
B := Sin(AFrac * aD) / Sin(aD);
X := A * Cos(latFrom) * Cos(lonFrom) + B * Cos(latTo) * Cos(lonTo);
Y := A * Cos(latFrom) * Sin(lonFrom) + B * Cos(latTo) * Sin(lonTo);
Z := A * Sin(latFrom) + B * Sin(latTo);
Lat := ArcTan2(Z, Sqrt(Sqr(X) + Sqr(Y)));
Lon := ArcTan2(Y, X);
Lat := RadToDeg(Lat);
Lon := NormalizeLon(RadToDeg(Lon));
end;
function NormalizeLon(const Lon: Double): Double;
begin
if InRange(Lon, -180.0, 180.0)
then Result := Lon
else Result := FMod(Lon + 540.0, 360.0) - 180.0;
end;
{ Converts an angle given as degrees, minutes and seconds to a single
floating point degrees value. }
function DMSToDeg(Deg, Min: Word; Sec: Double): Double;
begin
Result := Deg + Min/60.0 + Sec/3600.0;
end; end;
end. end.

View File

@ -0,0 +1,601 @@
unit mvGeoMath;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Math;
const
EARTH_EQUATORIAL_RADIUS = 6378137;
EARTH_POLAR_RADIUS = 6356752.3142;
EARTH_CIRCUMFERENCE = 2 * pi * EARTH_EQUATORIAL_RADIUS;
EARTH_ECCENTRICITY = sqrt(1 - sqr(EARTH_POLAR_RADIUS / EARTH_EQUATORIAL_RADIUS));
EARTH_FLATTENING = 1.0 - EARTH_POLAR_RADIUS / EARTH_EQUATORIAL_RADIUS;
DMS_Decimals: Integer = 1;
type
TDistanceUnits = (duMeters, duKilometers, duMiles);
TEarthShape = (esSphere, esEllipsoid);
function NormalizeLon(const Lon: Double): Double; inline;
function HaversineDist(Lat1, Lon1, Lat2, Lon2, Radius: Double): Double;
function LambertsDist(Lat1, Lon1, Lat2, Lon2, Radius, Flattening: Double): Double;
function CalcGeoDistance(Lat1, Lon1, Lat2, Lon2: double;
AUnits: TDistanceUnits = duKilometers; AShape: TEarthShape = esSphere): double;
function CalcBearing(Lat1, Lon1, Lat2, Lon2: Double): Double;
procedure CalcLatLon(const Lat1, Lon1, ADist, ABearing: Double; out Lat2, Lon2: Double);
procedure CalcMidpoint(const Lat1, Lon1, Lat2, Lon2: Double; out Lat, Lon: Double);
procedure CalcIntermedPoint(const Lat1, Lon1, Lat2, Lon2, AFrac: Double; out Lat, Lon: Double);
function DMSToDeg(Deg, Min: Word; Sec: Double): Double;
function GPSToDMS(Angle: Double): string;
function GPSToDMS(Angle: Double; AFormatSettings: TFormatSettings): string;
function LatToStr(ALatitude: Double; DMS: Boolean): String;
function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
function LonToStr(ALongitude: Double; DMS: Boolean): String;
function LonToStr(ALongitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
function TryStrToGps(const AValue: String; out ADeg: Double): Boolean;
function TryStrDMSToDeg(const AValue: String; out ADeg: Double): Boolean;
procedure SplitGps(AValue: Double; out ADegs, AMins, ASecs: Double);
function ZoomFactor(AZoomLevel: Integer): Int64;
implementation
const
_K = 1024;
_M = _K*_K;
_G = _K*_M;
ZOOM_FACTOR: array[0..32] of Int64 = (
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, // 0..9
_K, 2*_K, 4*_K, 8*_K, 16*_K, 32*_K, 64*_K, 128*_K, 256*_K, 512*_K, // 10..19
_M, 2*_M, 4*_M, 8*_M, 16*_M, 32*_M, 64*_M, 128*_M, 256*_M, 512*_M, // 20..29
_G, 2*_G, 4*_G // 30..32
);
function ZoomFactor(AZoomLevel: Integer): Int64;
begin
if (AZoomLevel >= Low(ZOOM_FACTOR)) and (AZoomLevel < High(ZOOM_FACTOR)) then
Result := ZOOM_FACTOR[AZoomLevel]
else
Result := round(IntPower(2, AZoomLevel));
end;
{ Calculation of distance on a sphere
https://stackoverflow.com/questions/73608975/pascal-delphi-11-formula-for-distance-in-meters-between-two-decimal-gps-point
}
// angles in radians
function HaversineAngle(Lat1, Lon1, Lat2, Lon2: Double): Double;
var
latFrom, latTo, lonDiff: Double;
dx, dy, dz: Double;
begin
lonDiff := Lon1 - Lon2;
latFrom := Lat1;
latTo := Lat2;
dz := sin(latFrom) - sin(latTo);
dx := cos(lonDiff) * cos(latFrom) - cos(latTo);
dy := sin(lonDiff) * cos(latFrom);
Result := arcsin(sqrt(sqr(dx) + sqr(dy) + sqr(dz)) / 2.0) * 2.0;
end;
// Angles in degrees
function HaversineDist(Lat1, Lon1, Lat2, Lon2, Radius: Double): Double;
begin
Result := HaversineAngle(DegToRad(Lat1), DegToRad(Lon1), DegToRad(Lat2), DegToRad(Lon2)) * Radius;
end;
{ Calculation of distance on an ellipsoid
https://en.wikipedia.org/wiki/Geographical_distance
}
// Angles in degrees
function LambertsDist(Lat1, Lon1, Lat2, Lon2, Radius, Flattening: Double): Double;
var
reducedLat1, reducedLat2, sigma: Double;
P, Q: Double;
X, Y: Double;
sinP, cosP, sinQ, cosQ: Double;
sinSigma, sinSigma2, cosSigma2: Double;
begin
Lat1 := DegToRad(Lat1);
Lon1 := DegToRad(Lon1);
Lat2 := DegToRad(Lat2);
Lon2 := DegToRad(Lon2);
reducedLat1 := arctan((1.0 - flattening) * tan(Lat1));
reducedLat2 := arctan((1.0 - flattening) * tan(Lat2));
sigma := HaversineAngle(reducedLat1, Lon1, reducedLat2, Lon2);
P := (reducedLat1 + reducedLat2) * 0.5;
Q := (reducedLat2 - reducedLat1) * 0.5;
SinCos(P, sinP, cosP);
SinCos(Q, sinQ, cosQ);
SinCos(sigma*0.5, sinSigma2, cosSigma2);
sinSigma := sin(sigma);
X := (sigma - sinSigma) * sqr(sinP * cosQ / cosSigma2);
Y := (sigma + sinSigma) * sqr(cosP * sinQ / sinSigma2);
Result := (sigma - 0.5*Flattening*(X + Y)) * Radius;
end;
{ Returns the direct distance (air-line) between two geo coordinates
If latitude is NOT between -90°..+90° and longitude is NOT between -180°..+180°
the function returns NaN.
Usage example:
CalcGeoDistance(51.53323, -2.90130, 51.29442, -2.27275, duKilometers, esEllipsoid);
}
function CalcGeoDistance(Lat1, Lon1, Lat2, Lon2: double;
AUnits: TDistanceUnits = duKilometers; AShape: TEarthShape = esSphere): double;
begin
// Validate
if (Lat1 < -90.0) or (Lat1 > 90.0) then exit(NaN);
if (Lat2 < -90.0) or (Lat2 > 90.0) then exit(NaN);
case AShape of
esSphere:
Result := HaversineDist(Lat1, Lon1, Lat2, Lon2, EARTH_EQUATORIAL_RADIUS);
esEllipsoid:
Result := LambertsDist(Lat1, Lon1, Lat2, Lon2, EARTH_EQUATORIAL_RADIUS, EARTH_FLATTENING);
end;
case AUnits of
duMeters: ;
duKilometers: Result := Result * 0.001;
duMiles: Result := Result * 0.62137E-3;
end;
end;
{ Calculate initial bearing (in °) from the start point Lat1,Lon1 to
the end point Lat2,Lon2. No parameter checks, result normalized to 0°..360°.
}
function CalcBearing(Lat1, Lon1, Lat2, Lon2: Double): Double;
var
latFrom, latTo, lonDiff: Double;
begin
lonDiff := DegToRad(Lon2 - Lon1);
latFrom := DegToRad(Lat1);
latTo := DegToRad(Lat2);
Result := ArcTan2(Sin(lonDiff) * Cos(latTo),
Cos(latFrom) * Sin(latTo) - Sin(latFrom) * Cos(latTo) * Cos(lonDiff));
Result := RadToDeg(Result);
if Result < 0.0 then
Result := Result + 360.0;
end;
{ Calculate end point Lat2,Lon2 by given start point Lat1,Lon1, distance
ADist (in meters) and bearing ABearing (in °). No parameter checks,
result Lon2 normalized to -180°..180°.
}
procedure CalcLatLon(const Lat1, Lon1, ADist, ABearing: Double; out Lat2,
Lon2: Double);
var
latFrom, lonFrom, brng, aD: Double;
begin
latFrom := DegToRad(Lat1);
lonFrom := DegToRad(Lon1);
brng := DegToRad(ABearing);
aD := ADist / EARTH_EQUATORIAL_RADIUS;
Lat2 := ArcSin(Sin(latFrom) * Cos(aD) + Cos(latFrom) * Sin(aD) * Cos(brng));
Lon2 := lonFrom + ArcTan2(Sin(brng) * Sin(aD) * Cos(latFrom),
Cos(aD) - Sin(latFrom) * Sin(Lat2));
Lat2 := RadToDeg(Lat2);
Lon2 := NormalizeLon(RadToDeg(Lon2));
end;
{ Calculate midpoint Lat,Lon by given start point Lat1,Lon1 and end point
Lat2,Lon2. No parameter checks, result Lon normalized to -180°..180°.
}
procedure CalcMidpoint(const Lat1, Lon1, Lat2, Lon2: Double; out Lat,
Lon: Double);
var
latFrom, lonDiff, latTo, lonTo, Bx, By: Double;
begin
lonDiff := DegToRad(Lon2 - Lon1);
latFrom := DegToRad(Lat1);
latTo := DegToRad(Lat2);
lonTo := DegToRad(Lon2);
Bx := Cos(latTo) * Cos(lonDiff);
By := Cos(latTo) * Sin(lonDiff);
Lat := ArcTan2(Sin(latFrom) + Sin(latTo), Sqrt(Sqr(Cos(latFrom) + Bx) + Sqr(By)));
Lon := lonTo + ArcTan2(By, Cos(latFrom) + By);
Lat := RadToDeg(Lat);
Lon := NormalizeLon(RadToDeg(Lon));
end;
{ Calculate intermediate point Lat,Lon by given start point Lat1,Lon1, end point
Lat2,Lon2 and fraction AFrac (0.0-1.0). No parameter checks for
Lat1,Lon1,Lat2 and Lon2. Result Lon normalized to -180°..180°.
}
procedure CalcIntermedPoint(const Lat1, Lon1, Lat2, Lon2, AFrac: Double; out
Lat, Lon: Double);
var
latFrom, lonFrom, latTo, lonTo: Double;
A, B, aD, X, Y, Z: Double;
begin
if (Lat1 = Lat2) and (Lon1 = Lon2) or (AFrac < 0.001) then
begin
Lat := Lat1;
Lon := Lon1;
Exit;
end;
if AFrac > 0.999 then
begin
Lat := Lat2;
Lon := Lon2;
Exit;
end;
aD := CalcGeoDistance(Lat1, Lon1, Lat2, Lon2) / EARTH_EQUATORIAL_RADIUS;
latFrom := DegToRad(Lat1);
lonFrom := DegToRad(Lon1);
latTo := DegToRad(Lat2);
lonTo := DegToRad(Lon2);
A := Sin((1.0 - AFrac) * aD) / Sin(aD);
B := Sin(AFrac * aD) / Sin(aD);
X := A * Cos(latFrom) * Cos(lonFrom) + B * Cos(latTo) * Cos(lonTo);
Y := A * Cos(latFrom) * Sin(lonFrom) + B * Cos(latTo) * Sin(lonTo);
Z := A * Sin(latFrom) + B * Sin(latTo);
Lat := ArcTan2(Z, Sqrt(Sqr(X) + Sqr(Y)));
Lon := ArcTan2(Y, X);
Lat := RadToDeg(Lat);
Lon := NormalizeLon(RadToDeg(Lon));
end;
function NormalizeLon(const Lon: Double): Double;
begin
if InRange(Lon, -180.0, 180.0)
then Result := Lon
else Result := FMod(Lon + 540.0, 360.0) - 180.0;
end;
{ Converts an angle given as degrees, minutes and seconds to a single
floating point degrees value. }
function DMSToDeg(Deg, Min: Word; Sec: Double): Double;
begin
Result := Deg + Min/60.0 + Sec/3600.0;
end;
procedure SplitGps(AValue: Double; out ADegs, AMins: Double);
begin
AValue := abs(AValue);
AMins := frac(AValue) * 60;
if abs(AMins - 60) < 1E-3 then
begin
AMins := 0;
ADegs := trunc(AValue) + 1;
end else
ADegs := trunc(AValue);
if AValue < 0 then
ADegs := -ADegs;
end;
procedure SplitGps(AValue: Double; out ADegs, AMins, ASecs: Double);
begin
SplitGps(AValue, ADegs, AMins);
ASecs := frac(AMins) * 60;
AMins := trunc(AMins);
if abs(ASecs - 60) < 1E-3 then
begin
ASecs := 0;
AMins := AMins + 1;
if abs(AMins - 60) < 1e-3 then
begin
AMins := 0;
ADegs := ADegs + 1;
end;
end;
if AValue < 0 then
ADegs := -ADegs;
end;
function GPSToDMS(Angle: Double): string;
begin
Result := GPSToDMS(Angle, DefaultFormatSettings);
end;
function GPSToDMS(Angle: Double; AFormatSettings: TFormatSettings): string;
var
deg, min, sec: Double;
begin
SplitGPS(Angle, deg, min, sec);
Result := Format('%.0f° %.0f'' %.*f"', [deg, min, DMS_Decimals, sec], AFormatSettings);
end;
function LatToStr(ALatitude: Double; DMS: Boolean): String;
begin
Result := LatToStr(ALatitude, DMS, DefaultFormatSettings);
end;
function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
begin
if DMS then
Result := GPSToDMS(abs(ALatitude), AFormatSettings)
else
Result := Format('%.6f°',[abs(ALatitude)], AFormatSettings);
if ALatitude > 0 then
Result := Result + ' N'
else
if ALatitude < 0 then
Result := Result + ' S';
end;
function LonToStr(ALongitude: Double; DMS: Boolean): String;
begin
Result := LonToStr(ALongitude, DMS, DefaultFormatSettings);
end;
function LonToStr(ALongitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String;
begin
if DMS then
Result := GPSToDMS(abs(ALongitude), AFormatSettings)
else
Result := Format('%.6f°', [abs(ALongitude)], AFormatSettings);
if ALongitude > 0 then
Result := Result + ' E'
else if ALongitude < 0 then
Result := Result + ' W';
end;
{ Combines up to three parts of a GPS coordinate string (degrees, minutes, seconds)
to a floating-point degree value. The parts are separated by non-numeric
characters:
three parts ---> d m s ---> d and m must be integer, s can be float
two parts ---> d m ---> d must be integer, s can be float
one part ---> d ---> d can be float
Each part can exhibit a unit identifier, such as °, ', or ". BUT: they are
ignored. This means that an input string 50°30" results in the output value 50.5
although the second part is marked as seconds, not minutes!
Hemisphere suffixes ('N', 'S', 'E', 'W') are supported at the end of the input string.
}
function TryStrToGps(const AValue: String; out ADeg: Double): Boolean;
const
NUMERIC_CHARS = ['0'..'9', '.', ',', '-', '+'];
var
mins, secs: Double;
i, j, len: Integer;
n: Integer;
s: String = '';
res: Integer;
sgn: Double;
begin
Result := false;
ADeg := NaN;
mins := 0;
secs := 0;
if AValue = '' then
exit;
len := Length(AValue);
i := len;
while (i >= 1) and (AValue[i] = ' ') do dec(i);
sgn := 1.0;
if (AValue[i] in ['S', 's', 'W', 'w']) then sgn := -1;
// skip leading non-numeric characters
i := 1;
while (i <= len) and not (AValue[i] in NUMERIC_CHARS) do
inc(i);
// extract first value: degrees
SetLength(s, len);
j := 1;
n := 0;
while (i <= len) and (AValue[i] in NUMERIC_CHARS) do begin
if AValue[i] = ',' then s[j] := '.' else s[j] := AValue[i];
inc(i);
inc(j);
inc(n);
end;
if n > 0 then begin
SetLength(s, n);
val(s, ADeg, res);
if res <> 0 then
exit;
end;
// skip non-numeric characters between degrees and minutes
while (i <= len) and not (AValue[i] in NUMERIC_CHARS) do
inc(i);
// extract second value: minutes
SetLength(s, len);
j := 1;
n := 0;
while (i <= len) and (AValue[i] in NUMERIC_CHARS) do begin
if AValue[i] = ',' then s[j] := '.' else s[j] := AValue[i];
inc(i);
inc(j);
inc(n);
end;
if n > 0 then begin
SetLength(s, n);
val(s, mins, res);
if (res <> 0) or (mins < 0) then
exit;
end;
// skip non-numeric characters between minutes and seconds
while (i <= len) and not (AValue[i] in NUMERIC_CHARS) do
inc(i);
// extract third value: seconds
SetLength(s, len);
j := 1;
n := 0;
while (i <= len) and (AValue[i] in NUMERIC_CHARS) do begin
if AValue[i] = ',' then s[j] := '.' else s[j] := AValue[i];
inc(i);
inc(j);
inc(n);
end;
if n > 0 then begin
SetLength(s, n);
val(s, secs, res);
if (res <> 0) or (secs < 0) then
exit;
end;
// If the string contains seconds then minutes and deegrees must be integers
if (secs <> 0) and ((frac(ADeg) > 0) or (frac(mins) > 0)) then
exit;
// If the string does not contain seconds then degrees must be integer.
if (secs = 0) and (mins <> 0) and (frac(ADeg) > 0) then
exit;
// If the string contains minutes, but no seconds, then the degrees must be integer.
Result := (mins >= 0) and (mins < 60) and (secs >= 0) and (secs < 60);
// A similar check should be made for the degrees range, but since this is
// different for latitude and longitude the check is skipped here.
if Result then
ADeg := sgn * (abs(ADeg) + mins / 60 + secs / 3600);
end;
{ Convert Lat/Lon string to degrees.
Recognized formats:
Degrees, Minutes and Seconds:
DDD°MM'SS.S"
32°18'23.1"N 122°36'52.5"W
Degrees and Decimal Minutes:
DDD° MM.MMM'
32°18.385'N 122°36.875'W
Decimal Degrees:
DDD.DDDDD°
32.30642°N 122.61458°W
+32.30642 -122.61458
}
function TryStrDMSToDeg(const AValue: String; out ADeg: Double): Boolean;
const
NUMERIC_CHARS = ['0'..'9', '.', ',', '-', '+'];
WS_CHARS = [' '];
var
I, Len, N: Integer;
S: String;
D, Minutes, Seconds: Double;
R: Word;
Last, Neg: Boolean;
function EOL: Boolean; inline;
begin
Result := Len < I;
end;
procedure SkipWS; inline;
begin
while not EOL and (AValue[I] in WS_CHARS) do
Inc(I);
end;
function NextNum: String;
begin
Result := '';
SkipWS;
while not EOL and (AValue[I] in NUMERIC_CHARS) do
begin
if AValue[I] = ','
then Result := Result + '.'
else Result := Result + AValue[I];
Inc(I);
end;
end;
begin
Result := False;
ADeg := NaN;
Len := Length(AValue);
I := 1;
// Degrees
S := NextNum;
if S = '' then
Exit;
Val(S, ADeg, R);
if R > 0 then
Exit;
// It must be the only part if negative or fractional
Neg := ADeg < 0.0;
Last := Neg or (Frac(ADeg) > 0.0);
// Eat the degree symbol if present
if not EOL and (Utf8CodePointLen(@AValue[I], 2, False) = 2)
and (AValue[I] = #$c2) and (AValue[I + 1] = #$b0)
then
Inc(I, 2);
Minutes := 0.0;
Seconds := 0.0;
N := 1;
while not (EOL or Last) and (N < 3) do
begin
S := NextNum;
if S = '' then
Break
else
begin
Val(S, D, R);
// Invalid part or negative one
if (R > 0) or (D < 0.0) then
Exit;
// No more parts when fractional
Last := Frac(D) > 0.0;
if not EOL then
case AValue[I] of
'''': // Munutes suffix
begin
Minutes := D;
Inc(I); // Eat the '
end;
'"': // Seconds suffix
begin
Seconds := D;
Last := True; // Last part
Inc(I); // Eat the "
end;
otherwise
if N = 1
then Minutes := D
else Seconds := D;
end;
end;
Inc(N);
end;
// Merge parts
ADeg := ADeg + Minutes / 60 + Seconds / 3600;
// Check for N-S and E-W designators
SkipWS;
if not (EOL or Neg) and (AValue[I] in ['S', 's', 'W', 'w', 'N', 'n', 'E', 'e']) then
begin
if AValue[I] in ['S', 's', 'W', 'w']
then ADeg := -1 * ADeg;
Inc(I);
end;
SkipWS;
// It must be entirely consumed
Result := EOL;
end;
end.

View File

@ -16,7 +16,8 @@ unit mvGpsObj;
interface interface
uses uses
Classes, SysUtils, Graphics, fgl, mvtypes, contnrs, syncobjs; Classes, SysUtils, Graphics, fgl, contnrs, syncobjs,
mvTypes, mvGeoMath;
const const
NO_ELE = -10000000; NO_ELE = -10000000;
@ -1013,6 +1014,21 @@ begin
Result := FDateTime <> NO_DATE; Result := FDateTime <> NO_DATE;
end; end;
function TGPSPoint.DistanceInKmFrom(OtherPt: TGPSPoint;
UseElevation: Boolean = true): Double;
var
lat1, lon1, lat2, lon2: Double;
dElev: Double;
begin
Result := CalcGeoDistance(Lat, Lon, OtherPt.Lat, OtherPt.Lon, duKilometers, esEllipsoid);
if UseElevation and HasElevation and OtherPt.HasElevation and (FElevation <> OtherPt.Elevation) then
begin
dElev := (FElevation - OtherPt.Elevation) * 0.001; // Elevation is given in meters
Result := sqrt(sqr(dElev) + sqr(Result));
end;
end;
(*
function TGPSPoint.DistanceInKmFrom(OtherPt: TGPSPoint; function TGPSPoint.DistanceInKmFrom(OtherPt: TGPSPoint;
UseElevation: boolean = true): double; UseElevation: boolean = true): double;
var var
@ -1031,6 +1047,12 @@ begin
t3 := cos(lon1 - lon2); t3 := cos(lon1 - lon2);
t4 := t2 * t3; t4 := t2 * t3;
t5 := t1 + t4; t5 := t1 + t4;
if t5 >= 1.0 then
rad_dist := 0.0
else
if t5 <= 1.0 then
rad_dist := pi
else
rad_dist := arctan(-t5/sqrt(-t5 * t5 + 1)) + 2 * arctan(1); rad_dist := arctan(-t5/sqrt(-t5 * t5 + 1)) + 2 * arctan(1);
result := (rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446; result := (rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446;
if UseElevation and (FElevation <> OtherPt.FElevation) then if UseElevation and (FElevation <> OtherPt.FElevation) then
@ -1041,6 +1063,7 @@ begin
Result := sqrt(DiffEle*DiffEle + result*result); Result := sqrt(DiffEle*DiffEle + result*result);
end; end;
end; end;
*)
procedure TGPSPoint.MoveTo(ALon, ALat: Double; AElevation: double = NO_ELE; procedure TGPSPoint.MoveTo(ALon, ALat: Double; AElevation: double = NO_ELE;
ADateTime: TDateTime = NO_DATE); ADateTime: TDateTime = NO_DATE);

View File

@ -29,8 +29,8 @@ interface
uses uses
Classes, SysUtils, Controls, GraphType, Graphics, FPImage, IntfGraphics, Classes, SysUtils, Controls, GraphType, Graphics, FPImage, IntfGraphics,
Forms, ImgList, LCLVersion, fgl, Forms, ImgList, LCLVersion, fgl,
MvTypes, MvGPSObj, MvEngine, MvMapProvider, MvDownloadEngine, MvDrawingEngine, MvTypes, MvGeoMath, MvGPSObj, MvCache, MvExtraData, MvEngine, MvMapProvider,
mvCache, mvExtraData; MvDownloadEngine, MvDrawingEngine;
Type Type

View File

@ -78,8 +78,9 @@ procedure Register;
implementation implementation
uses uses
Dialogs, IDEWindowIntf, mvMapViewer, mvGpsObj, mvLayersPropEditForm, mvEngine, Dialogs, IDEWindowIntf,
StrUtils; StrUtils,
mvGeoMath, mvMapViewer, mvGpsObj, mvLayersPropEditForm, mvEngine;
const const
NONE = '(none)'; NONE = '(none)';

View File

@ -63,6 +63,8 @@ Type
function Union(const Area: TRealArea): TRealArea; function Union(const Area: TRealArea): TRealArea;
end; end;
function RealPoint(Lat, Lon: Double): TRealPoint;
implementation implementation
@ -276,6 +278,12 @@ begin
Self.Lat := RadToDeg(AValue); Self.Lat := RadToDeg(AValue);
end; end;
function RealPoint(Lat, Lon: Double): TRealPoint;
begin
Result.Lon := Lon;
Result.Lat := Lat;
end;
{ TRealArea { TRealArea

View File

@ -8,7 +8,6 @@
<Title Value="mapviewer_tests"/> <Title Value="mapviewer_tests"/>
<ResourceType Value="res"/> <ResourceType Value="res"/>
<UseXPManifest Value="True"/> <UseXPManifest Value="True"/>
<Icon Value="0"/>
</General> </General>
<BuildModes> <BuildModes>
<Item Name="Default" Default="True"/> <Item Name="Default" Default="True"/>
@ -41,7 +40,7 @@
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
<Unit> <Unit>
<Filename Value="mvtests_engine.pas"/> <Filename Value="mvtests_geomath.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
</Units> </Units>

View File

@ -4,7 +4,7 @@ program mapviewer_tests;
uses uses
Interfaces, Forms, GuiTestRunner, Interfaces, Forms, GuiTestRunner,
mvtests_engine, mvtests_types; mvtests_geomath, mvtests_types;
{$R *.res} {$R *.res}

View File

@ -1,4 +1,4 @@
unit mvtests_engine; unit mvtests_geomath;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
@ -8,7 +8,7 @@ uses
Classes, SysUtils, fpcunit, testutils, testregistry; Classes, SysUtils, fpcunit, testutils, testregistry;
type type
TMvTests_Engine= class(TTestCase) TMvTests_GeoMath = class(TTestCase)
published published
procedure Test_Distance; procedure Test_Distance;
procedure Test_LatToStr_DMS; procedure Test_LatToStr_DMS;
@ -22,7 +22,7 @@ type
implementation implementation
uses uses
Math, mvEngine; Math, mvGeoMath;
type type
TDistanceRec = record TDistanceRec = record
@ -94,7 +94,7 @@ const
var var
PointFormatsettings: TFormatSettings; PointFormatsettings: TFormatSettings;
procedure TMvTests_Engine.Test_Distance; procedure TMvTests_GeoMath.Test_Distance;
const const
TOLERANCE = 2; TOLERANCE = 2;
RADIUS = 6378; // Earth radius in km, as used by the references RADIUS = 6378; // Earth radius in km, as used by the references
@ -110,7 +110,7 @@ begin
); );
end; end;
procedure TMvTests_Engine.Test_LatToStr_Deg; procedure TMvTests_GeoMath.Test_LatToStr_Deg;
const const
NO_DMS = false; NO_DMS = false;
var var
@ -125,7 +125,7 @@ begin
); );
end; end;
procedure TMvTests_Engine.Test_LatToStr_DMS; procedure TMvTests_GeoMath.Test_LatToStr_DMS;
const const
NEED_DMS = true; NEED_DMS = true;
var var
@ -140,7 +140,7 @@ begin
); );
end; end;
procedure TMvTests_Engine.Test_LonToStr_Deg; procedure TMvTests_GeoMath.Test_LonToStr_Deg;
const const
NO_DMS = false; NO_DMS = false;
var var
@ -155,7 +155,7 @@ begin
); );
end; end;
procedure TMvTests_Engine.Test_LonToStr_DMS; procedure TMvTests_GeoMath.Test_LonToStr_DMS;
const const
NEED_DMS = true; NEED_DMS = true;
var var
@ -170,7 +170,7 @@ begin
); );
end; end;
procedure TMvTests_Engine.Test_SplitGPS; procedure TMvTests_GeoMath.Test_SplitGPS;
const const
TOLERANCE = 1e-5; TOLERANCE = 1e-5;
var var
@ -218,7 +218,7 @@ begin
end; end;
end; end;
procedure TMvTests_Engine.Test_ZoomFactor; procedure TMvTests_GeoMath.Test_ZoomFactor;
var var
z: Integer; z: Integer;
f: Extended; f: Extended;
@ -236,6 +236,6 @@ initialization
PointFormatSettings.DecimalSeparator := '.'; PointFormatSettings.DecimalSeparator := '.';
DMS_Decimals := 4; DMS_Decimals := 4;
RegisterTest(TMvTests_Engine); RegisterTest(TMvTests_GeoMath);
end. end.

View File

@ -9,7 +9,7 @@ uses
type type
TMvTestsArea= class(TTestCase) TMvTests_Area= class(TTestCase)
published published
procedure Test_PointInArea; procedure Test_PointInArea;
procedure Test_Intersection; procedure Test_Intersection;
@ -28,7 +28,7 @@ begin
]); ]);
end; end;
procedure TMvTestsArea.Test_PointInArea; procedure TMvTests_Area.Test_PointInArea;
var var
counter: Integer; counter: Integer;
a: TRealArea; a: TRealArea;
@ -123,7 +123,7 @@ begin
); );
end; end;
procedure TMvTestsArea.Test_Union; procedure TMvTests_Area.Test_Union;
var var
counter: Integer; counter: Integer;
a, b, expected, actual: TRealArea; a, b, expected, actual: TRealArea;
@ -298,7 +298,7 @@ begin
); );
end; end;
procedure TMvTestsArea.Test_Intersection; procedure TMvTests_Area.Test_Intersection;
var var
counter: Integer; counter: Integer;
a, b, expected, actual: TRealArea; a, b, expected, actual: TRealArea;
@ -430,7 +430,7 @@ end;
initialization initialization
RegisterTest(TMvTestsArea); RegisterTest(TMvTests_Area);
end. end.