diff --git a/components/lazmapviewer/examples/elevations/main.pas b/components/lazmapviewer/examples/elevations/main.pas index 1c5ecd987..0aebb61fc 100644 --- a/components/lazmapviewer/examples/elevations/main.pas +++ b/components/lazmapviewer/examples/elevations/main.pas @@ -7,8 +7,8 @@ interface uses Classes, SysUtils, LazFileUtils, LCLIntf, Forms, Controls, Graphics, Dialogs, StdCtrls, - ExtCtrls, Grids, Buttons, mvMapViewer, mvTypes, mvEngine, Types, mvGpsObj, - mvDrawingEngine; + ExtCtrls, Grids, Buttons, Types, + mvMapViewer, mvTypes, mvGeoMath, mvEngine, mvGpsObj, mvDrawingEngine; type { TMainForm } diff --git a/components/lazmapviewer/examples/flights/main.lfm b/components/lazmapviewer/examples/flights/main.lfm index b08fb0b93..916af5e77 100644 --- a/components/lazmapviewer/examples/flights/main.lfm +++ b/components/lazmapviewer/examples/flights/main.lfm @@ -6,9 +6,10 @@ object MainForm: TMainForm Caption = 'Flights - LazMapViewer' ClientHeight = 662 ClientWidth = 942 + ShowHint = True + LCLVersion = '3.99.0.0' OnCreate = FormCreate OnDestroy = FormDestroy - ShowHint = True object MapView: TMapView Left = 0 Height = 662 @@ -27823,192 +27824,33 @@ object MainForm: TMainForm MapCenter.Longitude = -87.9081388888889 MapCenter.Latitude = 41.9769444444444 POIImage.Data = { - 36170000424D36170000000000003600000028000000200000002E0000000100 - 2000000000000017000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD560000FC4CFFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F1110000FEE70000FEE10000 - EA0CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE9A0000FFFF0000FFFF0000 - FE8FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF000000FB3E0000FEFE0000FFFF0000FFFF0000 - FEFC0000FB35FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF000000DB070000FED70000FFFF0000FFFF0000FFFF0000 - FFFF0000FECF0000C004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF000000FE800000FFFF0000FFFF0000FFFF0000FFFF0000 - FFFF0000FFFF0000FD75FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - 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 + 4503000089504E470D0A1A0A0000000D49484452000000200000002E08060000 + 0049701B840000030C49444154789CB5983B68145114867F4410C54644B0107C + 152262A7A4D2C2DA3422DAD8D868631510B1D1688855409104A2088634819056 + B00C488845626C82C55662A29204C40DC96ED66CD6F38F77976B76E6DCC7CC14 + 077667CEF9FFEF3EE6CC03AD560B3EB1021C6C023777805189598955892D13AB + E6D8287398EBABEB4CA803A745F895C47A92EE11CC650D6BA3012AC03E1119E4 + 087D8D5340383B83D40A0210F29352381F6B9C02F2899A5E000DE09C142C1765 + 6E412C535B05A801C72571A968730B62891EA90066CDE7CA32B720E6EC3DD101 + 901303012215893772C93D62F0378F05D40FFC07201BE4841CAC7B147EF8035C + CADAD13CC71C0F9D3A3D3B007260C451B023237DDC0FEC715DD7CC612E6B1C9A + 2309C077E080FCA96AC99C66DFCED68EA44607A8D21BDBC03547E2B4CFC8D366 + 82B59A36BD39FDC35A92AC6B4FA8B9B5277A1C831B26C08C92B0186B6E5D5D8B + 8AFE0C137EBA364A4E80CC0D4E6F26D494CD773F2F40A2910D5023404301E82B + 00A04F016810604D49182A60098614FD3568B7DD6483E607D036F93C13C69484 + A6CF534D5698A7A9A6A23FC635BAEDB856C7738C7E5CD3A637D68123DA46644F + 978E753DD49C35DAFD809EF46E934E39666153047B03CC7B59E3D09C6AFDFB97 + B4CC0B1E77AFA6C4CB2A7038CB98E798A3AD7B7B56E9D90130B330A115D9CD43 + E29DC41359C3BB0CFE36C7329BDA2E8D89B66F07600B38E3222F22CC9575AA0B + C0CCC2D3B20164C61EDA9E5DEB28100B258EFEE36EBF2E00D33C9CCF8711E61B + 9BC0312780B9813C2861EAEFA579A5024C037B85F87381A39FCD7AAC4B0530BD + E1A2146E1760DE9057B2F3593E99006643BE2800E099E6A102F04383087CCD61 + 5EF906EC8F06307DFD6AA4396F62575CFA4E00B3149311006F7DB4BD003680A3 + 22F82BC07C45BB69050398DE7027E09ABFE5ABEB0D605EB57CDE7CDFFB6A0601 + 30E48E7956FB68C5769BF52DA81000B321FB95A90F7E910906309F72BEA48C7E + 812DBC740086B4E9CBF6231C5B365B778C561480598AD716C0F3589D6880DFC0 + 2131FEC1561DF26DB83000866CBA1B49ABCEA1F117D2B9A057721AC774000000 + 0049454E44AE426082 } POIImages = ilPOIs POIImagesWidth = 32 @@ -28031,8 +27873,8 @@ object MainForm: TMainForm TabOrder = 1 object PgData: TTabSheet Caption = 'Tracking' - ClientHeight = 627 - ClientWidth = 312 + ClientHeight = 634 + ClientWidth = 310 object ZoomTrackBar: TTrackBar AnchorSideLeft.Control = PgData AnchorSideTop.Control = LblZoom @@ -28041,12 +27883,12 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 2 Height = 40 - Top = 23 - Width = 308 + Top = 21 + Width = 306 Min = 1 - OnChange = ZoomTrackBarChange Position = 4 TickMarks = tmBoth + OnChange = ZoomTrackBarChange Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 2 BorderSpacing.Right = 2 @@ -28056,9 +27898,9 @@ object MainForm: TMainForm AnchorSideLeft.Control = PgData AnchorSideTop.Control = PgData Left = 6 - Height = 17 + Height = 15 Top = 6 - Width = 43 + Width = 35 BorderSpacing.Left = 6 BorderSpacing.Top = 6 Caption = 'Zoom:' @@ -28071,9 +27913,9 @@ object MainForm: TMainForm AnchorSideRight.Control = PgData AnchorSideRight.Side = asrBottom Left = 6 - Height = 73 - Top = 71 - Width = 300 + Height = 70 + Top = 69 + Width = 298 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Left = 6 @@ -28081,17 +27923,17 @@ object MainForm: TMainForm BorderSpacing.Right = 6 BorderSpacing.InnerBorder = 4 Caption = 'Mouse position' - ClientHeight = 54 - ClientWidth = 296 + ClientHeight = 50 + ClientWidth = 294 TabOrder = 1 object lblMouseLon: TLabel AnchorSideLeft.Control = gbMouse AnchorSideTop.Control = lblMouseLat AnchorSideTop.Side = asrBottom Left = 8 - Height = 17 - Top = 29 - Width = 68 + Height = 15 + Top = 27 + Width = 54 BorderSpacing.Left = 8 BorderSpacing.Top = 4 Caption = 'Longitude' @@ -28101,9 +27943,9 @@ object MainForm: TMainForm AnchorSideLeft.Control = gbMouse AnchorSideTop.Control = gbMouse Left = 8 - Height = 17 + Height = 15 Top = 4 - Width = 57 + Width = 43 BorderSpacing.Left = 8 BorderSpacing.Top = 4 BorderSpacing.Bottom = 8 @@ -28116,10 +27958,10 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbMouse AnchorSideRight.Side = asrBottom - Left = 235 - Height = 17 - Top = 29 - Width = 45 + Left = 244 + Height = 15 + Top = 27 + Width = 34 Alignment = taRightJustify Anchors = [akTop, akRight] BorderSpacing.Top = 4 @@ -28132,10 +27974,10 @@ object MainForm: TMainForm AnchorSideTop.Control = gbMouse AnchorSideRight.Control = gbMouse AnchorSideRight.Side = asrBottom - Left = 235 - Height = 17 + Left = 244 + Height = 15 Top = 4 - Width = 45 + Width = 34 Alignment = taRightJustify Anchors = [akTop, akRight] BorderSpacing.Top = 4 @@ -28152,25 +27994,25 @@ object MainForm: TMainForm AnchorSideRight.Control = gbMouse AnchorSideRight.Side = asrBottom Left = 6 - Height = 73 - Top = 152 - Width = 300 + Height = 70 + Top = 147 + Width = 298 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 8 BorderSpacing.InnerBorder = 4 Caption = 'Center' - ClientHeight = 54 - ClientWidth = 296 + ClientHeight = 50 + ClientWidth = 294 TabOrder = 2 object lblCenterLon: TLabel AnchorSideLeft.Control = gbCenter AnchorSideTop.Control = lblCenterLat AnchorSideTop.Side = asrBottom Left = 8 - Height = 17 - Top = 29 - Width = 68 + Height = 15 + Top = 27 + Width = 54 BorderSpacing.Left = 8 BorderSpacing.Top = 4 Caption = 'Longitude' @@ -28180,9 +28022,9 @@ object MainForm: TMainForm AnchorSideLeft.Control = gbCenter AnchorSideTop.Control = gbCenter Left = 8 - Height = 17 + Height = 15 Top = 4 - Width = 57 + Width = 43 BorderSpacing.Left = 8 BorderSpacing.Top = 4 BorderSpacing.Bottom = 8 @@ -28195,10 +28037,10 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom AnchorSideRight.Control = gbCenter AnchorSideRight.Side = asrBottom - Left = 235 - Height = 17 - Top = 29 - Width = 45 + Left = 244 + Height = 15 + Top = 27 + Width = 34 Alignment = taRightJustify Anchors = [akTop, akRight] BorderSpacing.Top = 4 @@ -28211,10 +28053,10 @@ object MainForm: TMainForm AnchorSideTop.Control = gbCenter AnchorSideRight.Control = gbCenter AnchorSideRight.Side = asrBottom - Left = 235 - Height = 17 + Left = 244 + Height = 15 Top = 4 - Width = 45 + Width = 34 Alignment = taRightJustify Anchors = [akTop, akRight] BorderSpacing.Top = 4 @@ -28230,9 +28072,9 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = plInfo Left = 6 - Height = 231 - Top = 233 - Width = 298 + Height = 246 + Top = 225 + Width = 296 Anchors = [akTop, akLeft, akRight, akBottom] AutoFillColumns = True BorderSpacing.Top = 8 @@ -28248,12 +28090,12 @@ object MainForm: TMainForm item Title.Alignment = taCenter Title.Caption = 'Latitude' - Width = 105 + Width = 111 end item Title.Alignment = taCenter Title.Caption = 'Longitude' - Width = 106 + Width = 111 end> FixedCols = 0 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSelect, goSmoothScroll] @@ -28262,8 +28104,8 @@ object MainForm: TMainForm OnDblClick = sgTracksDblClick ColWidths = ( 70 - 105 - 106 + 111 + 111 ) end object pnlFlightControl: TPanel @@ -28274,8 +28116,8 @@ object MainForm: TMainForm AnchorSideBottom.Side = asrBottom Left = 0 Height = 50 - Top = 577 - Width = 312 + Top = 584 + Width = 310 Anchors = [akLeft, akRight, akBottom] BevelOuter = bvNone ChildSizing.LeftRightSpacing = 5 @@ -28288,13 +28130,13 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 99 ClientHeight = 50 - ClientWidth = 312 + ClientWidth = 310 TabOrder = 4 object btnPlay: TSpeedButton Left = 5 Height = 40 Top = 5 - Width = 65 + Width = 66 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 @@ -28334,10 +28176,10 @@ object MainForm: TMainForm OnClick = btnPlayClick end object btnPause: TSpeedButton - Left = 75 + Left = 76 Height = 40 Top = 5 - Width = 65 + Width = 66 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 @@ -28377,10 +28219,10 @@ object MainForm: TMainForm OnClick = btnPauseClick end object btnStop: TSpeedButton - Left = 145 + Left = 147 Height = 40 Top = 5 - Width = 65 + Width = 67 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 @@ -28420,10 +28262,10 @@ object MainForm: TMainForm OnClick = btnStopClick end object btnWarp: TSpeedButton - Left = 215 + Left = 219 Height = 40 Top = 5 - Width = 92 + Width = 86 Caption = 'Warp+' OnClick = btnWarpClick end @@ -28433,8 +28275,8 @@ object MainForm: TMainForm AnchorSideBottom.Control = pnlFlightControl Left = 6 Height = 33 - Top = 536 - Width = 298 + Top = 543 + Width = 296 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Bottom = 8 TabOrder = 5 @@ -28446,11 +28288,11 @@ object MainForm: TMainForm AnchorSideBottom.Control = pnlWarpInfo Left = 6 Height = 72 - Top = 464 - Width = 298 + Top = 471 + Width = 296 Anchors = [akLeft, akRight, akBottom] ClientHeight = 72 - ClientWidth = 298 + ClientWidth = 296 Color = clCream ParentBackground = False ParentColor = False @@ -28459,7 +28301,7 @@ object MainForm: TMainForm Left = 6 Height = 60 Top = 6 - Width = 286 + Width = 284 Align = alClient AutoSize = False BorderSpacing.Around = 5 @@ -28473,16 +28315,16 @@ object MainForm: TMainForm AnchorSideBottom.Control = plInfo AnchorSideBottom.Side = asrBottom Left = 4 - Height = 21 - Top = 47 - Width = 114 + Height = 19 + Top = 49 + Width = 90 Anchors = [akLeft, akBottom] BorderSpacing.Around = 3 Caption = 'Follow tightly' Checked = True - OnChange = cbTightFollowChange State = cbChecked TabOrder = 0 + OnChange = cbTightFollowChange end end end diff --git a/components/lazmapviewer/examples/flights/main.pas b/components/lazmapviewer/examples/flights/main.pas index 58e7c42e2..5c2ddfe38 100644 --- a/components/lazmapviewer/examples/flights/main.pas +++ b/components/lazmapviewer/examples/flights/main.pas @@ -71,7 +71,7 @@ implementation {$R *.lfm} uses - LCLType, Math, FPImage, DateUtils, mvEngine; + LCLType, Math, FPImage, DateUtils, mvGeoMath, mvEngine; type diff --git a/components/lazmapviewer/examples/fulldemo/globals.pas b/components/lazmapviewer/examples/fulldemo/globals.pas index 8b78a2f20..cd22de77d 100644 --- a/components/lazmapviewer/examples/fulldemo/globals.pas +++ b/components/lazmapviewer/examples/fulldemo/globals.pas @@ -5,7 +5,7 @@ unit globals; interface uses - Classes, SysUtils, mvEngine; + Classes, SysUtils, mvGeoMath, mvEngine; type TPOIMode = (pmDefaultDrawing, pmDefaultImage, pmImageList, pmCustomDrawing); diff --git a/components/lazmapviewer/examples/fulldemo/gpslistform.pas b/components/lazmapviewer/examples/fulldemo/gpslistform.pas index 47a4a4292..ded5332f8 100644 --- a/components/lazmapviewer/examples/fulldemo/gpslistform.pas +++ b/components/lazmapviewer/examples/fulldemo/gpslistform.pas @@ -57,7 +57,7 @@ implementation {$R *.lfm} uses - mvTypes, mvEngine, + mvTypes, mvGeoMath, mvEngine, globals; destructor TGPSListViewer.Destroy; @@ -143,7 +143,7 @@ begin // show distance between selected items ShowMessage(Format('Distance between %s and %s is: %.2n %s.', [ 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] ])); end; diff --git a/components/lazmapviewer/examples/fulldemo/main.pas b/components/lazmapviewer/examples/fulldemo/main.pas index 0d62bf6fa..ec5510fae 100644 --- a/components/lazmapviewer/examples/fulldemo/main.pas +++ b/components/lazmapviewer/examples/fulldemo/main.pas @@ -15,7 +15,7 @@ uses Classes, SysUtils, Types, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, ComCtrls, Buttons, IntfGraphics, PrintersDlgs, Grids, ExtDlgs, - mvGeoNames, mvMapViewer, mvTypes, mvGpsObj, mvDrawingEngine, + mvGeoMath, mvGeoNames, mvMapViewer, mvTypes, mvGpsObj, mvDrawingEngine, {$IFDEF WITH_ADDONS}ConfigFrame_with_Addons{$ELSE}ConfigFrame{$ENDIF}; type diff --git a/components/lazmapviewer/examples/trackdemo/main.lfm b/components/lazmapviewer/examples/trackdemo/main.lfm index e6e1e95ec..f6557ad26 100644 --- a/components/lazmapviewer/examples/trackdemo/main.lfm +++ b/components/lazmapviewer/examples/trackdemo/main.lfm @@ -24,192 +24,33 @@ object MainForm: TMainForm Font.Pitch = fpVariable MapProvider = 'Google Maps' POIImage.Data = { - 36170000424D36170000000000003600000028000000200000002E0000000100 - 2000000000000017000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FD560000FC4CFFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000F1110000FEE70000FEE10000 - EA0CFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000FE9A0000FFFF0000FFFF0000 - FE8FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF000000FB3E0000FEFE0000FFFF0000FFFF0000 - FEFC0000FB35FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF000000DB070000FED70000FFFF0000FFFF0000FFFF0000 - FFFF0000FECF0000C004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF000000FE800000FFFF0000FFFF0000FFFF0000FFFF0000 - FFFF0000FFFF0000FD75FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - 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 + 4503000089504E470D0A1A0A0000000D49484452000000200000002E08060000 + 0049701B840000030C49444154789CB5983B68145114867F4410C54644B0107C + 152262A7A4D2C2DA3422DAD8D868631510B1D1688855409104A2088634819056 + B00C488845626C82C55662A29204C40DC96ED66CD6F38F77976B76E6DCC7CC14 + 077667CEF9FFEF3EE6CC03AD560B3EB1021C6C023777805189598955892D13AB + E6D8287398EBABEB4CA803A745F895C47A92EE11CC650D6BA3012AC03E1119E4 + 087D8D5340383B83D40A0210F29352381F6B9C02F2899A5E000DE09C142C1765 + 6E412C535B05A801C72571A968730B62891EA90066CDE7CA32B720E6EC3DD101 + 901303012215893772C93D62F0378F05D40FFC07201BE4841CAC7B147EF8035C + CADAD13CC71C0F9D3A3D3B007260C451B023237DDC0FEC715DD7CC612E6B1C9A + 2309C077E080FCA96AC99C66DFCED68EA44607A8D21BDBC03547E2B4CFC8D366 + 82B59A36BD39FDC35A92AC6B4FA8B9B5277A1C831B26C08C92B0186B6E5D5D8B + 8AFE0C137EBA364A4E80CC0D4E6F26D494CD773F2F40A2910D5023404301E82B + 00A04F016810604D49182A60098614FD3568B7DD6483E607D036F93C13C69484 + A6CF534D5698A7A9A6A23FC635BAEDB856C7738C7E5CD3A637D68123DA46644F + 978E753DD49C35DAFD809EF46E934E39666153047B03CC7B59E3D09C6AFDFB97 + B4CC0B1E77AFA6C4CB2A7038CB98E798A3AD7B7B56E9D90130B330A115D9CD43 + E29DC41359C3BB0CFE36C7329BDA2E8D89B66F07600B38E3222F22CC9575AA0B + C0CCC2D3B20164C61EDA9E5DEB28100B258EFEE36EBF2E00D33C9CCF8711E61B + 9BC0312780B9813C2861EAEFA579A5024C037B85F87381A39FCD7AAC4B0530BD + E1A2146E1760DE9057B2F3593E99006643BE2800E099E6A102F04383087CCD61 + 5EF906EC8F06307DFD6AA4396F62575CFA4E00B3149311006F7DB4BD003680A3 + 22F82BC07C45BB69050398DE7027E09ABFE5ABEB0D605EB57CDE7CDFFB6A0601 + 30E48E7956FB68C5769BF52DA81000B321FB95A90F7E910906309F72BEA48C7E + 812DBC740086B4E9CBF6231C5B365B778C561480598AD716C0F3589D6880DFC0 + 2131FEC1561DF26DB83000866CBA1B49ABCEA1F117D2B9A057721AC774000000 + 0049454E44AE426082 } POITextBgColor = clCream UseThreads = True diff --git a/components/lazmapviewer/examples/trackdemo/main.pas b/components/lazmapviewer/examples/trackdemo/main.pas index d713a9d68..ce69615cb 100644 --- a/components/lazmapviewer/examples/trackdemo/main.pas +++ b/components/lazmapviewer/examples/trackdemo/main.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, - Grids, StdCtrls, ColorBox, mvMapViewer, mvGpsObj; + Grids, StdCtrls, ColorBox, mvMapViewer, mvGeoMath, mvGpsObj; type diff --git a/components/lazmapviewer/lazmapviewerpkg.lpk b/components/lazmapviewer/lazmapviewerpkg.lpk index ae869fb3d..40d9b08e2 100644 --- a/components/lazmapviewer/lazmapviewerpkg.lpk +++ b/components/lazmapviewer/lazmapviewerpkg.lpk @@ -20,7 +20,7 @@ - + @@ -108,6 +108,10 @@ + + + + diff --git a/components/lazmapviewer/lazmapviewerpkg.pas b/components/lazmapviewer/lazmapviewerpkg.pas index 66f5f3ff2..a54a42ca5 100644 --- a/components/lazmapviewer/lazmapviewerpkg.pas +++ b/components/lazmapviewer/lazmapviewerpkg.pas @@ -11,7 +11,7 @@ uses mvCache, mvDownloadEngine, mvDragObj, mvEngine, mvGeoNames, mvGpsObj, mvJobQueue, mvJobs, mvMapProvider, mvTypes, mvMapViewer, mvExtraData, mvDLEFpc, mvMapViewerReg, mvGPX, mvDrawingEngine, mvDE_IntfGraphics, - mvDLEWin, mvMapViewerPropEdits, mvLayersPropEditForm, mvDE_LCL, + mvDLEWin, mvMapViewerPropEdits, mvLayersPropEditForm, mvDE_LCL, mvgeomath, LazarusPackageIntf; implementation diff --git a/components/lazmapviewer/source/mvengine.pas b/components/lazmapviewer/source/mvengine.pas index b72ba1742..3003f9274 100644 --- a/components/lazmapviewer/source/mvengine.pas +++ b/components/lazmapviewer/source/mvengine.pas @@ -21,13 +21,7 @@ interface uses Classes, SysUtils, IntfGraphics, Controls, Math, GraphType, FPImage, - mvTypes, 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)); + mvTypes, mvGeoMath, mvJobQueue, mvMapProvider, mvDownloadEngine, mvCache, mvDragObj; type TDrawTileEvent = procedure (const TileId: TTileId; X,Y: integer; @@ -42,8 +36,6 @@ type TTileIdArray = Array of TTileId; - TDistanceUnits = (duMeters, duKilometers, duMiles); - { TMapWindow } TMapWindow = Record @@ -215,33 +207,19 @@ type property OnZoomChange: TNotifyEvent read FOnZoomChange write FOnZoomChange; end; -function RealPoint(Lat, Lon: Double): TRealPoint; -function NormalizeLon(const Lon: Double): Double; inline; +// The following functions have been moved to mvGeoMath and will be removed here sooner or later... +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 CalcGeoDistance(Lat1, Lon1, Lat2, Lon2: double; - AUnits: TDistanceUnits = duKilometers): double; +function LatToStr(ALatitude: Double; DMS: Boolean): String; deprecated 'Use function in unit mvGeoMath'; +function LatToStr(ALatitude: Double; DMS: Boolean; AFormatSettings: TFormatSettings): String; deprecated 'Use function in unit mvGeoMath'; +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; -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; +function ZoomFactor(AZoomLevel: Integer): Int64; deprecated 'Use function in unit mvGeoMath'; var HERE_AppID: String = ''; @@ -249,8 +227,6 @@ var OpenWeatherMap_ApiKey: String = ''; ThunderForest_ApiKey: String = ''; - DMS_Decimals: Integer = 1; - implementation @@ -258,25 +234,6 @@ uses Forms, TypInfo, laz2_xmlread, laz2_xmlwrite, laz2_dom, 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 { TEnvTile } @@ -1474,492 +1431,56 @@ begin MapWin.MapProvider := MP; // Restore the old Map Provider end; -//------------------------------------------------------------------------------ +{------------------------------------------------------------------------------} -function RealPoint(Lat, Lon: Double): TRealPoint; +function DMSToDeg(Deg, Min: Word; Sec: Double): Double; begin - Result.Lon := Lon; - 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; + Result := mvGeoMath.DMSToDeg(Deg, Min, Sec); end; function GPSToDMS(Angle: Double): string; begin - Result := GPSToDMS(Angle, DefaultFormatSettings); + Result := mvGeoMath.GPSToDMS(Angle); 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); + Result := mvGeoMath.GPSToDMS(Angle, AFormatSettings); end; function LatToStr(ALatitude: Double; DMS: Boolean): String; begin - Result := LatToStr(ALatitude, DMS, DefaultFormatSettings); + Result := mvGeoMath.LatToStr(ALatitude, DMS); 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'; + Result := mvGeoMath.LatToStr(ALatitude, DMS, AFormatSettings); end; function LonToStr(ALongitude: Double; DMS: Boolean): String; begin - Result := LonToStr(ALongitude, DMS, DefaultFormatSettings); + Result := mvGeoMath.LonToStr(ALongitude, DMS); 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'; + Result := mvGeoMath.LonToStr(ALongitude, DMS, AFormatSettings); 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); + Result := mvGeoMath.TryStrToGps(AValue, ADeg); 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; + Result := mvGeoMath.TryStrDMSToDeg(AValue, ADeg); 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; +function ZoomFactor(AZoomLevel: Integer): Int64; 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; + Result := mvGeoMath.ZoomFactor(AZoomLevel); end; end. diff --git a/components/lazmapviewer/source/mvgeomath.pas b/components/lazmapviewer/source/mvgeomath.pas new file mode 100644 index 000000000..1e5bf7e08 --- /dev/null +++ b/components/lazmapviewer/source/mvgeomath.pas @@ -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. + diff --git a/components/lazmapviewer/source/mvgpsobj.pas b/components/lazmapviewer/source/mvgpsobj.pas index b9068ee2f..a7850ab06 100644 --- a/components/lazmapviewer/source/mvgpsobj.pas +++ b/components/lazmapviewer/source/mvgpsobj.pas @@ -16,7 +16,8 @@ unit mvGpsObj; interface uses - Classes, SysUtils, Graphics, fgl, mvtypes, contnrs, syncobjs; + Classes, SysUtils, Graphics, fgl, contnrs, syncobjs, + mvTypes, mvGeoMath; const NO_ELE = -10000000; @@ -1013,6 +1014,21 @@ begin Result := FDateTime <> NO_DATE; 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; UseElevation: boolean = true): double; var @@ -1031,7 +1047,13 @@ begin t3 := cos(lon1 - lon2); t4 := t2 * t3; t5 := t1 + t4; - rad_dist := arctan(-t5/sqrt(-t5 * t5 +1)) + 2 * arctan(1); + 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); result := (rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446; if UseElevation and (FElevation <> OtherPt.FElevation) then if (HasElevation) and (OtherPt.HasElevation) then @@ -1041,6 +1063,7 @@ begin Result := sqrt(DiffEle*DiffEle + result*result); end; end; +*) procedure TGPSPoint.MoveTo(ALon, ALat: Double; AElevation: double = NO_ELE; ADateTime: TDateTime = NO_DATE); diff --git a/components/lazmapviewer/source/mvmapviewer.pas b/components/lazmapviewer/source/mvmapviewer.pas index c04fda1a1..5b0290eee 100644 --- a/components/lazmapviewer/source/mvmapviewer.pas +++ b/components/lazmapviewer/source/mvmapviewer.pas @@ -29,8 +29,8 @@ interface uses Classes, SysUtils, Controls, GraphType, Graphics, FPImage, IntfGraphics, Forms, ImgList, LCLVersion, fgl, - MvTypes, MvGPSObj, MvEngine, MvMapProvider, MvDownloadEngine, MvDrawingEngine, - mvCache, mvExtraData; + MvTypes, MvGeoMath, MvGPSObj, MvCache, MvExtraData, MvEngine, MvMapProvider, + MvDownloadEngine, MvDrawingEngine; Type diff --git a/components/lazmapviewer/source/mvmapviewerpropedits.pas b/components/lazmapviewer/source/mvmapviewerpropedits.pas index 064996e99..a760a32e1 100644 --- a/components/lazmapviewer/source/mvmapviewerpropedits.pas +++ b/components/lazmapviewer/source/mvmapviewerpropedits.pas @@ -78,8 +78,9 @@ procedure Register; implementation uses - Dialogs, IDEWindowIntf, mvMapViewer, mvGpsObj, mvLayersPropEditForm, mvEngine, - StrUtils; + Dialogs, IDEWindowIntf, + StrUtils, + mvGeoMath, mvMapViewer, mvGpsObj, mvLayersPropEditForm, mvEngine; const NONE = '(none)'; diff --git a/components/lazmapviewer/source/mvtypes.pas b/components/lazmapviewer/source/mvtypes.pas index d492a2da6..aa65e99d9 100644 --- a/components/lazmapviewer/source/mvtypes.pas +++ b/components/lazmapviewer/source/mvtypes.pas @@ -63,6 +63,8 @@ Type function Union(const Area: TRealArea): TRealArea; end; +function RealPoint(Lat, Lon: Double): TRealPoint; + implementation @@ -276,6 +278,12 @@ begin Self.Lat := RadToDeg(AValue); end; +function RealPoint(Lat, Lon: Double): TRealPoint; +begin + Result.Lon := Lon; + Result.Lat := Lat; +end; + { TRealArea diff --git a/components/lazmapviewer/unittests/mapviewer_tests.lpi b/components/lazmapviewer/unittests/mapviewer_tests.lpi index d1052f947..781bf4388 100644 --- a/components/lazmapviewer/unittests/mapviewer_tests.lpi +++ b/components/lazmapviewer/unittests/mapviewer_tests.lpi @@ -8,7 +8,6 @@ <ResourceType Value="res"/> <UseXPManifest Value="True"/> - <Icon Value="0"/> </General> <BuildModes> <Item Name="Default" Default="True"/> @@ -41,7 +40,7 @@ <IsPartOfProject Value="True"/> </Unit> <Unit> - <Filename Value="mvtests_engine.pas"/> + <Filename Value="mvtests_geomath.pas"/> <IsPartOfProject Value="True"/> </Unit> </Units> diff --git a/components/lazmapviewer/unittests/mapviewer_tests.lpr b/components/lazmapviewer/unittests/mapviewer_tests.lpr index 7f9e335e4..76a6ee5a2 100644 --- a/components/lazmapviewer/unittests/mapviewer_tests.lpr +++ b/components/lazmapviewer/unittests/mapviewer_tests.lpr @@ -4,7 +4,7 @@ program mapviewer_tests; uses Interfaces, Forms, GuiTestRunner, - mvtests_engine, mvtests_types; + mvtests_geomath, mvtests_types; {$R *.res} diff --git a/components/lazmapviewer/unittests/mvtests_engine.pas b/components/lazmapviewer/unittests/mvtests_geomath.pas similarity index 94% rename from components/lazmapviewer/unittests/mvtests_engine.pas rename to components/lazmapviewer/unittests/mvtests_geomath.pas index 63b84ea27..9b0a30523 100644 --- a/components/lazmapviewer/unittests/mvtests_engine.pas +++ b/components/lazmapviewer/unittests/mvtests_geomath.pas @@ -1,4 +1,4 @@ -unit mvtests_engine; +unit mvtests_geomath; {$mode objfpc}{$H+} @@ -8,7 +8,7 @@ uses Classes, SysUtils, fpcunit, testutils, testregistry; type - TMvTests_Engine= class(TTestCase) + TMvTests_GeoMath = class(TTestCase) published procedure Test_Distance; procedure Test_LatToStr_DMS; @@ -22,7 +22,7 @@ type implementation uses - Math, mvEngine; + Math, mvGeoMath; type TDistanceRec = record @@ -94,7 +94,7 @@ const var PointFormatsettings: TFormatSettings; -procedure TMvTests_Engine.Test_Distance; +procedure TMvTests_GeoMath.Test_Distance; const TOLERANCE = 2; RADIUS = 6378; // Earth radius in km, as used by the references @@ -110,7 +110,7 @@ begin ); end; -procedure TMvTests_Engine.Test_LatToStr_Deg; +procedure TMvTests_GeoMath.Test_LatToStr_Deg; const NO_DMS = false; var @@ -125,7 +125,7 @@ begin ); end; -procedure TMvTests_Engine.Test_LatToStr_DMS; +procedure TMvTests_GeoMath.Test_LatToStr_DMS; const NEED_DMS = true; var @@ -140,7 +140,7 @@ begin ); end; -procedure TMvTests_Engine.Test_LonToStr_Deg; +procedure TMvTests_GeoMath.Test_LonToStr_Deg; const NO_DMS = false; var @@ -155,7 +155,7 @@ begin ); end; -procedure TMvTests_Engine.Test_LonToStr_DMS; +procedure TMvTests_GeoMath.Test_LonToStr_DMS; const NEED_DMS = true; var @@ -170,7 +170,7 @@ begin ); end; -procedure TMvTests_Engine.Test_SplitGPS; +procedure TMvTests_GeoMath.Test_SplitGPS; const TOLERANCE = 1e-5; var @@ -218,7 +218,7 @@ begin end; end; -procedure TMvTests_Engine.Test_ZoomFactor; +procedure TMvTests_GeoMath.Test_ZoomFactor; var z: Integer; f: Extended; @@ -236,6 +236,6 @@ initialization PointFormatSettings.DecimalSeparator := '.'; DMS_Decimals := 4; - RegisterTest(TMvTests_Engine); + RegisterTest(TMvTests_GeoMath); end. diff --git a/components/lazmapviewer/unittests/mvtests_types.pas b/components/lazmapviewer/unittests/mvtests_types.pas index 7a5841f00..64b00838a 100644 --- a/components/lazmapviewer/unittests/mvtests_types.pas +++ b/components/lazmapviewer/unittests/mvtests_types.pas @@ -9,7 +9,7 @@ uses type - TMvTestsArea= class(TTestCase) + TMvTests_Area= class(TTestCase) published procedure Test_PointInArea; procedure Test_Intersection; @@ -28,7 +28,7 @@ begin ]); end; -procedure TMvTestsArea.Test_PointInArea; +procedure TMvTests_Area.Test_PointInArea; var counter: Integer; a: TRealArea; @@ -123,7 +123,7 @@ begin ); end; -procedure TMvTestsArea.Test_Union; +procedure TMvTests_Area.Test_Union; var counter: Integer; a, b, expected, actual: TRealArea; @@ -298,7 +298,7 @@ begin ); end; -procedure TMvTestsArea.Test_Intersection; +procedure TMvTests_Area.Test_Intersection; var counter: Integer; a, b, expected, actual: TRealArea; @@ -430,7 +430,7 @@ end; initialization - RegisterTest(TMvTestsArea); + RegisterTest(TMvTests_Area); end.