lazMapViewer: Initial commit to CCR (based on Maciej Kaczkowski (https://github.com/maciejkaczkowski/mapviewer) and ti-dic's (https://sourceforge.net/p/roadbook/code/ci/master/tree/mapviewer/) MapViewer components. Removed dependence on RGB_Graphics. Rename TMapViewer to TMapView and TMVGLGeonames to TMvGeoNames to avoid naming conflicts with original packages.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6307 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
b27acb05ae
commit
c76a4f904a
82
components/lazmapviewer/example/MapViewer_Demo.lpi
Normal file
82
components/lazmapviewer/example/MapViewer_Demo.lpi
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="11"/>
|
||||
<PathDelim Value="\"/>
|
||||
<General>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<MainUnit Value="0"/>
|
||||
<Title Value="MapViewer_Demo"/>
|
||||
<Scaled Value="True"/>
|
||||
<ResourceType Value="res"/>
|
||||
<UseXPManifest Value="True"/>
|
||||
<XPManifest>
|
||||
<DpiAware Value="True"/>
|
||||
</XPManifest>
|
||||
<Icon Value="0"/>
|
||||
</General>
|
||||
<BuildModes Count="1">
|
||||
<Item1 Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<FormatVersion Value="2"/>
|
||||
<Modes Count="0"/>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="2">
|
||||
<Item1>
|
||||
<PackageName Value="lazMapViewerPkg"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<PackageName Value="LCL"/>
|
||||
</Item2>
|
||||
</RequiredPackages>
|
||||
<Units Count="2">
|
||||
<Unit0>
|
||||
<Filename Value="MapViewer_Demo.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="main.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="Form1"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="Main"/>
|
||||
</Unit1>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<PathDelim Value="\"/>
|
||||
<Target>
|
||||
<Filename Value="MapViewer_Demo"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<Linking>
|
||||
<Options>
|
||||
<Win32>
|
||||
<GraphicApplication Value="True"/>
|
||||
</Win32>
|
||||
</Options>
|
||||
</Linking>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
22
components/lazmapviewer/example/MapViewer_Demo.lpr
Normal file
22
components/lazmapviewer/example/MapViewer_Demo.lpr
Normal file
@ -0,0 +1,22 @@
|
||||
program MapViewer_Demo;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
uses
|
||||
{$IFDEF UNIX}{$IFDEF UseCThreads}
|
||||
cthreads,
|
||||
{$ENDIF}{$ENDIF}
|
||||
Interfaces, // this includes the LCL widgetset
|
||||
Forms, Main
|
||||
{ you can add units after this };
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
RequireDerivedFormResource:=True;
|
||||
Application.Scaled:=True;
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
||||
|
8
components/lazmapviewer/example/main.lfm
Normal file
8
components/lazmapviewer/example/main.lfm
Normal file
@ -0,0 +1,8 @@
|
||||
object Form1: TForm1
|
||||
Left = 258
|
||||
Height = 545
|
||||
Top = 127
|
||||
Width = 869
|
||||
Caption = 'Form1'
|
||||
LCLVersion = '1.9.0.0'
|
||||
end
|
29
components/lazmapviewer/example/main.pas
Normal file
29
components/lazmapviewer/example/main.pas
Normal file
@ -0,0 +1,29 @@
|
||||
unit Main;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls;
|
||||
|
||||
type
|
||||
|
||||
{ TForm1 }
|
||||
|
||||
TForm1 = class(TForm)
|
||||
private
|
||||
|
||||
public
|
||||
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
end.
|
||||
|
93
components/lazmapviewer/lazmapviewerpkg.lpk
Normal file
93
components/lazmapviewer/lazmapviewerpkg.lpk
Normal file
@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<Package Version="4">
|
||||
<Name Value="lazMapViewerPkg"/>
|
||||
<Type Value="RunAndDesignTime"/>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<SearchPaths>
|
||||
<OtherUnitFiles Value="source"/>
|
||||
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
</CompilerOptions>
|
||||
<Files Count="13">
|
||||
<Item1>
|
||||
<Filename Value="source/mvcache.pas"/>
|
||||
<UnitName Value="mvCache"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Filename Value="source/mvdlesynapse.pas"/>
|
||||
<UnitName Value="mvDLESynapse"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Filename Value="source/mvdownloadengine.pas"/>
|
||||
<UnitName Value="mvDownloadEngine"/>
|
||||
</Item3>
|
||||
<Item4>
|
||||
<Filename Value="source/mvdragobj.pas"/>
|
||||
<UnitName Value="mvdragobj"/>
|
||||
</Item4>
|
||||
<Item5>
|
||||
<Filename Value="source/mvengine.pas"/>
|
||||
<UnitName Value="mvEngine"/>
|
||||
</Item5>
|
||||
<Item6>
|
||||
<Filename Value="source/mvgeonames.pas"/>
|
||||
<HasRegisterProc Value="True"/>
|
||||
<UnitName Value="mvgeonames"/>
|
||||
</Item6>
|
||||
<Item7>
|
||||
<Filename Value="source/mvgpsobj.pas"/>
|
||||
<UnitName Value="mvgpsobj"/>
|
||||
</Item7>
|
||||
<Item8>
|
||||
<Filename Value="source/mvjobqueue.pas"/>
|
||||
<UnitName Value="mvJobQueue"/>
|
||||
</Item8>
|
||||
<Item9>
|
||||
<Filename Value="source/mvjobs.pas"/>
|
||||
<UnitName Value="mvJobs"/>
|
||||
</Item9>
|
||||
<Item10>
|
||||
<Filename Value="source/mvmapprovider.pas"/>
|
||||
<UnitName Value="mvMapProvider"/>
|
||||
</Item10>
|
||||
<Item11>
|
||||
<Filename Value="source/mvtypes.pas"/>
|
||||
<UnitName Value="mvtypes"/>
|
||||
</Item11>
|
||||
<Item12>
|
||||
<Filename Value="source/mvmapviewer.pas"/>
|
||||
<HasRegisterProc Value="True"/>
|
||||
<UnitName Value="mvmapviewer"/>
|
||||
</Item12>
|
||||
<Item13>
|
||||
<Filename Value="source/mvextradata.pas"/>
|
||||
<UnitName Value="mvextradata"/>
|
||||
</Item13>
|
||||
</Files>
|
||||
<RequiredPkgs Count="4">
|
||||
<Item1>
|
||||
<PackageName Value="laz_synapse"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<PackageName Value="rgb_graphics"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<PackageName Value="LCLBase"/>
|
||||
</Item3>
|
||||
<Item4>
|
||||
<PackageName Value="FCL"/>
|
||||
</Item4>
|
||||
</RequiredPkgs>
|
||||
<UsageOptions>
|
||||
<UnitPath Value="$(PkgOutDir)"/>
|
||||
</UsageOptions>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
</PublishOptions>
|
||||
<CustomOptions Items="ExternHelp" Version="2">
|
||||
<_ExternHelp Items="Count"/>
|
||||
</CustomOptions>
|
||||
</Package>
|
||||
</CONFIG>
|
27
components/lazmapviewer/lazmapviewerpkg.pas
Normal file
27
components/lazmapviewer/lazmapviewerpkg.pas
Normal file
@ -0,0 +1,27 @@
|
||||
{ This file was automatically created by Lazarus. Do not edit!
|
||||
This source is only used to compile and install the package.
|
||||
}
|
||||
|
||||
unit lazMapViewerPkg;
|
||||
|
||||
{$warn 5023 off : no warning about unused units}
|
||||
interface
|
||||
|
||||
uses
|
||||
mvCache, mvDLESynapse, mvDownloadEngine, mvDragObj, mvEngine, mvGeoNames,
|
||||
mvGPSObj, mvJobQueue, mvJobs, mvMapProvider, mvTypes, mvMapViewer,
|
||||
mvExtraData,
|
||||
LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
RegisterUnit('mvgeonames', @mvgeonames.Register);
|
||||
RegisterUnit('mvmapviewer', @mvmapviewer.Register);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterPackage('lazMapViewerPkg', @Register);
|
||||
|
||||
end.
|
360
components/lazmapviewer/source/mvcache.pas
Normal file
360
components/lazmapviewer/source/mvcache.pas
Normal file
@ -0,0 +1,360 @@
|
||||
{
|
||||
Picture cache manager (c) 2014 ti_dic
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvCache;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,mvmapprovider,IntfGraphics,syncObjs,mvtypes;
|
||||
|
||||
Type
|
||||
|
||||
{ TPictureCache }
|
||||
|
||||
TPictureCache = Class(TComponent)
|
||||
private
|
||||
FMemMaxElem : integer;
|
||||
Crit : TCriticalSection;
|
||||
Cache : TStringList;
|
||||
FBasePath: String;
|
||||
FUseDisk: Boolean;
|
||||
FUseThreads: Boolean;
|
||||
procedure SetUseThreads(AValue: Boolean);
|
||||
Procedure EnterCrit;
|
||||
Procedure LeaveCrit;
|
||||
protected
|
||||
function GetNewImgFor(aStream : TStream) : TLazIntfImage;
|
||||
procedure FreeCache;
|
||||
Function MapProvider2FileName(MapProvider : TMapProvider) : String;
|
||||
Function DiskCached(const aFileName : String) : Boolean;
|
||||
procedure LoadFromDisk(const aFileName : String;out img : TLazIntfImage);
|
||||
Function GetFileName(MapProvider : TMapProvider;const TileId : TTileId) : String;
|
||||
public
|
||||
Procedure CheckCacheSize(sender : TObject);
|
||||
constructor Create(aOwner : TComponent);override;
|
||||
destructor destroy;override;
|
||||
Procedure Add(MapProvider : TMapProvider;const TileId : TTileId;Stream : TMemoryStream);
|
||||
Procedure GetFromCache(MapProvider : TMapProvider;const TileId : TTileId;out img : TLazIntfImage);
|
||||
function InCache(MapProvider : TMapProvider;const TileId : TTileId) : Boolean;
|
||||
|
||||
property UseDisk : Boolean read FUseDisk write FUseDisk;
|
||||
property BasePath : String read FBasePath write FBasePath;
|
||||
property UseThreads : Boolean read FUseThreads write SetUseThreads;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
uses FPimage,GraphType,FPReadJPEG;
|
||||
|
||||
{ TPictureCache }
|
||||
|
||||
function IsValidPNG(stream: TStream): Boolean;
|
||||
var
|
||||
s: string;
|
||||
y: Int64;
|
||||
begin
|
||||
if Assigned(stream) then
|
||||
begin
|
||||
SetLength(s, 3);
|
||||
y := stream.Position;
|
||||
stream.Position := 1;
|
||||
stream.Read(s[1], 3);
|
||||
stream.Position := y;
|
||||
Result := s = 'PNG';
|
||||
end
|
||||
else
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function IsValidJPEG(stream: TStream): Boolean;
|
||||
var
|
||||
s: string;
|
||||
y: Int64;
|
||||
begin
|
||||
if Assigned(stream) then
|
||||
begin
|
||||
SetLength(s, 4);
|
||||
y := stream.Position;
|
||||
stream.Position := 6;
|
||||
stream.Read(s[1], 4);
|
||||
stream.Position := y;
|
||||
Result := (s = 'JFIF') or (s = 'Exif');
|
||||
end
|
||||
else
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
procedure TPictureCache.SetUseThreads(AValue: Boolean);
|
||||
begin
|
||||
if FUseThreads=AValue then Exit;
|
||||
FUseThreads:=AValue;
|
||||
if aValue then
|
||||
Crit:=TCriticalSection.Create
|
||||
else
|
||||
FreeAndnil(Crit);
|
||||
end;
|
||||
|
||||
procedure TPictureCache.EnterCrit;
|
||||
begin
|
||||
if Assigned(Crit) then
|
||||
Crit.Enter;
|
||||
end;
|
||||
|
||||
procedure TPictureCache.LeaveCrit;
|
||||
begin
|
||||
if Assigned(Crit) then
|
||||
Crit.Leave;
|
||||
end;
|
||||
|
||||
function TPictureCache.GetNewImgFor(aStream: TStream): TLazIntfImage;
|
||||
var
|
||||
reader : TFPCustomImageReader;
|
||||
rawImg : TRawImage;
|
||||
begin
|
||||
result:=nil;
|
||||
Reader := nil;
|
||||
if not(assigned(aStream)) then
|
||||
exit;
|
||||
if IsValidJPEG(astream) then
|
||||
Reader := TFPReaderJPEG.create
|
||||
else
|
||||
if IsValidPNG(astream) then
|
||||
Reader := TLazReaderPNG.create;
|
||||
if Assigned(reader) then
|
||||
Begin
|
||||
try
|
||||
rawImg.Init;
|
||||
rawImg.Description.Init_BPP24_B8G8R8_BIO_TTB(TILE_SIZE,TILE_SIZE);
|
||||
Result:=TLazIntfImage.create(rawImg,true);
|
||||
Try
|
||||
Result.LoadFromStream(aStream,reader);
|
||||
except
|
||||
FreeAndNil(result);
|
||||
end;
|
||||
finally
|
||||
FreeAndNil(Reader)
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPictureCache.FreeCache;
|
||||
var i : integer;
|
||||
begin
|
||||
EnterCrit;
|
||||
Try
|
||||
For i:=0 to pred(Cache.Count) do
|
||||
begin
|
||||
Cache.Objects[i].Free;
|
||||
end;
|
||||
Cache.Clear;
|
||||
Cache.Free;
|
||||
finally
|
||||
LeaveCrit;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPictureCache.MapProvider2FileName(MapProvider: TMapProvider): String;
|
||||
var i : integer;
|
||||
begin
|
||||
Result:='';
|
||||
if Assigned(MapProvider) then
|
||||
begin
|
||||
Result:=MapProvider.Name;
|
||||
For i:=1 to length(Result) do
|
||||
if not(result[i] in ['a'..'z','A'..'Z','0'..'9','_','.']) then
|
||||
Result[i]:='-';
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPictureCache.DiskCached(const aFileNAme: String): Boolean;
|
||||
Var FullFileName : string;
|
||||
begin
|
||||
if UseDisk then
|
||||
Begin
|
||||
FullFileName:=BasePath+aFileName;
|
||||
Result:=FileExists(FullFileName);
|
||||
end
|
||||
Else
|
||||
Result:=False;
|
||||
end;
|
||||
|
||||
procedure TPictureCache.LoadFromDisk(const aFileName: String; out
|
||||
img: TLazIntfImage);
|
||||
var FullFileName : String;
|
||||
aStream : TFileStream;
|
||||
begin
|
||||
img:=nil;
|
||||
FullFileName:=BasePath+aFileName;
|
||||
if FileExists(fullFileName) then
|
||||
Begin
|
||||
aStream:=TFileStream.Create(FullFileName,fmOpenRead);
|
||||
try
|
||||
Try
|
||||
img:=GetNewImgFor(aStream);
|
||||
except
|
||||
FreeAndNil(img);
|
||||
end;
|
||||
if Assigned(img) then
|
||||
begin
|
||||
EnterCrit;
|
||||
Try
|
||||
Cache.AddObject(aFileName,img);
|
||||
finally
|
||||
LeaveCrit;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
aStream.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPictureCache.GetFileName(MapProvider: TMapProvider;const TileId: TTileId
|
||||
): String;
|
||||
begin
|
||||
Result:=MapProvider2FileName(MapProvider)+'_'+inttostr(TileId.X)+'_'+inttostr(TileId.Y)+'_'+inttostr(TileId.Z);
|
||||
end;
|
||||
|
||||
procedure TPictureCache.CheckCacheSize(Sender : TObject);
|
||||
var i ,idx : integer;
|
||||
begin
|
||||
EnterCrit;
|
||||
try
|
||||
if Cache.Count>FMemMaxElem then
|
||||
Begin
|
||||
For i:=1 to 10 do
|
||||
Begin
|
||||
idx:=pred(Cache.Count);
|
||||
if idx>1 then
|
||||
Begin
|
||||
Cache.Objects[idx].free;
|
||||
Cache.Delete(idx);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
LeaveCrit;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TPictureCache.Create(aOwner: TComponent);
|
||||
begin
|
||||
inherited Create(aOwner);
|
||||
FMemMaxElem :=2048 div 256;
|
||||
Cache:=TStringList.create;
|
||||
end;
|
||||
|
||||
destructor TPictureCache.destroy;
|
||||
begin
|
||||
inherited destroy;
|
||||
FreeCache;
|
||||
FreeAndNil(Crit);
|
||||
end;
|
||||
|
||||
procedure TPictureCache.Add(MapProvider: TMapProvider;const TileId: TTileId;
|
||||
Stream: TMemoryStream);
|
||||
var FileName : String;
|
||||
img : TLazIntfImage;
|
||||
aFile : TFileStream;
|
||||
idx : integer;
|
||||
begin
|
||||
FileName:=GetFileName(MapProvider,TileId);
|
||||
EnterCrit;
|
||||
Try
|
||||
idx:=Cache.IndexOF(FileName);
|
||||
if idx<>-1 then
|
||||
Cache.Objects[idx].Free
|
||||
else
|
||||
Begin
|
||||
Cache.Insert(0,FileName);
|
||||
idx:=0;
|
||||
end;
|
||||
img:=GetNewImgFor(Stream);
|
||||
Cache.Objects[idx]:=img;
|
||||
finally
|
||||
LeaveCrit;
|
||||
end;
|
||||
if UseDisk then
|
||||
Begin
|
||||
if assigned(img) then
|
||||
Begin
|
||||
aFile:=TFileStream.Create(BasePath+FileName,fmCreate);
|
||||
Try
|
||||
Stream.Position:=0;
|
||||
aFile.CopyFrom(Stream,0);
|
||||
finally
|
||||
FreeAndNil(aFile);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if Not(FUseThreads) then
|
||||
CheckCacheSize(self);
|
||||
end;
|
||||
|
||||
procedure TPictureCache.GetFromCache(MapProvider: TMapProvider;const TileId: TTileId; out img: TLazIntfImage);
|
||||
var FileName : String;
|
||||
idx : integer;
|
||||
begin
|
||||
img:=nil;
|
||||
FileName:=GetFileName(MapProvider,TileId);
|
||||
EnterCrit;
|
||||
Try
|
||||
idx:=Cache.IndexOF(FileName);
|
||||
if idx<>-1 then
|
||||
Begin
|
||||
img:=TLazIntfImage(Cache.Objects[idx]);
|
||||
if Idx>FMemMaxElem div 2 then
|
||||
Begin
|
||||
Cache.Delete(idx);
|
||||
Cache.Insert(0,FileName);
|
||||
Cache.Objects[0]:=img;
|
||||
end;
|
||||
end;
|
||||
|
||||
finally
|
||||
leaveCrit;
|
||||
end;
|
||||
if idx=-1 then
|
||||
Begin
|
||||
if UseDisk then
|
||||
LoadFromDisk(FileName,img);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TPictureCache.InCache(MapProvider: TMapProvider;const TileId: TTileId
|
||||
): Boolean;
|
||||
var FileName : String;
|
||||
idx : integer;
|
||||
begin
|
||||
FileName:=GetFileName(MapProvider,TileId);
|
||||
EnterCrit;
|
||||
try
|
||||
idx:=Cache.IndexOF(FileNAme);
|
||||
finally
|
||||
leaveCrit;
|
||||
end;
|
||||
if idx<>-1 then
|
||||
Result:=True
|
||||
else
|
||||
Result:=DiskCached(FileName);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
80
components/lazmapviewer/source/mvdlesynapse.pas
Normal file
80
components/lazmapviewer/source/mvdlesynapse.pas
Normal file
@ -0,0 +1,80 @@
|
||||
{ Map Viewer Download Engine Synapse
|
||||
|
||||
Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvDLESynapse;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
mvDownloadEngine,SysUtils, Classes, httpsend;
|
||||
|
||||
type
|
||||
|
||||
{ TMVDESynapse }
|
||||
|
||||
TMVDESynapse = class(TCustomDownloadEngine)
|
||||
private
|
||||
FProxyHost: string;
|
||||
FProxyPassword: string;
|
||||
FProxyPort: Integer;
|
||||
FProxyUsername: string;
|
||||
FUseProxy: Boolean;
|
||||
public
|
||||
procedure DownloadFile(const Url: string; str: TStream); override;
|
||||
|
||||
published
|
||||
property UseProxy: Boolean read FUseProxy write FUseProxy;
|
||||
property ProxyHost: string read FProxyHost write FProxyHost;
|
||||
property ProxyPort: Integer read FProxyPort write FProxyPort;
|
||||
property ProxyUsername: string read FProxyUsername write FProxyUsername;
|
||||
property ProxyPassword: string read FProxyPassword write FProxyPassword;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TMVDESynapse }
|
||||
|
||||
procedure TMVDESynapse.DownloadFile(const Url: string; str: TStream);
|
||||
var
|
||||
FHttp: THTTPSend;
|
||||
begin
|
||||
inherited DownloadFile(Url, str);
|
||||
FHttp := THTTPSend.Create;
|
||||
try
|
||||
if FUseProxy then
|
||||
begin
|
||||
FHTTP.ProxyHost := FProxyHost;
|
||||
FHTTP.ProxyPort := IntToStr(FProxyPort);
|
||||
FHTTP.ProxyUser := FProxyUsername;
|
||||
FHTTP.ProxyPass := FProxyPassword;
|
||||
end;
|
||||
|
||||
if FHTTP.HTTPMethod('GET', Url) then
|
||||
begin
|
||||
str.Seek(0, soFromBeginning);
|
||||
str.CopyFrom(FHTTP.Document, 0);
|
||||
str.Position := 0;
|
||||
end;
|
||||
finally
|
||||
FHttp.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
46
components/lazmapviewer/source/mvdownloadengine.pas
Normal file
46
components/lazmapviewer/source/mvdownloadengine.pas
Normal file
@ -0,0 +1,46 @@
|
||||
{ Map Viewer Download Engine Synapse
|
||||
|
||||
Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvDownloadEngine;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
Type
|
||||
|
||||
{ TCustomDownloadEngine }
|
||||
|
||||
TCustomDownloadEngine = class(TComponent)
|
||||
public
|
||||
procedure DownloadFile(const Url: string; str: TStream); virtual;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TCustomDownloadEngine }
|
||||
|
||||
procedure TCustomDownloadEngine.DownloadFile(const Url: string; str: TStream);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
end.
|
||||
|
202
components/lazmapviewer/source/mvdragobj.pas
Normal file
202
components/lazmapviewer/source/mvdragobj.pas
Normal file
@ -0,0 +1,202 @@
|
||||
{
|
||||
(c) 2014 ti_dic
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvdragobj;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
|
||||
Type
|
||||
TDragObj = Class;
|
||||
|
||||
TDragEvent = Procedure (Sender : TDragObj) of Object;
|
||||
|
||||
{ TDragObj }
|
||||
|
||||
TDragObj = Class
|
||||
private
|
||||
FMouseDown : boolean;
|
||||
FLnkObj: TObject;
|
||||
FDragsrc,FStartSrc : TObject;
|
||||
FOfsX: integer;
|
||||
FOfsY: integer;
|
||||
InDrag : Boolean;
|
||||
FStartX,FStartY : integer;
|
||||
FMouseX,FMouseY : integer;
|
||||
FEndX,FEndY : integer;
|
||||
FOnDrag: TDragEvent;
|
||||
FOnEndDrag: TDragEvent;
|
||||
|
||||
procedure SetDest(X,Y : Integer);
|
||||
procedure SetLnkObj(AValue: TObject);
|
||||
procedure SetOnDrag(AValue: TDragEvent);
|
||||
procedure SetOnEndDrag(AValue: TDragEvent);
|
||||
|
||||
Procedure DostartDrag(X,Y : Integer);
|
||||
Procedure DoDrag(X,Y : integer);
|
||||
Procedure DoEndDrag(X,Y : integer);
|
||||
Function HasMoved(X,Y : integer) : Boolean;
|
||||
Procedure AbortDrag;
|
||||
|
||||
public
|
||||
Procedure MouseDown(aDragSrc : TObject;X,Y : integer);
|
||||
Procedure MouseUp(X,Y : integer);
|
||||
Procedure MouseMove(X,Y : integer);
|
||||
|
||||
property OnDrag : TDragEvent read FOnDrag write SetOnDrag;
|
||||
property OnEndDrag : TDragEvent read FOnEndDrag write SetOnEndDrag;
|
||||
|
||||
|
||||
|
||||
property OfsX : integer read FOfsX;
|
||||
property OfsY : integer read FOfsY;
|
||||
property StartX : integer read FStartX;
|
||||
property StartY : integer read FStartY;
|
||||
property MouseX : Integer read FMouseX;
|
||||
property MouseY : integer read FMouseY;
|
||||
property EndX : integer read FEndX;
|
||||
property EndY : integer read FEndY;
|
||||
Property LnkObj : TObject Read FLnkObj write SetLnkObj;
|
||||
property DragSrc : TObject Read FStartSrc;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TDragObj }
|
||||
|
||||
procedure TDragObj.SetDest(X, Y: Integer);
|
||||
begin
|
||||
FEndX:=X;
|
||||
FEndY:=Y;
|
||||
FOfsX:=FEndX-FstartX;
|
||||
FOfsY:=FEndY-FstartY;
|
||||
end;
|
||||
|
||||
procedure TDragObj.SetLnkObj(AValue: TObject);
|
||||
begin
|
||||
if FLnkObj=AValue then Exit;
|
||||
FreeAndNil(FLnkObj);
|
||||
FLnkObj:=AValue;
|
||||
end;
|
||||
|
||||
procedure TDragObj.SetOnDrag(AValue: TDragEvent);
|
||||
begin
|
||||
if FOnDrag=AValue then Exit;
|
||||
FOnDrag:=AValue;
|
||||
end;
|
||||
|
||||
procedure TDragObj.SetOnEndDrag(AValue: TDragEvent);
|
||||
begin
|
||||
if FOnEndDrag=AValue then Exit;
|
||||
FOnEndDrag:=AValue;
|
||||
end;
|
||||
|
||||
procedure TDragObj.DostartDrag(X, Y: Integer);
|
||||
begin
|
||||
InDrag:=True;
|
||||
FStartSrc := FDragSrc;
|
||||
DoDrag(X,Y);
|
||||
end;
|
||||
|
||||
procedure TDragObj.DoDrag(X, Y: integer);
|
||||
begin
|
||||
if (X<>FEndX) or (Y<>FEndY) then
|
||||
Begin
|
||||
SetDest(X,Y);
|
||||
if Assigned(FOnDrag) then
|
||||
FOnDrag(Self);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDragObj.DoEndDrag(X, Y: integer);
|
||||
begin
|
||||
DoDrag(X,Y);
|
||||
if Assigned(FOnEndDrag) then
|
||||
FOnEndDrag(self);
|
||||
FreeAndNil(FLnkObj);
|
||||
FStartSrc := nil;
|
||||
InDrag:=False;
|
||||
end;
|
||||
|
||||
function TDragObj.HasMoved(X, Y: integer): Boolean;
|
||||
begin
|
||||
Result:=(X<>FStartX) or (Y<>FStartY);
|
||||
end;
|
||||
|
||||
procedure TDragObj.AbortDrag;
|
||||
begin
|
||||
if InDrag then
|
||||
Begin
|
||||
DoDrag(FstartX,FStartY);
|
||||
InDrag:=False;
|
||||
FMouseDown:=False;
|
||||
FDragSrc :=nil;
|
||||
FStartSrc := nil;
|
||||
FreeAndNil(FLnkObj);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDragObj.MouseDown(aDragSrc : TObject;X, Y: integer);
|
||||
begin
|
||||
if not(FMouseDown) then
|
||||
Begin
|
||||
FDragSrc := aDragSrc;
|
||||
FMouseDown := True;
|
||||
FStartX := X;
|
||||
FStartY := Y;
|
||||
FEndX := X;
|
||||
FEndY := Y;
|
||||
End
|
||||
Else
|
||||
AbortDrag;
|
||||
end;
|
||||
|
||||
|
||||
procedure TDragObj.MouseMove(X, Y: integer);
|
||||
begin
|
||||
FMouseX := X;
|
||||
FMouseY := Y;
|
||||
if FMouseDown then
|
||||
Begin
|
||||
if InDrag then
|
||||
DoDrag(X,Y)
|
||||
else
|
||||
Begin
|
||||
if HasMoved(X,Y) then
|
||||
DoStartDrag(X,Y);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TDragObj.MouseUp(X, Y: integer);
|
||||
begin
|
||||
if FMouseDown then
|
||||
Begin
|
||||
FMouseDown:=False;
|
||||
if InDrag then
|
||||
DoEndDrag(X,Y);
|
||||
FDragSrc := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
930
components/lazmapviewer/source/mvengine.pas
Normal file
930
components/lazmapviewer/source/mvengine.pas
Normal file
@ -0,0 +1,930 @@
|
||||
{
|
||||
(c) 2014 ti_dic
|
||||
Parts of this component are based on :
|
||||
Map Viewer Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
|
||||
|
||||
unit mvEngine;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,mvJobQueue,mvmapprovider,mvDownloadEngine,IntfGraphics,
|
||||
mvCache,mvdragobj,controls,mvtypes;
|
||||
|
||||
const
|
||||
EARTH_RADIUS = 6378137;
|
||||
MIN_LATITUDE = -85.05112878;
|
||||
MAX_LATITUDE = 85.05112878;
|
||||
MIN_LONGITUDE = -180;
|
||||
MAX_LONGITUDE = 180;
|
||||
SHIFT = 2 * pi * EARTH_RADIUS / 2.0;
|
||||
|
||||
|
||||
Type
|
||||
TDrawTileEvent = Procedure (const TileId : TTileId;X,Y : integer;TileImg : TLazIntfImage) of object;
|
||||
|
||||
TTileIdArray = Array of TTileId;
|
||||
|
||||
{ TMapWindow }
|
||||
TMapWindow = Record
|
||||
MapProvider: TMapProvider;
|
||||
X: Int64;
|
||||
Y: Int64;
|
||||
Center : TRealPoint;
|
||||
Zoom: integer;
|
||||
Height: integer;
|
||||
Width: integer;
|
||||
end;
|
||||
|
||||
|
||||
{ TMapViewerEngine }
|
||||
|
||||
TMapViewerEngine = Class(TComponent)
|
||||
private
|
||||
DragObj : TDragObj;
|
||||
Cache : TPictureCache;
|
||||
FActive: boolean;
|
||||
FDownloadEngine: TCustomDownloadEngine;
|
||||
FDrawTitleInGuiThread: boolean;
|
||||
FOnCenterMove: TNotifyEvent;
|
||||
FOnChange: TNotifyEvent;
|
||||
FOnDrawTile: TDrawTileEvent;
|
||||
FOnZoomChange: TNotifyEvent;
|
||||
lstProvider : TStringList;
|
||||
Queue : TJobQueue;
|
||||
MapWin : TMapWindow;
|
||||
procedure ConstraintZoom(var aWin: TMapWindow);
|
||||
function GetCacheOnDisk: Boolean;
|
||||
function GetCachePath: String;
|
||||
function GetCenter: TRealPoint;
|
||||
function GetHeight: integer;
|
||||
function GetMapProvider: String;
|
||||
function GetUseThreads: Boolean;
|
||||
function GetWidth: integer;
|
||||
function GetZoom: integer;
|
||||
function IsValidTile(const aWin: TMapWindow; const aTile: TTIleId
|
||||
): boolean;
|
||||
procedure MoveMapCenter(Sender: TDragObj);
|
||||
procedure SetActive(AValue: boolean);
|
||||
procedure SetCacheOnDisk(AValue: Boolean);
|
||||
procedure SetCachePath(AValue: String);
|
||||
procedure SetDownloadEngine(AValue: TCustomDownloadEngine);
|
||||
procedure SetHeight(AValue: integer);
|
||||
procedure SetMapProvider(AValue: String);
|
||||
procedure SetUseThreads(AValue: Boolean);
|
||||
procedure SetWidth(AValue: integer);
|
||||
procedure SetZoom(AValue: integer);
|
||||
function LonLatToMapWin(const aWin: TMapWindow; aPt: TRealPoint): TPoint;
|
||||
Function MapWinToLonLat(const aWin: TMapWindow; aPt : TPoint) : TRealPoint;
|
||||
Procedure CalculateWin(var aWin : TMapWindow);
|
||||
Procedure Redraw(const aWin : TmapWindow);
|
||||
function CalculateVisibleTiles(const aWin : TMapWindow) : TArea;
|
||||
function IsCurrentWin(const aWin : TMapWindow) : boolean;
|
||||
protected
|
||||
function GetTileName(const Id : TTileId) : String;
|
||||
procedure evDownload(Data : TObject;Job : TJob);
|
||||
procedure TileDownloaded(Data: PtrInt);
|
||||
Procedure RegisterProviders;
|
||||
Procedure DrawTile(const TileId : TTileId;X,Y : integer;TileImg : TLazIntfImage);
|
||||
|
||||
function GetLetterSvr(id: integer): String;
|
||||
function GetYahooSvr(id: integer): String;
|
||||
function GetYahooY(const Tile : TTileId): string;
|
||||
function GetYahooZ(const Tile : TTileId): string;
|
||||
function GetQuadKey(const Tile : TTileId): string;
|
||||
|
||||
Procedure DoDrag(Sender : TDragObj);
|
||||
public
|
||||
Procedure CancelCurrentDrawing;
|
||||
Procedure Redraw;
|
||||
function AddMapProvider(OpeName: String; Url: String; MinZoom : integer;MaxZoom : integer;NbSvr: integer; GetSvrStr: TGetSvrStr =nil; GetXStr: TGetValStr =nil; GetYStr: TGetValStr =nil; GetZStr: TGetValStr =nil) : TMapProvider;
|
||||
Procedure GetMapProviders(lst : TStrings);
|
||||
|
||||
Constructor Create(aOwner : TComponent);override;
|
||||
destructor Destroy; override;
|
||||
Function ScreenToLonLat(aPt : TPoint) : TRealPoint;
|
||||
Function LonLatToScreen(aPt : TRealPoint) : TPoint;
|
||||
Function WorldScreenToLonLat(aPt : TPoint) : TRealPoint;
|
||||
Function LonLatToWorldScreen(aPt : TRealPoint) : TPoint;
|
||||
|
||||
Procedure SetSize(aWidth,aHeight : integer);
|
||||
|
||||
Procedure MouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
|
||||
Procedure MouseUp(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
|
||||
Procedure MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
||||
Procedure DblClick(Sender: TObject);
|
||||
Procedure MouseWheel(Sender: TObject; Shift: TShiftState;WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
||||
Procedure SetCenter(aCenter : TRealPoint);
|
||||
Procedure ZoomOnArea(const aArea : TRealArea);
|
||||
|
||||
|
||||
property Center : TRealPoint read GetCenter write SetCenter;
|
||||
property Zoom : integer read GetZoom write SetZoom;
|
||||
property Width : integer read GetWidth write SetWidth;
|
||||
property Height : integer read GetHeight write SetHeight;
|
||||
property UseThreads : Boolean read GetUseThreads write SetUseThreads;
|
||||
property MapProvider : String read GetMapProvider write SetMapProvider;
|
||||
property DownloadEngine : TCustomDownloadEngine read FDownloadEngine write SetDownloadEngine;
|
||||
property CacheOnDisk : Boolean read GetCacheOnDisk write SetCacheOnDisk;
|
||||
property CachePath : String read GetCachePath write SetCachePath;
|
||||
property Active : boolean read FActive write SetActive;
|
||||
|
||||
property OnDrawTile :TDrawTileEvent read FOnDrawTile write FOnDrawTile;
|
||||
property DrawTitleInGuiThread : boolean read FDrawTitleInGuiThread write FDrawTitleInGuiThread;
|
||||
property OnCenterMove : TNotifyEvent read FOnCenterMove write FOnCenterMove;
|
||||
property OnZoomChange : TNotifyEvent read FOnZoomChange write FOnZoomChange;
|
||||
property Jobqueue : TJobQueue read Queue;
|
||||
property OnChange : TNotifyEvent Read FOnChange write FOnchange; //called when visiable area change
|
||||
End;
|
||||
|
||||
implementation
|
||||
uses Math,mvJobs,forms,mvgpsobj;
|
||||
|
||||
Type
|
||||
|
||||
{ TLaunchDownloadJob }
|
||||
|
||||
TLaunchDownloadJob = Class(TJob)
|
||||
private
|
||||
AllRun : boolean;
|
||||
Win : TMapWindow;
|
||||
Engine : TMapViewerEngine;
|
||||
FRunning : boolean;
|
||||
FTiles : TTileIdArray;
|
||||
FStates : Array of integer;
|
||||
protected
|
||||
function pGetTask : integer;override;
|
||||
procedure pTaskStarted(aTask: integer);override;
|
||||
procedure pTaskEnded(aTask : integer;aExcept : Exception);override;
|
||||
public
|
||||
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);override;
|
||||
function Running : boolean;override;
|
||||
public
|
||||
Constructor Create(Eng : TMapViewerEngine;const Tiles : TTileIdArray;const aWin : TMapWindow);
|
||||
end;
|
||||
|
||||
|
||||
{ TEnvTile }
|
||||
|
||||
TEnvTile = Class
|
||||
private
|
||||
Tile : TTileId;
|
||||
Win : TMapWindow;
|
||||
public
|
||||
constructor Create(const aTile : TTileId;Const aWin : TMapWindow);
|
||||
End;
|
||||
|
||||
{ TLaunchDownloadJob }
|
||||
|
||||
function TLaunchDownloadJob.pGetTask: integer;
|
||||
var i : integer;
|
||||
begin
|
||||
if not(AllRun) and not(Cancelled) then
|
||||
Begin
|
||||
For i:=low(FStates) to high(FStates) do
|
||||
if FStates[i]=0 then
|
||||
Begin
|
||||
result:=i+1;
|
||||
Exit;
|
||||
end;
|
||||
AllRun:=True;
|
||||
end;
|
||||
Result:=ALL_TASK_COMPLETED;
|
||||
For i:=low(FStates) to high(FStates) do
|
||||
if FStates[i]=1 then
|
||||
Begin
|
||||
Result:=NO_MORE_TASK;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLaunchDownloadJob.pTaskStarted(aTask: integer);
|
||||
begin
|
||||
FRunning:=True;
|
||||
FStates[aTask-1]:=1;
|
||||
end;
|
||||
|
||||
procedure TLaunchDownloadJob.pTaskEnded(aTask: integer; aExcept: Exception);
|
||||
begin
|
||||
if Assigned(aExcept) then
|
||||
FStates[aTask-1]:=3
|
||||
Else
|
||||
FStates[aTask-1]:=2;
|
||||
end;
|
||||
|
||||
procedure TLaunchDownloadJob.ExecuteTask(aTask: integer; FromWaiting: boolean);
|
||||
var iTile : integer;
|
||||
begin
|
||||
iTile:=aTask-1;
|
||||
Queue.AddUniqueJob(TEventJob.Create(@Engine.evDownload,TEnvTile.Create(FTiles[iTile],Win),false,Engine.GetTileName(FTiles[iTile])),Launcher);
|
||||
end;
|
||||
|
||||
function TLaunchDownloadJob.Running: boolean;
|
||||
begin
|
||||
Result:=FRunning;
|
||||
end;
|
||||
|
||||
constructor TLaunchDownloadJob.Create(Eng : TMapViewerEngine;const Tiles: TTileIdArray;const aWin : TMapWindow);
|
||||
var i : integer;
|
||||
begin
|
||||
Engine:=Eng;
|
||||
SetLength(FTiles,Length(Tiles));
|
||||
For i:=low(FTiles) to high(FTiles) do
|
||||
FTiles[i]:=Tiles[i];
|
||||
SetLength(FStates,length(Tiles));
|
||||
AllRun:=false;
|
||||
Name:='LaunchDownload';
|
||||
Win:=aWin;
|
||||
end;
|
||||
|
||||
{ TEnvTile }
|
||||
|
||||
constructor TEnvTile.Create(const aTile : TTileId;Const aWin : TMapWindow);
|
||||
begin
|
||||
Tile:=aTile;
|
||||
Win:=aWin;
|
||||
end;
|
||||
|
||||
|
||||
{ TMapViewerEngine }
|
||||
|
||||
procedure TMapViewerEngine.SetZoom(AValue: integer);
|
||||
begin
|
||||
if MapWin.Zoom=AValue then Exit;
|
||||
MapWin.Zoom:=AValue;
|
||||
ConstraintZoom(MapWin);
|
||||
CalculateWin(MapWin);
|
||||
Redraw(MapWin);
|
||||
if assigned(OnZoomChange) then
|
||||
OnZoomChange(Self);
|
||||
if Assigned(OnChange) then
|
||||
OnChange(Self);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetWidth(AValue: integer);
|
||||
begin
|
||||
if MapWin.Width=AValue then Exit;
|
||||
MapWin.Width:=AValue;
|
||||
CalculateWin(MapWin);
|
||||
Redraw(MapWin);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetHeight(AValue: integer);
|
||||
begin
|
||||
if MapWin.Height=AValue then Exit;
|
||||
MapWin.Height:=AValue;
|
||||
CalculateWin(MapWin);
|
||||
Redraw(MapWin);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.ConstraintZoom(var aWin : TMapWindow);
|
||||
var zMin,zMax :integer;
|
||||
Begin
|
||||
if Assigned(aWin.MapProvider) then
|
||||
Begin
|
||||
aWin.MapProvider.GetZoomInfos(zMin,zMax);
|
||||
if aWin.Zoom<zMin then
|
||||
aWin.Zoom:=zMin;
|
||||
if aWin.Zoom>zMax then
|
||||
aWin.Zoom:=zMax;
|
||||
End;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetMapProvider(AValue: String);
|
||||
var idx : integer;
|
||||
zMin,zMax : integer;
|
||||
begin
|
||||
idx:=lstProvider.IndexOf(aValue);
|
||||
if not((aValue='') or (idx<>-1)) then
|
||||
Raise Exception.Create('Unknow Provider : '+aValue);
|
||||
if Assigned(MapWin.MapProvider) and (MapWin.MapProvider.Name=AValue) then Exit;
|
||||
if idx<>-1 then
|
||||
Begin
|
||||
MapWin.MapProvider:=TMapProvider(lstProvider.Objects[idx]);
|
||||
ConstraintZoom(MapWin);
|
||||
end
|
||||
else
|
||||
MapWin.MapProvider:=nil;
|
||||
if Assigned(MapWin.MapProvider) then
|
||||
Redraw(MapWin);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMapViewerEngine.SetUseThreads(AValue: Boolean);
|
||||
begin
|
||||
if Queue.UseThreads=AValue then Exit;
|
||||
Queue.UseThreads:=AValue;
|
||||
Cache.UseThreads:=AValue;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetZoom: integer;
|
||||
begin
|
||||
Result:=MapWin.zoom;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetCacheOnDisk(AValue: Boolean);
|
||||
begin
|
||||
if Cache.UseDisk=AValue then Exit;
|
||||
Cache.UseDisk:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetCachePath(AValue: String);
|
||||
begin
|
||||
Cache.BasePath:=aValue;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetDownloadEngine(AValue: TCustomDownloadEngine);
|
||||
begin
|
||||
if FDownloadEngine=AValue then Exit;
|
||||
FDownloadEngine:=AValue;
|
||||
if Assigned(FDownloadEngine) then
|
||||
FDownloadEngine.FreeNotification(self);
|
||||
end;
|
||||
|
||||
|
||||
function TMapViewerEngine.GetHeight: integer;
|
||||
begin
|
||||
Result:=MapWin.Height
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetCacheOnDisk: Boolean;
|
||||
begin
|
||||
Result:=Cache.UseDisk;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetCachePath: String;
|
||||
begin
|
||||
Result:=Cache.BasePath;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetCenter: TRealPoint;
|
||||
begin
|
||||
Result:=MapWin.Center;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetMapProvider: String;
|
||||
begin
|
||||
if Assigned(MapWin.MapProvider) then
|
||||
Result:=MapWin.MapProvider.Name
|
||||
else
|
||||
Result:='';
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetUseThreads: Boolean;
|
||||
begin
|
||||
Result:=Queue.UseThreads;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetWidth: integer;
|
||||
begin
|
||||
Result:=MapWin.Width
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.ScreenToLonLat(aPt: TPoint): TRealPoint;
|
||||
begin
|
||||
Result:=MapWinToLonLat(MapWin,aPt);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.LonLatToScreen(aPt: TRealPoint): TPoint;
|
||||
Begin
|
||||
Result:=LonLatToMapWin(MapWin,aPt);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.WorldScreenToLonLat(aPt: TPoint): TRealPoint;
|
||||
begin
|
||||
aPt.X:=aPt.X-MapWin.X;
|
||||
aPt.Y:=aPt.Y-MapWin.Y;
|
||||
Result:=ScreenToLonLat(aPt);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.LonLatToWorldScreen(aPt: TRealPoint): TPoint;
|
||||
begin
|
||||
Result:=LonLatToScreen(aPt);
|
||||
Result.X:=Result.X+MapWin.X;
|
||||
Result.Y:=Result.Y+MapWin.Y;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetSize(aWidth, aHeight: integer);
|
||||
begin
|
||||
if (MapWin.Width=aWidth) and (MapWin.Height=aHeight) then Exit;
|
||||
CancelCurrentDrawing;
|
||||
MapWin.Width:=aWidth;
|
||||
MapWin.Height:=aHeight;
|
||||
CalculateWin(MapWin);
|
||||
Redraw(MapWin);
|
||||
if Assigned(Onchange) then
|
||||
OnChange(Self);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.MouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
if Button=mbLeft then
|
||||
DragObj.MouseDown(self,X,Y);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.MouseUp(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
if Button=mbLeft then
|
||||
DragObj.MouseUp(X,Y);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.MouseMove(Sender: TObject; Shift: TShiftState; X,
|
||||
Y: Integer);
|
||||
begin
|
||||
DragObj.MouseMove(X,Y);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.DblClick(Sender: TObject);
|
||||
var pt: TPoint;
|
||||
begin
|
||||
pt.X:=DragObj.MouseX;
|
||||
pt.Y:=DragObj.MouseY;
|
||||
SetCenter(ScreenToLonLat(pt));
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.MouseWheel(Sender: TObject;
|
||||
Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
|
||||
var Handled: Boolean);
|
||||
var Val : Integer;
|
||||
nZoom : integer;
|
||||
begin
|
||||
Val:=0;
|
||||
if WheelDelta>0 then
|
||||
Val:=1;
|
||||
if WheelDelta<0 then
|
||||
Val:=-1;
|
||||
nZoom:=Zoom+Val;
|
||||
if (nZoom>0) and (nZoom<20) then
|
||||
Zoom:=nZoom;
|
||||
Handled:=true;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetCenter(aCenter: TRealPoint);
|
||||
begin
|
||||
if (MapWin.Center.lon<>aCenter.Lon) and (MapWin.Center.lat<>aCenter.Lat) then
|
||||
Begin
|
||||
Mapwin.center:=aCenter;
|
||||
CalculateWin(MapWin);
|
||||
Redraw(MapWin);
|
||||
if assigned(OnCenterMove) then
|
||||
OnCenterMove(Self);
|
||||
if Assigned(OnChange) then
|
||||
OnChange(Self);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.ZoomOnArea(const aArea: TRealArea);
|
||||
var tmpWin : TMapWindow;
|
||||
visArea : TRealArea;
|
||||
TopLeft,BottomRight : TPoint;
|
||||
begin
|
||||
tmpWin:=MapWin;
|
||||
tmpWin.Center.Lon:=(aArea.TopLeft.Lon+aArea.BottomRight.Lon)/2;
|
||||
tmpWin.Center.Lat:=(aArea.TopLeft.Lat+aArea.BottomRight.Lat)/2;
|
||||
tmpWin.Zoom:=15;
|
||||
TopLeft.X:=0;
|
||||
TopLeft.Y:=0;
|
||||
BottomRight.X:=tmpWin.Width;
|
||||
BottomRight.Y:=tmpWin.Height;
|
||||
Repeat
|
||||
CalculateWin(tmpWin);
|
||||
visArea.TopLeft:=MapWinToLonLat(tmpWin,TopLeft);
|
||||
visArea.BottomRight:=MapWinToLonLat(tmpWin,BottomRight);
|
||||
if (AreaInsideArea(aArea,visArea)) then
|
||||
begin
|
||||
break;
|
||||
end;
|
||||
Dec(tmpWin.Zoom);
|
||||
until (tmpWin.Zoom=2);
|
||||
MapWin:=tmpWin;
|
||||
Redraw(MapWin);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.GetMapProviders(lst: TStrings);
|
||||
begin
|
||||
lst.Assign(lstProvider);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.LonLatToMapWin(const aWin : TMapWindow;aPt: TRealPoint): TPoint;
|
||||
var
|
||||
tiles: Int64;
|
||||
circumference: Int64;
|
||||
lat: Extended;
|
||||
res: Extended;
|
||||
tmpX,tmpY : Double;
|
||||
begin
|
||||
tiles := 1 shl aWin.Zoom;
|
||||
circumference := tiles * TILE_SIZE;
|
||||
tmpX := ((aPt.Lon+ 180.0)*circumference)/360.0;
|
||||
|
||||
res := (2 * pi * EARTH_RADIUS) / circumference;
|
||||
|
||||
|
||||
tmpY := -aPt.Lat;
|
||||
tmpY := ln(tan((degToRad(tmpY) + pi / 2.0) / 2)) *180 / pi;
|
||||
tmpY:= (((tmpY /180.0)*SHIFT)+SHIFT)/res;
|
||||
|
||||
tmpX := tmpX + aWin.X;
|
||||
tmpY := tmpY + aWin.Y;
|
||||
Result.X:=trunc(tmpX);
|
||||
Result.Y:=trunc(tmpY);
|
||||
End;
|
||||
|
||||
function TMapViewerEngine.MapWinToLonLat(const aWin: TMapWindow; aPt: TPoint): TRealPoint;
|
||||
var
|
||||
tiles: Int64;
|
||||
circumference: Int64;
|
||||
lat: Extended;
|
||||
res: Extended;
|
||||
mPoint : TPoint;
|
||||
begin
|
||||
tiles := 1 shl aWin.Zoom;
|
||||
circumference := tiles * TILE_SIZE;
|
||||
|
||||
mPoint.X := aPt.X - aWin.X;
|
||||
mPoint.Y := aPt.Y - aWin.Y;
|
||||
|
||||
if mPoint.X < 0 then
|
||||
mPoint.X := 0
|
||||
else
|
||||
if mPoint.X > circumference then
|
||||
mPoint.X := circumference;
|
||||
|
||||
if mPoint.Y < 0 then
|
||||
mPoint.Y := 0
|
||||
else
|
||||
if mPoint.Y > circumference then
|
||||
mPoint.Y := circumference;
|
||||
|
||||
|
||||
Result.Lon := ((mPoint.X * 360.0) / circumference) - 180.0;
|
||||
|
||||
res := (2 * pi * EARTH_RADIUS) / circumference;
|
||||
lat := ((mPoint.Y * res - SHIFT) / SHIFT) * 180.0;
|
||||
|
||||
lat := radtodeg (2 * arctan( exp( lat * pi / 180.0)) - pi / 2.0);
|
||||
Result.Lat := -lat;
|
||||
|
||||
if Result.Lat > MAX_LATITUDE then
|
||||
Result.Lat := MAX_LATITUDE
|
||||
else
|
||||
if Result.Lat < MIN_LATITUDE then
|
||||
Result.Lat := MIN_LATITUDE;
|
||||
|
||||
if Result.Lon > MAX_LONGITUDE then
|
||||
Result.Lon := MAX_LONGITUDE
|
||||
else
|
||||
if Result.Lon < MIN_LONGITUDE then
|
||||
Result.Lon := MIN_LONGITUDE;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.CalculateWin(var aWin: TMapWindow);
|
||||
var
|
||||
mx, my: Extended;
|
||||
res: Extended;
|
||||
px, py: Int64;
|
||||
|
||||
Begin
|
||||
|
||||
mx := aWin.Center.Lon * SHIFT / 180.0;
|
||||
my := ln( tan((90 - aWin.Center.Lat) * pi / 360.0 )) / (pi / 180.0);
|
||||
|
||||
my := my * SHIFT / 180.0;
|
||||
|
||||
res := (2 * pi * EARTH_RADIUS) / (TILE_SIZE * (1 shl aWin.Zoom));
|
||||
px := Round((mx + shift) / res);
|
||||
py := Round((my + shift) / res);
|
||||
|
||||
aWin.X := aWin.Width div 2 - px;
|
||||
aWin.Y := aWin.Height div 2 - py;
|
||||
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.IsValidTile(const aWin: TMapWindow;const aTile : TTIleId) : boolean;
|
||||
var tiles : int64;
|
||||
begin
|
||||
tiles := 1 shl aWin.Zoom;
|
||||
Result:=(aTile.X>=0) and (aTile.X<=tiles-1) and (aTile.Y>=0) and (aTile.Y<=tiles-1);
|
||||
end;
|
||||
|
||||
|
||||
procedure TMapViewerEngine.Redraw(const aWin: TmapWindow);
|
||||
var TilesVis : TArea;
|
||||
x,y : Integer; //int64;
|
||||
Tiles : TTileIdArray;
|
||||
iTile : Integer;
|
||||
begin
|
||||
if not(Active) then
|
||||
Exit;
|
||||
Queue.CancelAllJob(self);
|
||||
TilesVis:=CalculateVisibleTiles(aWin);
|
||||
SetLength(Tiles,(TilesVis.Bottom-TilesVis.top+1)*(TilesVis.Right-TilesVis.Left+1));
|
||||
iTile:=low(Tiles);
|
||||
For y:=TilesVis.top to TilesVis.Bottom do
|
||||
For X:=TilesVis.Left to TilesVis.Right do
|
||||
Begin
|
||||
Tiles[iTile].X:=X;
|
||||
Tiles[iTile].Y:=Y;
|
||||
Tiles[iTile].Z:=aWin.Zoom;
|
||||
if IsValidTile(aWin,Tiles[iTile]) then
|
||||
iTile+=1;
|
||||
end;
|
||||
SetLength(Tiles,iTile);
|
||||
if length(Tiles)>0 then
|
||||
Begin
|
||||
Queue.AddJob(TLaunchDownloadJob.Create(self,Tiles,aWin),self);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.CalculateVisibleTiles(const aWin: TMapWindow): TArea;
|
||||
var MaxX,MAxY,Startx,StartY : int64;
|
||||
begin
|
||||
MaxX := (aWin.Width div TILE_SIZE) + 1;
|
||||
MaxY := (aWin.Height div TILE_SIZE) + 1;
|
||||
startX := (-(aWin.X)) div TILE_SIZE;
|
||||
startY := (-(aWin.Y)) div TILE_SIZE;
|
||||
Result.Left := startX;
|
||||
Result.right := startX + MaxX;
|
||||
Result.top := startY;
|
||||
Result.bottom := startY + MaxY;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.IsCurrentWin(const aWin: TMapWindow): boolean;
|
||||
begin
|
||||
Result:=(aWin.Zoom=MapWin.Zoom) and (aWin.Center.Lat=MapWin.Center.Lat) and (aWin.Center.Lon=MapWin.Center.Lon) and (aWin.Width=MapWin.Width) and (aWin.Height=MapWin.Height);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetTileName(const Id: TTileId): String;
|
||||
begin
|
||||
Result:=Inttostr(Id.X)+'.'+inttostr(Id.Y)+'.'+inttostr(Id.Z);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.evDownload(Data : TObject;Job : TJob);
|
||||
var Id : TTileId;
|
||||
Url : String;
|
||||
Env : TEnvTile;
|
||||
MapO : TMapProvider;
|
||||
FStream : TMemoryStream;
|
||||
Begin
|
||||
Env:=TEnvTile(Data);
|
||||
Id:=Env.Tile;
|
||||
MapO:=Env.Win.MapProvider;
|
||||
if Assigned(MapO) then
|
||||
Begin
|
||||
if not(Cache.InCache(MapO,Id)) then
|
||||
Begin
|
||||
if Assigned(FDownloadEngine) then
|
||||
begin
|
||||
Url:=MapO.GetUrlForTile(Id);
|
||||
if Url<>'' then
|
||||
begin
|
||||
FStream:=TMemoryStream.Create;
|
||||
Try
|
||||
Try
|
||||
FDownloadEngine.DownloadFile(Url,Fstream);
|
||||
Cache.Add(MapO,Id,FStream);
|
||||
except
|
||||
end;
|
||||
finally
|
||||
FreeAndNil(FStream);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if Job.Cancelled then
|
||||
Exit;
|
||||
if DrawTitleInGuiThread then
|
||||
Queue.QueueAsyncCall(@TileDownloaded,PtrInt(Env))
|
||||
else
|
||||
TileDownloaded(PtrInt(Env));
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.TileDownloaded(Data: PtrInt);
|
||||
var EnvTile : TEnvTile;
|
||||
img : TLazIntfImage;
|
||||
X,Y : integer;
|
||||
begin
|
||||
EnvTile:=TEnvTile(Data);
|
||||
Try
|
||||
if IsCurrentWin(EnvTile.Win)then
|
||||
Begin
|
||||
Cache.GetFromCache(EnvTile.Win.MapProvider,EnvTile.Tile,img);
|
||||
X := EnvTile.Win.X + EnvTile.Tile.X * TILE_SIZE; // begin of X
|
||||
Y := EnvTile.Win.Y + EnvTile.Tile.Y * TILE_SIZE; // begin of X
|
||||
DrawTile(EnvTile.Tile,X,Y,img);
|
||||
end;
|
||||
finally
|
||||
FreeAndNil(EnvTile);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetLetterSvr(id: integer): String;
|
||||
Begin
|
||||
Result:=Char(Ord('a')+id);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetYahooSvr(id: integer): String;
|
||||
Begin
|
||||
Result:=inttostr(id+1);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetYahooY(const Tile : TTileId): string;
|
||||
Begin
|
||||
Result :=inttostr( - (Tile.Y - (1 shl Tile.Z) div 2) - 1);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetYahooZ(const Tile : TTileId): string;
|
||||
Begin
|
||||
result:=inttostr(Tile.Z+1);
|
||||
end;
|
||||
|
||||
function TMapViewerEngine.GetQuadKey(const Tile : TTileId): string;
|
||||
var
|
||||
i, d, m: Longword;
|
||||
begin
|
||||
{
|
||||
Bing Maps Tile System
|
||||
http://msdn.microsoft.com/en-us/library/bb259689.aspx
|
||||
}
|
||||
Result := '';
|
||||
for i := Tile.Z downto 1 do
|
||||
begin
|
||||
d := 0;
|
||||
m := 1 shl (i - 1);
|
||||
if (Tile.x and m) <> 0 then
|
||||
Inc(d, 1);
|
||||
if (Tile.y and m) <> 0 then
|
||||
Inc(d, 2);
|
||||
Result := Result + IntToStr(d);
|
||||
end;
|
||||
end;
|
||||
|
||||
Type
|
||||
|
||||
{ TMemObj }
|
||||
|
||||
TMemObj = Class
|
||||
private
|
||||
FWin : TMapWindow;
|
||||
public
|
||||
constructor Create(const aWin : TMapWindow);
|
||||
End;
|
||||
|
||||
{ TMemObj }
|
||||
|
||||
constructor TMemObj.Create(const aWin: TMapWindow);
|
||||
begin
|
||||
FWin:=aWin;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMapViewerEngine.MoveMapCenter(Sender: TDragObj);
|
||||
var old : TMemObj;
|
||||
nCenter : TRealPoint;
|
||||
Job : TJob;
|
||||
aPt : TPoint;
|
||||
Begin
|
||||
if Sender.LnkObj=nil then
|
||||
Begin
|
||||
Sender.LnkObj:=TMemObj.Create(MapWin);
|
||||
end;
|
||||
old:=TMemObj(Sender.LnkObj);
|
||||
aPt.X:=old.FWin.Width DIV 2-Sender.OfsX;
|
||||
aPt.Y:=old.FWin.Height DIV 2-Sender.OfsY;
|
||||
nCenter:=MapWinToLonLat(old.FWin,aPt);
|
||||
SetCenter(nCenter);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.SetActive(AValue: boolean);
|
||||
begin
|
||||
if FActive=AValue then Exit;
|
||||
FActive:=AValue;
|
||||
if not(FActive) then
|
||||
Queue.CancelAllJob(self)
|
||||
else
|
||||
Redraw(MapWin);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.DoDrag(Sender: TDragObj);
|
||||
begin
|
||||
if Sender.DragSrc=self then
|
||||
Begin
|
||||
MoveMapCenter(Sender);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.CancelCurrentDrawing;
|
||||
var Jobs : TJobArray;
|
||||
begin
|
||||
Jobs:=Queue.CancelAllJob(self);
|
||||
Queue.WaitForTerminate(Jobs);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.Redraw;
|
||||
begin
|
||||
Redraw(MapWin);
|
||||
end;
|
||||
|
||||
|
||||
function TMapViewerEngine.AddMapProvider(OpeName: String; Url: String;
|
||||
MinZoom : integer;MaxZoom : integer;
|
||||
NbSvr: integer; GetSvrStr: TGetSvrStr; GetXStr: TGetValStr;
|
||||
GetYStr: TGetValStr; GetZStr: TGetValStr) : TMapProvider;
|
||||
var idx :integer;
|
||||
Begin
|
||||
idx:=lstProvider.IndexOf(OpeName);
|
||||
if idx=-1 then
|
||||
Begin
|
||||
result:=TMapProvider.Create(OpeName);
|
||||
lstProvider.AddObject(OpeName,result);
|
||||
end
|
||||
else
|
||||
result:=TMapProvider(lstProvider.Objects[idx]);
|
||||
result.AddUrl(Url,NbSvr,MinZoom,MaxZoom,GetSvrStr,GetXStr,GetYStr,GetZStr);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.RegisterProviders;
|
||||
begin
|
||||
AddMapProvider('Aucun','',0,30, 0);
|
||||
{
|
||||
AddMapProvider('Google Satellite','http://khm%d.google.com/kh/v=82&x=%x%&y=%y%&z=%z%&s=Ga',4);
|
||||
AddMapProvider('Google Hybrid','http://khm%d.google.com/kh/v=82&x=%x%&y=%y%&z=%z%&s=Ga',4);
|
||||
AddMapProvider('Google Hybrid','http://mt%d.google.com/vt/lyrs=h@145&v=w2.104&x=%d&y=%d&z=%z%',4);
|
||||
AddMapProvider('Google physical','http://mt%d.google.com/vt/lyrs=t@145&v=w2.104&x=%d&y=%d&z=%z%',4);
|
||||
AddMapProvider('Google Physical Hybrid','http://mt%d.google.com/vt/lyrs=t@145&v=w2.104&x=%x%&y=%y%&z=%z%',4);
|
||||
AddMapProvider('Google Physical Hybrid','http://mt%d.google.com/vt/lyrs=h@145&v=w2.104&x=%x%&y=%y%&z=%z%',4);}
|
||||
//AddMapProvider('OpenStreetMap Osmarender','http://%serv%.tah.openstreetmap.org/Tiles/tile/%z%/%x%/%y%.png',0,20,3, @getLetterSvr); // [Char(Ord('a')+Random(3)), Z, X, Y]));
|
||||
//AddMapProvider('Yahoo Normal','http://maps%serv%.yimg.com/hx/tl?b=1&v=4.3&.intl=en&x=%x%&y=%y%d&z=%d&r=1' , 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //(Z+1]));
|
||||
//AddMapProvider('Yahoo Satellite','http://maps%serv%.yimg.com/ae/ximg?v=1.9&t=a&s=256&.intl=en&x=%d&y=%d&z=%d&r=1', 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
|
||||
//AddMapProvider('Yahoo Hybrid','http://maps%serv%.yimg.com/ae/ximg?v=1.9&t=a&s=256&.intl=en&x=%x%&y=%y%&z=%z%&r=1', 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
|
||||
//AddMapProvider('Yahoo Hybrid','http://maps%serv%.yimg.com/hx/tl?b=1&v=4.3&t=h&.intl=en&x=%x%&y=%y%&z=%z%&r=1' , 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
|
||||
|
||||
MapWin.MapProvider:=AddMapProvider('OpenStreetMap Mapnik','http://%serv%.tile.openstreetmap.org/%z%/%x%/%y%.png',0,19, 3, @getLetterSvr);
|
||||
AddMapProvider('Open Cycle Map','http://%serv%.tile.opencyclemap.org/cycle/%z%/%x%/%y%.png',0,18,3, @getLetterSvr);
|
||||
AddMapProvider('Virtual Earth Bing','http://ecn.t%serv%.tiles.virtualearth.net/tiles/r%x%?g=671&mkt=en-us&lbl=l1&stl=h&shading=hill',1,19,8,nil,@GetQuadKey);
|
||||
AddMapProvider('Virtual Earth Road','http://r%serv%.ortho.tiles.virtualearth.net/tiles/r%x%.png?g=72&shading=hill',1,19,4,nil,@getQuadKey);
|
||||
AddMapProvider('Virtual Earth Aerial','http://a%serv%.ortho.tiles.virtualearth.net/tiles/a%x%.jpg?g=72&shading=hill',1,19,4,nil,@getQuadKey);
|
||||
AddMapProvider('Virtual Earth Hybrid','http://h%serv%.ortho.tiles.virtualearth.net/tiles/h%x%.jpg?g=72&shading=hill',1,19,4,nil,@getQuadKey);
|
||||
AddMapProvider('Ovi Normal', 'http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/normal.day/%z%/%x%/%y%/256/png8', 0,20,5,@getLetterSvr);
|
||||
AddMapProvider('Ovi Satellite','http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/satellite.day/%z%/%x%/%y%/256/png8', 0,20,5,@getLetterSvr);
|
||||
AddMapProvider('Ovi Hybrid','http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/hybrid.day/%z%/%x%/%y%/256/png8', 0,20,5,@getLetterSvr);
|
||||
AddMapProvider('Ovi Physical','http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/terrain.day/%z%/%x%/%y%/256/png8', 0,20,5,@getLetterSvr);
|
||||
end;
|
||||
|
||||
procedure TMapViewerEngine.DrawTile(const TileId : TTileId;X, Y: integer; TileImg: TLazIntfImage);
|
||||
begin
|
||||
if Assigned(FOnDrawTile) then
|
||||
FOnDrawTile(TileId,X,Y,TileImg);
|
||||
end;
|
||||
|
||||
constructor TMapViewerEngine.Create(aOwner: TComponent);
|
||||
begin
|
||||
DrawTitleInGuiThread := true;
|
||||
DragObj := TDragObj.Create;
|
||||
DragObj.OnDrag:=@DoDrag;
|
||||
Cache := TPictureCache.Create(self);
|
||||
lstProvider:=TStringList.Create;
|
||||
RegisterProviders;
|
||||
Queue:=TJobQueue.Create(8);
|
||||
Queue.OnIdle:= @Cache.CheckCacheSize;
|
||||
inherited Create(aOwner);
|
||||
ConstraintZoom(MapWin);
|
||||
CalculateWin(mapWin);
|
||||
end;
|
||||
|
||||
destructor TMapViewerEngine.Destroy;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
FreeAndNil(DragObj);
|
||||
for i:=0 to lstProvider.Count-1 do
|
||||
TObject(lstProvider.Objects[i]).Free;
|
||||
FreeAndNil(lstProvider);
|
||||
FreeAndNil(Cache);
|
||||
FreeAndNil(Queue);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
43
components/lazmapviewer/source/mvextradata.pas
Normal file
43
components/lazmapviewer/source/mvextradata.pas
Normal file
@ -0,0 +1,43 @@
|
||||
unit mvextradata;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,graphics;
|
||||
|
||||
type
|
||||
|
||||
{ TDrawingExtraData }
|
||||
|
||||
TDrawingExtraData = class
|
||||
private
|
||||
FColor: TColor;
|
||||
FId: integer;
|
||||
procedure SetColor(AValue: TColor);
|
||||
public
|
||||
constructor Create(aId : integer);virtual;
|
||||
property Color : TColor read FColor write SetColor;
|
||||
property Id : integer read FId;
|
||||
End;
|
||||
|
||||
implementation
|
||||
|
||||
{ TDrawingExtraData }
|
||||
|
||||
|
||||
procedure TDrawingExtraData.SetColor(AValue: TColor);
|
||||
begin
|
||||
if FColor=AValue then Exit;
|
||||
FColor:=AValue;
|
||||
end;
|
||||
|
||||
constructor TDrawingExtraData.Create(aId: integer);
|
||||
begin
|
||||
FId:=aId;
|
||||
FColor:=clRed;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
197
components/lazmapviewer/source/mvgeonames.pas
Normal file
197
components/lazmapviewer/source/mvgeonames.pas
Normal file
@ -0,0 +1,197 @@
|
||||
{ Map Viewer Geolocation Engine for geonames.org
|
||||
|
||||
Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvGeoNames;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes, StrUtils,
|
||||
mvTypes, mvDownloadEngine;
|
||||
|
||||
type
|
||||
TNameFoundEvent = procedure (const AName: string; const ADescr: String;
|
||||
const ALoc: TRealPoint) of object;
|
||||
|
||||
TStringArray = array of string;
|
||||
|
||||
{ TMVGeoNames }
|
||||
|
||||
TMVGeoNames = class(TComponent)
|
||||
private
|
||||
FLocationName: string;
|
||||
FOnNameFound: TNameFoundEvent;
|
||||
function RemoveTag(const str: String): TStringArray;
|
||||
public
|
||||
function DoSearch(dl : TCustomDownloadEngine): TRealPoint;
|
||||
published
|
||||
property LocationName: string read FLocationName write FLocationName;
|
||||
property OnNameFound : TNameFoundEvent read FOnNameFound write FOnNameFound;
|
||||
end;
|
||||
|
||||
procedure Register;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
function CleanLocationName(x: string): string;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result := '';
|
||||
for i := 1 to Length(x) do
|
||||
begin
|
||||
if x[i] in ['A'..'Z', 'a'..'z', '0'..'9'] then
|
||||
Result := Result + x[i]
|
||||
else
|
||||
Result := Result + '+'
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TMVGeoNames }
|
||||
|
||||
Type
|
||||
TResRec = record
|
||||
Name : String;
|
||||
Descr : String;
|
||||
Loc : TRealPoint;
|
||||
End;
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
RegisterComponents('Maps',[TMVGeoNames]);
|
||||
end;
|
||||
|
||||
function TMVGeoNames.RemoveTag(Const str : String) : TStringArray;
|
||||
var iStart,iEnd,i : Integer;
|
||||
tmp : String;
|
||||
lst : TStringList;
|
||||
Begin
|
||||
SetLength(Result,0);
|
||||
tmp:=StringReplace(str,'<br>',#13,[rfReplaceall]);
|
||||
tmp:=StringReplace(tmp,' ',' ',[rfReplaceall]);
|
||||
tmp:=StringReplace(tmp,' ',' ',[rfReplaceall]);
|
||||
repeat
|
||||
iEnd:=-1;
|
||||
iStart:=pos('<',tmp);
|
||||
if iStart>0 then
|
||||
Begin
|
||||
iEnd:=posEx('>',tmp,iStart);
|
||||
if iEnd>0 then
|
||||
Begin
|
||||
tmp:=copy(tmp,1,iStart-1)+copy(tmp,iEnd+1,length(tmp));
|
||||
end;
|
||||
end;
|
||||
until iEnd<=0;
|
||||
lst:=TStringList.Create;
|
||||
try
|
||||
lst.Text:=tmp;
|
||||
SetLEngth(Result,lst.Count);
|
||||
For i:=0 to pred(lst.Count) do
|
||||
Result[i]:=trim(lst[i]);
|
||||
finally
|
||||
freeAndNil(lst);
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
function TMVGeoNames.DoSearch(dl: TCustomDownloadEngine): TRealPoint;
|
||||
const
|
||||
LAT_ID = '<span class="latitude">';
|
||||
LONG_ID = '<span class="longitude">';
|
||||
var
|
||||
s: string;
|
||||
|
||||
function gs(id: string;Start : integer): string;
|
||||
var
|
||||
i: Integer;
|
||||
ln: Integer;
|
||||
begin
|
||||
Result := '';
|
||||
ln := Length(s);
|
||||
i := PosEx(id, s,start) + Length(id);
|
||||
while (s[i] <> '<') and (i < ln) do
|
||||
begin
|
||||
if s[i] = '.' then
|
||||
Result := Result + DecimalSeparator
|
||||
else
|
||||
Result := Result + s[i];
|
||||
Inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
m: TMemoryStream;
|
||||
iRes,i : integer;
|
||||
lstRes : Array of TResRec;
|
||||
iStartDescr : integer;
|
||||
lst : TStringArray;
|
||||
begin
|
||||
m := TMemoryStream.Create;
|
||||
try
|
||||
dl.DownloadFile('http://www.geonames.org/search.html?q='+
|
||||
CleanLocationName(FLocationName), m);
|
||||
m.Position := 0;
|
||||
SetLength(s, m.Size);
|
||||
m.Read(s[1], m.Size);
|
||||
finally
|
||||
m.Free;
|
||||
end;
|
||||
|
||||
Result.Lon := 0;
|
||||
Result.Lat:=0;
|
||||
SetLength(lstRes,0);
|
||||
iRes:=Pos('<span class="geo"',s);
|
||||
while (iRes>0) do
|
||||
Begin
|
||||
SetLength(lstRes,length(lstRes)+1);
|
||||
lstRes[high(lstRes)].Loc.Lon:=strtofloat(gs(LONG_ID,iRes));
|
||||
lstRes[high(lstRes)].Loc.Lat:=strtofloat(gs(LAT_ID,iRes));
|
||||
iStartDescr:=RPosex('<td>',s,iRes);
|
||||
if iStartDescr>0 then
|
||||
Begin
|
||||
lst:=RemoveTag(Copy(s,iStartDescr,iRes-iStartDescr));
|
||||
if length(lst)>0 then
|
||||
lstRes[high(lstRes)].Name:=lst[0];
|
||||
lstRes[high(lstRes)].Descr:='';
|
||||
For i:=1 to high(lst) do
|
||||
lstRes[high(lstRes)].Descr+=lst[i];
|
||||
end;
|
||||
|
||||
Result.Lon += lstRes[high(lstRes)].Loc.Lon;
|
||||
Result.Lat += lstRes[high(lstRes)].Loc.Lat;
|
||||
iRes:=PosEx('<span class="geo"',s,iRes+17);
|
||||
End;
|
||||
|
||||
if length(lstRes)>0 then
|
||||
Begin
|
||||
if length(lstRes)>1 then
|
||||
begin
|
||||
Result.Lon := Result.Lon/length(lstRes);
|
||||
Result.Lat := Result.Lat/length(lstRes);
|
||||
end;
|
||||
if Assigned(FOnNameFound) then
|
||||
For iRes:=low(lstRes) to high(lstRes) do
|
||||
Begin
|
||||
FOnNameFound(lstRes[iRes].Name,lstRes[iRes].Descr,lstRes[iRes].Loc);
|
||||
end;
|
||||
End;
|
||||
|
||||
end;
|
||||
|
||||
end.
|
728
components/lazmapviewer/source/mvgpsobj.pas
Normal file
728
components/lazmapviewer/source/mvgpsobj.pas
Normal file
@ -0,0 +1,728 @@
|
||||
{ Map Viewer - basic gps object
|
||||
|
||||
Copyright (C) 2014 ti_dic@hotmail.com
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}unit mvgpsobj;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,fgl,mvtypes,contnrs,syncobjs;
|
||||
const
|
||||
NO_ELE = -10000000;
|
||||
NO_DATE = 0;
|
||||
type
|
||||
TIdArray = Array of integer;
|
||||
|
||||
{ TGPSObj }
|
||||
|
||||
TGPSObj = Class
|
||||
private
|
||||
BBoxSet : Boolean;
|
||||
FBoundingBox : TRealArea;
|
||||
FExtraData: TObject;
|
||||
FName: String;
|
||||
FIdOwner : integer;
|
||||
function GetBoundingBox: TRealArea;
|
||||
procedure SetBoundingBox(AValue: TRealArea);
|
||||
procedure SetExtraData(AValue: TObject);
|
||||
public
|
||||
destructor Destroy;override;
|
||||
Procedure GetArea(out Area : TRealArea);virtual;abstract;
|
||||
property Name : String read FName write FName;
|
||||
property ExtraData : TObject read FExtraData write SetExtraData;
|
||||
property BoundingBox : TRealArea read GetBoundingBox write SetBoundingBox;
|
||||
|
||||
end;
|
||||
|
||||
TGPSObjarray = Array of TGPSObj;
|
||||
|
||||
{ TGPSPoint }
|
||||
|
||||
TGPSPoint = Class(TGPSObj)
|
||||
private
|
||||
FRealPt : TRealPoint;
|
||||
FEle : Double;
|
||||
FDateTime : TDateTime;
|
||||
function GetLat: Double;
|
||||
function GetLon: Double;
|
||||
public
|
||||
Procedure GetArea(out Area : TRealArea);override;
|
||||
Function HasEle : boolean;
|
||||
Function HasDateTime : Boolean;
|
||||
Function DistanceInKmFrom(OtherPt : TGPSPoint;UseEle : boolean=true) : double;
|
||||
constructor Create(ALon,ALat : double;AEle : double=NO_ELE;ADateTime : TDateTime=NO_DATE);
|
||||
Class function CreateFrom(aPt : TRealPoint) : TGPSPoint;
|
||||
|
||||
property Lon : Double read GetLon;
|
||||
property Lat : Double read GetLat;
|
||||
property Ele : double read FEle;
|
||||
property DateTime : TDateTime read FDateTime;
|
||||
property RealPoint : TRealPoint read FRealPt;
|
||||
end;
|
||||
|
||||
TGPSPointList = specialize TFPGObjectList<TGPSPoint>;
|
||||
|
||||
{ TGPSTrack }
|
||||
|
||||
TGPSTrack = Class(TGPSObj)
|
||||
private
|
||||
FDateTime: TDateTime;
|
||||
FPoints : TGPSPointList;
|
||||
function GetDateTime: TDateTime;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy;override;
|
||||
|
||||
Procedure GetArea(out Area : TRealArea);override;
|
||||
Function TrackLengthInKm(UseEle : Boolean=true) : double;
|
||||
|
||||
property Points : TGPSPointList read FPoints;
|
||||
property DateTime : TDateTime read GetDateTime write FDateTime;
|
||||
end;
|
||||
|
||||
TGPSObjList_ = specialize TFPGObjectList<TGPSObj>;
|
||||
|
||||
{ TGPSObjList }
|
||||
|
||||
TGPSObjList = class(TGPSObjList_)
|
||||
private
|
||||
FRef : TObject;
|
||||
public
|
||||
Destructor Destroy;override;
|
||||
end;
|
||||
|
||||
{ TGPSObjectList }
|
||||
TModifiedEvent = procedure (Sender : TObject;objs : TGPSObjList;Adding : boolean) of object;
|
||||
|
||||
TGPSObjectList = Class(TGPSObj)
|
||||
private
|
||||
Crit:TCriticalSection;
|
||||
FPending : TObjectList;
|
||||
FRefCount : integer;
|
||||
FOnModified: TModifiedEvent;
|
||||
FUpdating : integer;
|
||||
FItems : TGPSObjList;
|
||||
function Getcount: integer;
|
||||
protected
|
||||
Procedure _Delete(Idx : Integer;out DelLst : TGPSObjList);
|
||||
Procedure FreePending;
|
||||
Procedure DecRef;
|
||||
procedure Lock;
|
||||
procedure UnLock;
|
||||
procedure CallModified(lst : TGPSObjList;Adding : boolean);
|
||||
property Items : TGPSObjList read FItems;
|
||||
procedure IdsToObj(const Ids : TIdArray;out objs : TGPSObjArray;IdOwner : integer);
|
||||
public
|
||||
Procedure GetArea(out Area : TRealArea);override;
|
||||
function GetObjectsInArea(const Area: TRealArea): TGPSObjList;
|
||||
constructor Create;
|
||||
destructor Destroy;override;
|
||||
Procedure Clear(OwnedBy : integer);
|
||||
procedure ClearExcept(OwnedBy : integer;const ExceptLst : TIdArray;out Notfound : TIdArray);
|
||||
function GetIdsArea(const Ids : TIdArray;IdOwner : integer) : TRealArea;
|
||||
|
||||
function Add(aItem : TGpsObj;IdOwner : integer) : integer;
|
||||
Procedure DeleteById(const Ids : Array of integer);
|
||||
|
||||
Procedure BeginUpdate;
|
||||
Procedure EndUpdate;
|
||||
|
||||
property Count : integer read Getcount;
|
||||
property OnModified : TModifiedEvent read FOnModified write FOnModified;
|
||||
end;
|
||||
|
||||
function hasIntersectArea(const Area1 : TRealArea;const Area2 : TRealArea) : boolean;
|
||||
function IntersectArea(const Area1 : TRealArea;const Area2 : TRealArea) : TRealArea;
|
||||
function PtInsideArea(const aPoint : TRealPoint;const Area : TRealArea) : boolean;
|
||||
Function AreaInsideArea(const AreaIn : TRealArea;const AreaOut : TRealArea) : boolean;
|
||||
Procedure ExtendArea(var AreaToExtend : TRealArea;Const Area : TRealArea);
|
||||
Function GetAreaOf(objs : TGPSObjList) : TRealArea;
|
||||
|
||||
|
||||
implementation
|
||||
uses mvextradata;
|
||||
|
||||
function hasIntersectArea(const Area1: TRealArea; const Area2: TRealArea): boolean;
|
||||
begin
|
||||
Result:=(Area1.TopLeft.Lon<=Area2.BottomRight.Lon) and (Area1.BottomRight.Lon>=Area2.TopLeft.Lon) and
|
||||
(Area1.TopLeft.Lat>=Area2.BottomRight.Lat) and (Area1.BottomRight.Lat<=Area2.TopLeft.Lat);
|
||||
end;
|
||||
|
||||
function IntersectArea(const Area1: TRealArea; const Area2: TRealArea
|
||||
): TRealArea;
|
||||
begin
|
||||
Result:=Area1;
|
||||
if Result.TopLeft.Lon<Area2.topLeft.Lon then
|
||||
Result.TopLeft.Lon:=Area2.topLeft.Lon;
|
||||
if Result.TopLeft.Lat>Area2.topLeft.Lat then
|
||||
Result.TopLeft.Lat:=Area2.topLeft.Lat;
|
||||
if Result.BottomRight.Lon>Area2.BottomRight.Lon then
|
||||
Result.BottomRight.Lon:=Area2.BottomRight.Lon;
|
||||
if Result.BottomRight.Lat<Area2.BottomRight.Lat then
|
||||
Result.BottomRight.Lat:=Area2.BottomRight.Lat;
|
||||
end;
|
||||
|
||||
function PtInsideArea(const aPoint: TRealPoint; const Area: TRealArea): boolean;
|
||||
begin
|
||||
Result:=(Area.TopLeft.Lon<=aPoint.Lon) and (Area.BottomRight.Lon>=aPoint.Lon) and
|
||||
(Area.TopLeft.Lat>=aPoint.Lat) and (Area.BottomRight.Lat<=aPoint.Lat);
|
||||
end;
|
||||
|
||||
function AreaInsideArea(const AreaIn: TRealArea; const AreaOut: TRealArea
|
||||
): boolean;
|
||||
begin
|
||||
Result:=(AreaIn.TopLeft.Lon>=AreaOut.TopLeft.Lon) and (AreaIn.BottomRight.Lon<=AreaOut.BottomRight.Lon) and
|
||||
(AreaOut.TopLeft.Lat>=AreaIn.TopLeft.Lat) and (AreaOut.BottomRight.Lat<=AreaIn.BottomRight.Lat);
|
||||
end;
|
||||
|
||||
procedure ExtendArea(var AreaToExtend: TRealArea; const Area: TRealArea);
|
||||
begin
|
||||
if AreaToExtend.TopLeft.Lon>Area.TopLeft.Lon then
|
||||
AreaToExtend.TopLeft.Lon:=Area.TopLeft.Lon;
|
||||
if AreaToExtend.BottomRight.Lon<Area.BottomRight.Lon then
|
||||
AreaToExtend.BottomRight.Lon:=Area.BottomRight.Lon;
|
||||
|
||||
if AreaToExtend.TopLeft.Lat<Area.TopLeft.Lat then
|
||||
AreaToExtend.TopLeft.Lat:=Area.TopLeft.Lat;
|
||||
if AreaToExtend.BottomRight.Lat>Area.BottomRight.Lat then
|
||||
AreaToExtend.BottomRight.Lat:=Area.BottomRight.Lat;
|
||||
end;
|
||||
|
||||
function GetAreaOf(objs: TGPSObjList): TRealArea;
|
||||
var i : integer;
|
||||
begin
|
||||
Result.TopLeft.Lon:=0;
|
||||
Result.TopLeft.Lat:=0;
|
||||
Result.BottomRight.Lon:=0;
|
||||
Result.BottomRight.Lat:=0;
|
||||
if Objs.Count>0 then
|
||||
Begin
|
||||
Result:=Objs[0].BoundingBox;
|
||||
For i:=1 to pred(Objs.Count) do
|
||||
ExtendArea(Result,Objs[i].BoundingBox);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TGPSObjList }
|
||||
|
||||
destructor TGPSObjList.Destroy;
|
||||
begin
|
||||
if Assigned(FRef) then
|
||||
TGPSObjectList(FRef).DecRef;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TGPSObj }
|
||||
|
||||
procedure TGPSObj.SetExtraData(AValue: TObject);
|
||||
begin
|
||||
if FExtraData=AValue then Exit;
|
||||
if Assigned(FExtraData) then
|
||||
FreeAndNil(FExtraData);
|
||||
FExtraData:=AValue;
|
||||
end;
|
||||
|
||||
function TGPSObj.GetBoundingBox: TRealArea;
|
||||
begin
|
||||
if not(BBoxSet) then
|
||||
Begin
|
||||
GetArea(FBoundingBox);
|
||||
BBoxSet:=true;
|
||||
end;
|
||||
Result:=FBoundingBox;
|
||||
end;
|
||||
|
||||
procedure TGPSObj.SetBoundingBox(AValue: TRealArea);
|
||||
begin
|
||||
FBoundingBox:=AValue;
|
||||
BBoxSet:=true;
|
||||
end;
|
||||
|
||||
destructor TGPSObj.Destroy;
|
||||
begin
|
||||
FreeAndNil(FExtraData);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TGPSObjectList }
|
||||
|
||||
function TGPSObjectList.Getcount: integer;
|
||||
begin
|
||||
Result:=FItems.Count
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList._Delete(Idx: Integer; out DelLst: TGPSObjList);
|
||||
var Item : TGpsObj;
|
||||
begin
|
||||
Lock;
|
||||
Try
|
||||
if not(Assigned(DelLst)) then
|
||||
Begin
|
||||
DelLst:=TGpsObjList.Create(False);
|
||||
DelLst.FRef:=Self;
|
||||
inc(FRefCount);
|
||||
end;
|
||||
if not Assigned(FPending) then
|
||||
FPending:=TObjectList.Create(true);
|
||||
Item:=Items.Extract(Items[Idx]);
|
||||
FPending.Add(Item);
|
||||
finally
|
||||
UnLock;
|
||||
end;
|
||||
DelLst.Add(Item);
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.FreePending;
|
||||
begin
|
||||
if Assigned(FPending) then
|
||||
Begin
|
||||
Lock;
|
||||
Try
|
||||
FreeAndNil(FPending);
|
||||
finally
|
||||
UnLock;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.DecRef;
|
||||
begin
|
||||
FRefCount-=1;
|
||||
if FRefCount=0 then
|
||||
FreePending;
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.Lock;
|
||||
begin
|
||||
if Assigned(Crit) then
|
||||
Crit.Enter;
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.UnLock;
|
||||
begin
|
||||
if Assigned(Crit) then
|
||||
Crit.Leave;
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.CallModified(lst: TGPSObjList; Adding: boolean);
|
||||
begin
|
||||
if (FUpdating=0) and Assigned(FOnModified) then
|
||||
FOnModified(self,lst,Adding)
|
||||
else
|
||||
lst.Free;
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.IdsToObj(const Ids: TIdArray; out objs: TGPSObjArray;IdOwner : integer);
|
||||
|
||||
function ToSelect(aId : integer) : boolean;
|
||||
var i : integer;
|
||||
begin
|
||||
result:=false;
|
||||
for i:=low(Ids) to high(Ids) do
|
||||
if Ids[i]=aId then
|
||||
begin
|
||||
result:=true;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
var i,nb : integer;
|
||||
begin
|
||||
SetLength(objs,length(Ids));
|
||||
nb:=0;
|
||||
Lock;
|
||||
Try
|
||||
for i:=0 to pred(FItems.Count) do
|
||||
begin
|
||||
if (IdOwner=0) or (IdOwner=FItems[i].FIdOwner) then
|
||||
if Assigned(FItems[i].ExtraData) and FItems[i].ExtraData.InheritsFrom(TDrawingExtraData) then
|
||||
Begin
|
||||
if ToSelect(TDrawingExtraData(FItems[i].ExtraData).Id) then
|
||||
Begin
|
||||
objs[nb]:=FItems[i];
|
||||
nb+=1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
SetLength(objs,nb);
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.GetArea(out Area: TRealArea);
|
||||
var i : integer;
|
||||
ptArea : TRealArea;
|
||||
begin
|
||||
Area.BottomRight.lon:=0;
|
||||
Area.BottomRight.lat:=0;
|
||||
Area.TopLeft.lon:=0;
|
||||
Area.TopLeft.lat:=0;
|
||||
Lock;
|
||||
Try
|
||||
if Items.Count>0 then
|
||||
begin
|
||||
Area:=Items[0].BoundingBox;
|
||||
for i:=1 to pred(Items.Count) do
|
||||
begin
|
||||
ptArea:=Items[i].BoundingBox;
|
||||
ExtendArea(Area,ptArea);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TGPSObjectList.GetObjectsInArea(const Area: TRealArea): TGPSObjList;
|
||||
var i : integer;
|
||||
ItemArea : TRealArea;
|
||||
begin
|
||||
Result:=TGPSObjList.Create(false);
|
||||
Lock;
|
||||
Try
|
||||
Inc(FRefCount);
|
||||
For i:=0 to pred(Items.Count) do
|
||||
Begin
|
||||
ItemArea:=Items[i].BoundingBox;
|
||||
If hasIntersectArea(Area,ItemArea) then
|
||||
Result.Add(Items[i]);
|
||||
end;
|
||||
if Result.Count>0 then
|
||||
Result.FRef:=Self
|
||||
else
|
||||
Dec(FRefCount);
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TGPSObjectList.Create;
|
||||
begin
|
||||
Crit:=TCriticalSection.Create;
|
||||
FItems := TGPSObjList.Create(true);
|
||||
end;
|
||||
|
||||
destructor TGPSObjectList.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
FreeAndNil(FItems);
|
||||
FreeAndNil(FPending);
|
||||
FreeAndNil(Crit);
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.Clear(OwnedBy: integer);
|
||||
var i : integer;
|
||||
DelObj : TGPSObjList;
|
||||
begin
|
||||
DelObj:=nil;
|
||||
Lock;
|
||||
try
|
||||
For i:=pred(FItems.Count) downto 0 do
|
||||
if (OwnedBy=0) or (FItems[i].FIdOwner=OwnedBy) then
|
||||
_Delete(i,DelObj);
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
if Assigned(DelObj) then
|
||||
CallModified(DelObj,false);
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.ClearExcept(OwnedBy: integer;
|
||||
const ExceptLst : TIdArray; out Notfound: TIdArray);
|
||||
|
||||
var Found : TIdArray;
|
||||
|
||||
function ToDel(aIt : TGPsObj) : boolean;
|
||||
var i,Id : integer;
|
||||
Begin
|
||||
if (aIt.ExtraData=nil) or not(aIt.ExtraData.InheritsFrom(TDrawingExtraData)) then
|
||||
result:=true
|
||||
else
|
||||
Begin
|
||||
Result:=true;
|
||||
Id:=TDrawingExtraData(aIt.ExtraData).Id;
|
||||
for i:=low(ExceptLst) to high(ExceptLst) do
|
||||
if Id=ExceptLst[i] then
|
||||
begin
|
||||
result:=false;
|
||||
SetLength(Found,Length(Found)+1);
|
||||
Found[high(Found)]:=Id;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
var i,j : integer;
|
||||
IsFound : boolean;
|
||||
DelLst : TGPSObjList;
|
||||
begin
|
||||
DelLst:=nil;
|
||||
SetLength(NotFound,0);
|
||||
SetLength(Found,0);
|
||||
Lock;
|
||||
try
|
||||
For i:=pred(FItems.Count) downto 0 do
|
||||
begin
|
||||
if (FItems[i].FIdOwner=OwnedBy) or (OwnedBy=0) then
|
||||
Begin
|
||||
if ToDel(FItems[i]) then
|
||||
_Delete(i,DelLst);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
For i:=low(ExceptLst) to high(ExceptLst) do
|
||||
Begin
|
||||
IsFound:=false;
|
||||
for j:=low(Found) to high(Found) do
|
||||
if Found[j]=ExceptLst[i] then
|
||||
begin
|
||||
IsFound:=true;
|
||||
break;
|
||||
end;
|
||||
if not(IsFound) then
|
||||
Begin
|
||||
SetLength(NotFound,length(NotFound)+1);
|
||||
NotFound[high(NotFound)]:=ExceptLst[i];
|
||||
end;
|
||||
end;
|
||||
if Assigned(DelLst) then
|
||||
CallModified(DelLst,false);
|
||||
end;
|
||||
|
||||
function TGPSObjectList.GetIdsArea(const Ids: TIdArray;IdOwner : integer): TRealArea;
|
||||
var Objs : TGPSObjarray;
|
||||
i : integer;
|
||||
begin
|
||||
Result.BottomRight.Lat:=0;
|
||||
Result.BottomRight.Lon:=0;
|
||||
Result.TopLeft.Lat:=0;
|
||||
Result.TopLeft.Lon:=0;
|
||||
Lock;
|
||||
Try
|
||||
IdsToObj(Ids,Objs,IdOwner);
|
||||
if length(Objs)>0 then
|
||||
Begin
|
||||
Result:=Objs[0].BoundingBox;
|
||||
for i:=succ(low(Objs)) to high(Objs) do
|
||||
begin
|
||||
ExtendArea(Result,Objs[i].BoundingBox);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TGPSObjectList.Add(aItem: TGpsObj;IdOwner : integer): integer;
|
||||
var mList : TGPSObjList;
|
||||
begin
|
||||
aItem.FIdOwner:=IdOwner;
|
||||
Lock;
|
||||
try
|
||||
Result:=Items.Add(aItem);
|
||||
mList:=TGPSObjList.Create(false);
|
||||
mList.Add(aItem);
|
||||
inc(FRefCount);
|
||||
mList.FRef:=Self;
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
CallModified(mList,true);
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.DeleteById(const Ids: array of integer);
|
||||
function ToDelete(const AId : integer) : Boolean;
|
||||
var i : integer;
|
||||
begin
|
||||
result:=false;
|
||||
For i:=low(Ids) to high(Ids) do
|
||||
if Ids[i]=AId then
|
||||
Begin
|
||||
result:=true;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
var Extr : TDrawingExtraData;
|
||||
i : integer;
|
||||
DelLst : TGPSObjList;
|
||||
begin
|
||||
DelLst:=nil;
|
||||
Lock;
|
||||
try
|
||||
For i:=Pred(Items.Count) downto 0 do
|
||||
Begin
|
||||
if Assigned(Items[i].ExtraData) then
|
||||
Begin
|
||||
if Items[i].ExtraData.InheritsFrom(TDrawingExtraData) then
|
||||
Begin
|
||||
Extr := TDrawingExtraData(Items[i]);
|
||||
if ToDelete(Extr.Id) then
|
||||
_Delete(i,DelLst);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Unlock;
|
||||
end;
|
||||
if Assigned(DelLst) then
|
||||
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.BeginUpdate;
|
||||
begin
|
||||
inc(FUpdating);
|
||||
end;
|
||||
|
||||
procedure TGPSObjectList.EndUpdate;
|
||||
begin
|
||||
if FUpdating>0 then
|
||||
begin
|
||||
Dec(FUpdating);
|
||||
if FUpdating=0 then
|
||||
CallModified(nil,true);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TGPSTrack }
|
||||
|
||||
function TGPSTrack.GetDateTime: TDateTime;
|
||||
begin
|
||||
if FDateTime=0 then
|
||||
Begin
|
||||
if FPoints.Count>0 then
|
||||
FDateTime:=FPoints[0].DateTime;
|
||||
end;
|
||||
Result:=FDateTime;
|
||||
end;
|
||||
|
||||
constructor TGPSTrack.Create;
|
||||
begin
|
||||
FPoints := TGPSPointList.Create(true);
|
||||
end;
|
||||
|
||||
destructor TGPSTrack.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
FreeAndNil(FPoints);
|
||||
end;
|
||||
|
||||
procedure TGPSTrack.GetArea(out Area: TRealArea);
|
||||
var i : integer;
|
||||
ptArea : TRealArea;
|
||||
begin
|
||||
Area.BottomRight.lon:=0;
|
||||
Area.BottomRight.lat:=0;
|
||||
Area.TopLeft.lon:=0;
|
||||
Area.TopLeft.lat:=0;
|
||||
if FPoints.Count>0 then
|
||||
begin
|
||||
Area:=FPoints[0].BoundingBox;
|
||||
for i:=1 to pred(FPoints.Count) do
|
||||
begin
|
||||
ptArea:=FPoints[i].BoundingBox;
|
||||
ExtendArea(Area,ptArea);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TGPSTrack.TrackLengthInKm(UseEle: Boolean): double;
|
||||
var i : integer;
|
||||
begin
|
||||
Result:=0;
|
||||
For i:=1 to pred(FPoints.Count) do
|
||||
begin
|
||||
result+=FPoints[i].DistanceInKmFrom(FPoints[pred(i)],UseEle);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TGPSPoint }
|
||||
|
||||
function TGPSPoint.GetLat: Double;
|
||||
begin
|
||||
result:=FRealPt.Lat;
|
||||
end;
|
||||
|
||||
function TGPSPoint.GetLon: Double;
|
||||
begin
|
||||
result:=FRealPt.Lon;
|
||||
end;
|
||||
|
||||
procedure TGPSPoint.GetArea(out Area: TRealArea);
|
||||
begin
|
||||
Area.TopLeft:=FRealPt;
|
||||
Area.BottomRight:=FRealPt;
|
||||
end;
|
||||
|
||||
function TGPSPoint.HasEle: boolean;
|
||||
begin
|
||||
Result:=FEle<>NO_ELE;
|
||||
end;
|
||||
|
||||
function TGPSPoint.HasDateTime: Boolean;
|
||||
begin
|
||||
Result:=FDateTime<>NO_DATE;
|
||||
end;
|
||||
|
||||
function TGPSPoint.DistanceInKmFrom(OtherPt: TGPSPoint;UseEle : boolean): double;
|
||||
var a : double;
|
||||
lat1,lat2,lon1,lon2,t1,t2,t3,t4,t5,rad_dist : double;
|
||||
DiffEle :Double;
|
||||
begin
|
||||
a := PI / 180;
|
||||
lat1 := lat * a;
|
||||
lat2 := OtherPt.lat * a;
|
||||
lon1 := lon * a;
|
||||
lon2 := OtherPt.lon * a;
|
||||
|
||||
t1 := sin(lat1) * sin(lat2);
|
||||
t2 := cos(lat1) * cos(lat2);
|
||||
t3 := cos(lon1 - lon2);
|
||||
t4 := t2 * t3;
|
||||
t5 := t1 + t4;
|
||||
rad_dist := arctan(-t5/sqrt(-t5 * t5 +1)) + 2 * arctan(1);
|
||||
result := (rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446;
|
||||
if UseEle and (FEle<>OtherPt.FEle) then
|
||||
if (HasEle) and (OtherPt.HasEle) then
|
||||
Begin
|
||||
//FEle is assumed in Metter
|
||||
DiffEle:=(FEle-OtherPt.Ele)/1000;
|
||||
Result:=sqrt(DiffEle*DiffEle+result*result);
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TGPSPoint.Create(ALon, ALat: double; AEle: double;
|
||||
ADateTime: TDateTime);
|
||||
begin
|
||||
FRealPt.Lon:=ALon;
|
||||
FRealPt.Lat:=ALat;
|
||||
FEle:=AEle;
|
||||
FDateTime:=ADateTime;
|
||||
end;
|
||||
|
||||
class function TGPSPoint.CreateFrom(aPt: TRealPoint): TGPSPoint;
|
||||
begin
|
||||
Result:=Create(aPt.Lon,aPt.Lat);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
803
components/lazmapviewer/source/mvjobqueue.pas
Normal file
803
components/lazmapviewer/source/mvjobqueue.pas
Normal file
@ -0,0 +1,803 @@
|
||||
{
|
||||
Multi thread Queue,witch can be used without multi-thread (c) 2014 ti_dic
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvJobQueue;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,syncobjs,contnrs,forms;
|
||||
|
||||
const ALL_TASK_COMPLETED = -1;
|
||||
NO_MORE_TASK = 0;
|
||||
|
||||
type
|
||||
TjobQueue = class;
|
||||
|
||||
{ TJob }
|
||||
|
||||
TJob = Class
|
||||
private
|
||||
FLauncher : TObject;
|
||||
FCancelled : Boolean;
|
||||
FName: String;
|
||||
protected
|
||||
Queue : TJobQueue;
|
||||
|
||||
procedure DoCancel;virtual;
|
||||
Procedure WaitForResultOf(aJob : TJob);
|
||||
Procedure EnterCriticalSection;
|
||||
procedure LeaveCriticalSection;
|
||||
|
||||
//should be called inside critical section
|
||||
function pGetTask : integer;virtual;
|
||||
procedure pTaskStarted(aTask: integer);virtual;abstract;
|
||||
procedure pTaskEnded(aTask : integer;aExcept : Exception);virtual;abstract;
|
||||
property Launcher : TObject read FLauncher;
|
||||
public
|
||||
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);virtual;abstract;
|
||||
function Running : boolean;virtual;abstract;
|
||||
procedure Cancel;
|
||||
property Cancelled : boolean read FCancelled;
|
||||
property Name : String read FName write FName;
|
||||
end;
|
||||
|
||||
TJobArray = Array of TJob;
|
||||
|
||||
{ TjobQueue }
|
||||
|
||||
TjobQueue = Class
|
||||
private
|
||||
FMainThreadId : TThreadID;
|
||||
FOnIdle: TNotifyEvent;
|
||||
waitings : TStringList;
|
||||
FNbThread : integer;
|
||||
TerminatedThread : integer;
|
||||
FSect : TCriticalSection;
|
||||
FEvent,TerminateEvent : TEvent;
|
||||
FUseThreads: boolean;
|
||||
Threads : TList;
|
||||
Jobs : TObjectList;
|
||||
procedure pJobCompleted(var aJob: TJob);
|
||||
procedure SetUseThreads(AValue: boolean);
|
||||
procedure ClearWaitings;
|
||||
protected
|
||||
Procedure InitThreads;
|
||||
Procedure FreeThreads;
|
||||
Procedure EnterCriticalSection;
|
||||
procedure LeaveCriticalSection;
|
||||
Procedure DoWaiting(E : Exception;TaskId : integer);
|
||||
|
||||
//Should be called inside critical section
|
||||
procedure pAddWaiting(aJob : TJob;aTask : integer;JobId : String);
|
||||
procedure pTaskStarted(aJob : TJob;aTask : integer);
|
||||
procedure pTaskEnded(var aJob : TJob;aTask : integer;aExcept : Exception);
|
||||
function pGetJob(out TaskId : integer;out Restart : boolean) : TJob;
|
||||
function pFindJobByName(const aName : string;ByLauncher: TObject) : TJobArray;
|
||||
procedure pNotifyWaitings(aJob : TJob);
|
||||
Function IsMainThread : boolean;
|
||||
public
|
||||
constructor Create(NbThread : integer = 5);
|
||||
destructor Destroy;override;
|
||||
procedure QueueAsyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
||||
procedure QueueSyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
||||
property UseThreads : boolean read FUseThreads write SetUseThreads;
|
||||
Procedure AddJob(aJob : TJob;Launcher : TObject);
|
||||
function AddUniqueJob(aJob : TJob;Launcher : TObject) : boolean;
|
||||
function CancelAllJob(ByLauncher: TObject) : TJobArray;
|
||||
function CancelJobByName(aJobName : String;ByLauncher: TObject) : boolean;
|
||||
Procedure WaitForTerminate(const lstJob : TJobArray);
|
||||
Procedure WaitAllJobTerminated(ByLauncher: TObject);
|
||||
property OnIdle : TNotifyEvent read FOnIdle write FOnIdle;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
const
|
||||
WAIT_TIME = 3000;
|
||||
TERMINATE_TIMEOUT = 1000;
|
||||
|
||||
|
||||
Type
|
||||
|
||||
{ EWaiting }
|
||||
|
||||
EWaiting = Class(Exception)
|
||||
private
|
||||
FLauncher : TJob;
|
||||
FNewJob : TJob;
|
||||
public
|
||||
constructor Create(launcher : TJob;NewJob : TJob);
|
||||
end;
|
||||
|
||||
{ TRestartTask }
|
||||
|
||||
TRestartTask = Class(TJob)
|
||||
private
|
||||
FStarted : Boolean;
|
||||
FJob : TJob;
|
||||
FTask : integer;
|
||||
protected
|
||||
procedure DoCancel;override;
|
||||
procedure pTaskStarted(aTask: integer);override;
|
||||
procedure pTaskEnded(aTask : integer;aExcept : Exception);override;
|
||||
function pGetTask : integer;override;
|
||||
public
|
||||
constructor Create(aJob : TJob;aTask : integer);
|
||||
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);override;
|
||||
function Running : boolean;override;
|
||||
end;
|
||||
|
||||
{ TQueueThread }
|
||||
|
||||
TQueueThread = Class(TThread)
|
||||
private
|
||||
MyQueue : TJobqueue;
|
||||
function ProcessJob : boolean;
|
||||
public
|
||||
constructor Create(aQueue: TJobQueue);
|
||||
procedure Execute; override;
|
||||
end;
|
||||
|
||||
{ TRestartTask }
|
||||
|
||||
procedure TRestartTask.DoCancel;
|
||||
begin
|
||||
FJob.Cancel;
|
||||
end;
|
||||
|
||||
procedure TRestartTask.pTaskStarted(aTask: integer);
|
||||
begin
|
||||
FStarted := true;
|
||||
end;
|
||||
|
||||
procedure TRestartTask.pTaskEnded(aTask: integer; aExcept: Exception);
|
||||
begin
|
||||
Queue.pTaskEnded(FJob,FTask,aExcept);
|
||||
end;
|
||||
|
||||
function TRestartTask.pGetTask: integer;
|
||||
begin
|
||||
if FStarted then
|
||||
Result:=inherited pGetTask
|
||||
else
|
||||
Result:=1;
|
||||
end;
|
||||
|
||||
constructor TRestartTask.Create(aJob: TJob; aTask: integer);
|
||||
begin
|
||||
FJob:=aJob;
|
||||
FTask:=aTask;
|
||||
end;
|
||||
|
||||
procedure TRestartTask.ExecuteTask(aTask: integer; FromWaiting: boolean);
|
||||
begin
|
||||
FJob.ExecuteTask(FTask,true);
|
||||
end;
|
||||
|
||||
function TRestartTask.Running: boolean;
|
||||
begin
|
||||
Result:=Fstarted;
|
||||
end;
|
||||
|
||||
{ EWaiting }
|
||||
|
||||
constructor EWaiting.Create(launcher: TJob; NewJob: TJob);
|
||||
begin
|
||||
FLauncher:=launcher;
|
||||
FNewJob:=NewJob;
|
||||
end;
|
||||
|
||||
{ TQueueThread }
|
||||
|
||||
function TQueueThread.ProcessJob : boolean;
|
||||
var aJob : TJob;
|
||||
TaskId : Integer;
|
||||
|
||||
Procedure SetRes(e : Exception);
|
||||
Begin
|
||||
MyQueue.EnterCriticalSection;
|
||||
Try
|
||||
MyQueue.pTaskEnded(aJob,TaskId,nil);
|
||||
finally
|
||||
MyQueue.LeaveCriticalSection;
|
||||
end;
|
||||
end;
|
||||
var RestartTask : boolean;
|
||||
SomeJob : Boolean;
|
||||
begin
|
||||
Result:=false;
|
||||
Repeat
|
||||
SomeJob:=false;
|
||||
MyQueue.EnterCriticalSection;
|
||||
Try
|
||||
result:=result or (MyQueue.Jobs.Count>0);
|
||||
aJob:=MyQueue.pGetJob(TaskId,RestartTask);
|
||||
if Assigned(aJob) then
|
||||
Begin
|
||||
if TaskId=ALL_TASK_COMPLETED then
|
||||
begin
|
||||
MyQueue.pJobCompleted(aJob);
|
||||
SomeJob := true;
|
||||
end
|
||||
else
|
||||
Begin
|
||||
MyQueue.FEvent.ResetEvent;
|
||||
if not(RestartTask) then
|
||||
MyQueue.pTaskStarted(aJob,TaskId);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
MyQueue.LeaveCriticalSection;
|
||||
end;
|
||||
if Assigned(aJob) then
|
||||
Begin
|
||||
SomeJob:=true;
|
||||
Try
|
||||
aJob.ExecuteTask(TaskId,RestartTask);
|
||||
SetRes(nil);
|
||||
Except
|
||||
on e : Exception do
|
||||
if e.InheritsFrom(EWaiting) then
|
||||
MyQueue.DoWaiting(e,TaskId)
|
||||
else
|
||||
SetRes(e);
|
||||
end;
|
||||
end;
|
||||
until SomeJob=false;
|
||||
end;
|
||||
|
||||
constructor TQueueThread.Create(aQueue: TJobQueue);
|
||||
begin
|
||||
MyQueue := aQueue;
|
||||
inherited Create(False);
|
||||
end;
|
||||
|
||||
procedure TQueueThread.Execute;
|
||||
var wRes : TWaitResult;
|
||||
begin
|
||||
while not Terminated do
|
||||
begin
|
||||
wRes:=MyQueue.FEvent.WaitFor(WAIT_TIME);
|
||||
if not(Terminated) then
|
||||
Begin
|
||||
if not(ProcessJob) then
|
||||
if wRes=wrTimeout then
|
||||
if Assigned(MyQueue.OnIdle) then
|
||||
MyQueue.OnIdle(self);
|
||||
end;
|
||||
end;
|
||||
MyQueue.EnterCriticalSection;
|
||||
Try
|
||||
inc(MyQueue.TerminatedThread);
|
||||
if Assigned(MyQueue.TerminateEvent) then
|
||||
if MyQueue.TerminatedThread=MyQueue.Threads.count then
|
||||
MyQueue.TerminateEvent.SetEvent;
|
||||
finally
|
||||
MyQueue.LeaveCriticalSection;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TjobQueue }
|
||||
|
||||
procedure TjobQueue.SetUseThreads(AValue: boolean);
|
||||
begin
|
||||
if FUseThreads=AValue then
|
||||
Exit;
|
||||
FUseThreads:=AValue;
|
||||
if Fusethreads then
|
||||
InitThreads
|
||||
else
|
||||
FreeThreads;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.ClearWaitings;
|
||||
var i : integer;
|
||||
begin
|
||||
For i:=0 to pred(Waitings.count) do
|
||||
Waitings.Objects[i].Free;
|
||||
Waitings.Clear;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.InitThreads;
|
||||
var i : integer;
|
||||
begin
|
||||
Jobs:=TObjectList.Create(true);
|
||||
Threads:=TObjectList.Create(true);
|
||||
FEvent:=TEvent.Create(nil,true,false,'');
|
||||
FSect:=TCriticalSection.Create;
|
||||
TerminatedThread := 0;
|
||||
For i:=1 to FNbThread do
|
||||
Threads.Add(TQueueThread.Create(self));
|
||||
end;
|
||||
|
||||
procedure TjobQueue.FreeThreads;
|
||||
var i : integer;
|
||||
begin
|
||||
if Assigned(Threads) then
|
||||
Begin
|
||||
TerminateEvent := TEvent.Create(nil,false,false,'');
|
||||
Try
|
||||
FEvent.SetEvent;
|
||||
TerminatedThread:=0;
|
||||
For i:=0 to pred(Threads.Count) do
|
||||
TQueueThread(Threads[i]).Terminate;
|
||||
TerminateEvent.WaitFor(TERMINATE_TIMEOUT);
|
||||
FreeAndNil(FSect);
|
||||
FreeAndNil(FEvent);
|
||||
FreeAndNil(Threads);
|
||||
finally
|
||||
FreeAndNil(TerminateEvent);
|
||||
end;
|
||||
FreeAndNil(Jobs);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.EnterCriticalSection;
|
||||
begin
|
||||
if Assigned(FSect) and UseThreads then
|
||||
FSect.Enter;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.LeaveCriticalSection;
|
||||
begin
|
||||
if Assigned(FSect) and UseThreads then
|
||||
FSect.Leave;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.DoWaiting(E : Exception;TaskId : integer);
|
||||
var we : EWaiting;
|
||||
begin
|
||||
EnterCriticalSection;
|
||||
try
|
||||
we:=EWaiting(e);
|
||||
pAddWaiting(we.FLauncher,TaskId,we.FNewJob.Name);
|
||||
AddUniqueJob(we.FNewJob,we.FLauncher.FLauncher);
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.pAddWaiting(aJob: TJob; aTask: integer; JobId: String);
|
||||
begin
|
||||
Waitings.AddObject(JobId,TRestartTask.Create(aJob,aTask));
|
||||
end;
|
||||
|
||||
procedure TjobQueue.pTaskStarted(aJob: TJob; aTask: integer);
|
||||
begin
|
||||
aJob.pTaskStarted(aTask);
|
||||
end;
|
||||
|
||||
procedure TjobQueue.pJobCompleted(var aJob: TJob);
|
||||
Begin
|
||||
pNotifyWaitings(aJob);
|
||||
if FuseThreads then
|
||||
Begin
|
||||
Jobs.Remove(aJob);
|
||||
aJob:=nil;
|
||||
end
|
||||
else
|
||||
FreeAndNil(aJob);
|
||||
end;
|
||||
|
||||
procedure TjobQueue.pTaskEnded(var aJob: TJob; aTask: integer; aExcept: Exception);
|
||||
begin
|
||||
aJob.pTaskEnded(aTask,aExcept);
|
||||
if (aJob.pGetTask=ALL_TASK_COMPLETED) then
|
||||
Begin
|
||||
pJobcompleted(aJob);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TjobQueue.pGetJob(out TaskId : integer;out Restart : boolean): TJob;
|
||||
var iJob : integer;
|
||||
aJob : TJob;
|
||||
begin
|
||||
Restart:=false;
|
||||
Result:=nil;
|
||||
For iJob:=0 to pred(Jobs.Count) do
|
||||
Begin
|
||||
aJob:=TJob(Jobs[iJob]);
|
||||
if aJob.InheritsFrom(TRestartTask) then
|
||||
Begin
|
||||
result:=TRestartTask(aJob).FJob;
|
||||
TaskId:=TRestartTask(aJob).FTask;
|
||||
Restart:=true;
|
||||
Jobs.Delete(iJob);
|
||||
Exit;
|
||||
end;
|
||||
TaskId:=aJob.pGetTask;
|
||||
if (TaskId>NO_MORE_TASK) or (TaskId=ALL_TASK_COMPLETED) then
|
||||
Begin
|
||||
Result:=aJob;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
if not(assigned(result)) then
|
||||
TaskId:=NO_MORE_TASK;
|
||||
end;
|
||||
|
||||
function TjobQueue.pFindJobByName(const aName: string;ByLauncher: TObject): TJobArray;
|
||||
var iRes,i : integer;
|
||||
begin
|
||||
SetLength(result,Jobs.count);
|
||||
iRes:=0;
|
||||
For i:=0 to pred(Jobs.Count) do
|
||||
Begin
|
||||
if TJob(Jobs[i]).Name=aName then
|
||||
begin
|
||||
if (ByLauncher=nil) or (TJob(Jobs[i]).FLauncher=ByLauncher) then
|
||||
Begin
|
||||
Result[iRes]:=TJob(Jobs[i]);
|
||||
inc(iRes);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
SetLength(result,iRes);
|
||||
end;
|
||||
|
||||
procedure TjobQueue.pNotifyWaitings(aJob: TJob);
|
||||
var JobId : String;
|
||||
ObjRestart : TRestartTask;
|
||||
idx : integer;
|
||||
begin
|
||||
JobId:=aJob.Name;
|
||||
Repeat
|
||||
idx:=waitings.IndexOf(JobId);
|
||||
if idx<>-1 then
|
||||
Begin
|
||||
ObjRestart:=TRestartTask(waitings.Objects[idx]);
|
||||
waitings.Delete(idx);
|
||||
Jobs.Add(ObjRestart);
|
||||
end;
|
||||
until idx=-1;
|
||||
end;
|
||||
|
||||
function TjobQueue.IsMainThread: boolean;
|
||||
begin
|
||||
Result:=GetCurrentThreadId=FMainThreadID;
|
||||
end;
|
||||
|
||||
constructor TjobQueue.Create(NbThread: integer);
|
||||
begin
|
||||
waitings:=TStringList.create;
|
||||
FNbThread:=NbThread;
|
||||
FMainThreadId:=GetCurrentThreadId;
|
||||
end;
|
||||
|
||||
destructor TjobQueue.Destroy;
|
||||
begin
|
||||
FreeThreads;
|
||||
ClearWaitings;
|
||||
FreeAndNil(Waitings);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.QueueAsyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
||||
begin
|
||||
if UseThreads then
|
||||
Application.QueueAsyncCall(aMethod,Data)
|
||||
else
|
||||
AMethod(Data);
|
||||
end;
|
||||
|
||||
|
||||
Type
|
||||
|
||||
{ TSyncCallData }
|
||||
|
||||
TSyncCallData = Class
|
||||
private
|
||||
FMethod : TDataEvent;
|
||||
FData : PtrInt;
|
||||
public
|
||||
Constructor Create(AMethod : TDataEvent;AData : PtrInt);
|
||||
Procedure SyncCall;
|
||||
End;
|
||||
|
||||
{ TSyncCallData }
|
||||
|
||||
constructor TSyncCallData.Create(AMethod: TDataEvent; AData: PtrInt);
|
||||
begin
|
||||
FMethod:=AMethod;
|
||||
FData:=AData;
|
||||
|
||||
end;
|
||||
|
||||
procedure TSyncCallData.SyncCall;
|
||||
begin
|
||||
FMethod(FData);
|
||||
end;
|
||||
|
||||
procedure TjobQueue.QueueSyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
||||
var tmp : TSyncCallData;
|
||||
begin
|
||||
tmp := TSyncCallData.Create(AMethod,Data);
|
||||
Try
|
||||
TThread.Synchronize(nil,@tmp.SyncCall);
|
||||
finally
|
||||
tmp.free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.AddJob(aJob: TJob;Launcher : TObject);
|
||||
var TaskId : Integer;
|
||||
restart : boolean;
|
||||
begin
|
||||
aJob.FLauncher:=Launcher;
|
||||
aJob.Queue:=self;
|
||||
if Usethreads then
|
||||
Begin
|
||||
EnterCriticalSection;
|
||||
Try
|
||||
Jobs.add(aJob);
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
FEvent.SetEvent;
|
||||
end
|
||||
Else
|
||||
Begin
|
||||
Try
|
||||
Repeat
|
||||
TaskId:=aJob.pGetTask;
|
||||
restart:=false;
|
||||
if TaskId>NO_MORE_TASK then
|
||||
Begin
|
||||
pTaskStarted(aJob,TaskId);
|
||||
Try
|
||||
aJob.ExecuteTask(TaskId,restart);
|
||||
pTaskEnded(aJob,TaskId,nil);
|
||||
except
|
||||
on e : Exception do
|
||||
Begin
|
||||
if not(e.InheritsFrom(EWaiting)) then
|
||||
pTaskEnded(aJob,TaskId,e)
|
||||
else
|
||||
DoWaiting(e,TaskId);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if not(Assigned(aJob)) then
|
||||
TaskId:=ALL_TASK_COMPLETED;
|
||||
until TaskId=ALL_TASK_COMPLETED;
|
||||
finally
|
||||
aJob.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TjobQueue.AddUniqueJob(aJob: TJob; Launcher: TObject): boolean;
|
||||
var lst : TJobArray;
|
||||
begin
|
||||
Result:=true;
|
||||
if FUseThreads then
|
||||
Begin
|
||||
aJob.Queue:=self;
|
||||
aJob.FLauncher:=Launcher;
|
||||
EnterCriticalSection;
|
||||
Try
|
||||
lst:=pFindJobByName(aJob.Name,Launcher);
|
||||
if length(lst)=0 then
|
||||
Jobs.add(aJob)
|
||||
else
|
||||
Result:=false;
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
FEvent.SetEvent;;
|
||||
end
|
||||
Else
|
||||
AddJob(aJob,Launcher);
|
||||
end;
|
||||
|
||||
function TjobQueue.CancelAllJob(ByLauncher: TObject) : TJobArray;
|
||||
var i,iJob : integer;
|
||||
begin
|
||||
SetLength(Result,0);
|
||||
if FUseThreads then
|
||||
Begin
|
||||
EnterCriticalSection;
|
||||
Try
|
||||
SetLEngth(Result,Jobs.Count);
|
||||
iJob:=0;
|
||||
For i:=pred(Jobs.Count) downto 0 do
|
||||
Begin
|
||||
if (ByLauncher=nil) or (TJob(Jobs[i]).FLauncher=ByLauncher) then
|
||||
Begin
|
||||
TJob(Jobs[i]).Cancel;
|
||||
Result[iJob]:=TJob(Jobs[i]);
|
||||
iJob+=1;
|
||||
End;
|
||||
End;
|
||||
SetLength(Result,iJob);
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TjobQueue.CancelJobByName(aJobName: String;ByLauncher: TObject) : boolean;
|
||||
var lst : TJobArray;
|
||||
i : integer;
|
||||
begin
|
||||
Result:=false;
|
||||
if FUseThreads then
|
||||
Begin
|
||||
EnterCriticalSection;
|
||||
Try
|
||||
lst:=pFindJobByName(aJobName,ByLauncher);
|
||||
For i:=low(lst) to high(lst) do
|
||||
Begin
|
||||
result:=true;
|
||||
lst[i].Cancel;
|
||||
End;
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.WaitForTerminate(const lstJob: TJobArray);
|
||||
var OneFound : Boolean;
|
||||
i : integer;
|
||||
mThread : Boolean;
|
||||
TimeOut : integer;
|
||||
begin
|
||||
TimeOut:=0;
|
||||
mThread:=IsMainThread;
|
||||
if FUseThreads then
|
||||
Begin
|
||||
repeat
|
||||
OneFound:=False;
|
||||
EnterCriticalSection;
|
||||
Try
|
||||
For i:=low(lstJob) to high(lstJob) do
|
||||
Begin
|
||||
if Jobs.IndexOf(lstJob[i])<>-1 then
|
||||
Begin
|
||||
OneFound:=True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
if OneFound and (TimeOut>200) then
|
||||
Raise Exception.Create('TimeOut');
|
||||
if mThread then
|
||||
Application.ProcessMessages;
|
||||
if OneFound then
|
||||
Sleep(100);
|
||||
Inc(TimeOut);
|
||||
until not(OneFound);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TjobQueue.WaitAllJobTerminated(ByLauncher: TObject);
|
||||
var OneFound : boolean;
|
||||
i : integer;
|
||||
TimeOut : integer;
|
||||
mThread : Boolean;
|
||||
|
||||
Procedure CheckTimeOut;
|
||||
Begin
|
||||
if TimeOut>200 then
|
||||
Raise Exception.Create('TimeOut');
|
||||
if mThread then
|
||||
Application.ProcessMessages;
|
||||
sleep(100);
|
||||
inc(TimeOut);
|
||||
end;
|
||||
|
||||
begin
|
||||
TimeOut:=0;
|
||||
if FUseThreads then
|
||||
Begin
|
||||
mThread:=IsMainThread;
|
||||
if ByLauncher=nil then
|
||||
Begin
|
||||
While Jobs.Count>0 do
|
||||
CheckTimeOut;
|
||||
end
|
||||
else
|
||||
Begin
|
||||
repeat
|
||||
OneFound:=False;
|
||||
EnterCriticalSection;
|
||||
Try
|
||||
For i:=0 to pred(Jobs.Count) do
|
||||
Begin
|
||||
if TJob(Jobs[i]).FLauncher=ByLauncher then
|
||||
Begin
|
||||
OneFound:=True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
LeaveCriticalSection;
|
||||
end;
|
||||
if OneFound then
|
||||
CheckTimeOut;
|
||||
until not(OneFound);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TjobQueue }
|
||||
|
||||
procedure TJob.Cancel;
|
||||
var lst : Array of TRestartTask;
|
||||
i,idx : integer;
|
||||
begin
|
||||
Queue.EnterCriticalSection;
|
||||
Try
|
||||
FCancelled := true;
|
||||
if (Name<>'') and (Queue.waitings.count>0) then
|
||||
Begin
|
||||
SetLength(lst,0);
|
||||
Repeat
|
||||
idx:=Queue.waitings.IndexOf(Name);
|
||||
if idx<>-1 then
|
||||
Begin
|
||||
SetLength(lst,length(lst)+1);
|
||||
lst[high(lst)]:=TRestartTask(Queue.waitings.Objects[idx]);
|
||||
Queue.waitings.Delete(idx);
|
||||
end;
|
||||
until idx=-1;
|
||||
For i:=low(lst) to high(lst) do
|
||||
Begin
|
||||
lst[i].Cancel;
|
||||
lst[i].pTaskEnded(1,nil);
|
||||
lst[i].Free;
|
||||
end;
|
||||
end;
|
||||
DoCancel;
|
||||
finally
|
||||
Queue.LeaveCriticalSection;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJob.DoCancel;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
function TJob.pGetTask: integer;
|
||||
begin
|
||||
result:=ALL_TASK_COMPLETED;
|
||||
end;
|
||||
|
||||
procedure TJob.WaitForResultOf(aJob: TJob);
|
||||
begin
|
||||
Raise EWaiting.Create(self,aJob);
|
||||
end;
|
||||
|
||||
procedure TJob.EnterCriticalSection;
|
||||
begin
|
||||
Queue.EnterCriticalSection;
|
||||
end;
|
||||
|
||||
procedure TJob.LeaveCriticalSection;
|
||||
begin
|
||||
Queue.LeaveCriticalSection;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
130
components/lazmapviewer/source/mvjobs.pas
Normal file
130
components/lazmapviewer/source/mvjobs.pas
Normal file
@ -0,0 +1,130 @@
|
||||
{
|
||||
basics jobs for multi-threading(c) 2014 ti_dic
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvJobs;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,mvJobQueue;
|
||||
|
||||
|
||||
type
|
||||
{ TSimpleJob }
|
||||
//job with only one task
|
||||
TSimpleJob = class(TJob)
|
||||
private
|
||||
FRunning,FEnded : boolean;
|
||||
protected
|
||||
function pGetTask : integer;override;
|
||||
procedure pTaskStarted(aTask: integer);override;
|
||||
procedure pTaskEnded(aTask : integer;aExcept : Exception);override;
|
||||
public
|
||||
function Running : boolean;override;
|
||||
end;
|
||||
|
||||
TJobProc = Procedure (Data : TObject;Job : TJob) of object;
|
||||
|
||||
{ TEventJob }
|
||||
//job with only one task (callback an event)
|
||||
TEventJob = Class(TSimpleJob)
|
||||
private
|
||||
FData : TObject;
|
||||
FTask : TJobProc;
|
||||
FOwnData : Boolean;
|
||||
public
|
||||
constructor Create(aEvent : TJobProc;Data : TObject;OwnData : Boolean;JobName : String='');virtual;
|
||||
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);override;
|
||||
destructor Destroy;override;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{ TEventJob }
|
||||
|
||||
constructor TEventJob.Create(aEvent: TJobProc; Data: TObject;
|
||||
OwnData: Boolean;JobName : String='');
|
||||
begin
|
||||
Name:=JobName;
|
||||
FTask:=aEvent;
|
||||
if Assigned(Data) or OwnData then
|
||||
Begin
|
||||
FData:=Data;
|
||||
FOwnData:=OwnData;
|
||||
end
|
||||
else
|
||||
Begin
|
||||
FOwnData:=false;
|
||||
FData:=self;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TEventJob.ExecuteTask(aTask : integer;FromWaiting : boolean);
|
||||
begin
|
||||
if Assigned(FTask) then
|
||||
FTask(FData,self);
|
||||
end;
|
||||
|
||||
destructor TEventJob.Destroy;
|
||||
begin
|
||||
if FOwnData then
|
||||
if FData<>self then
|
||||
FData.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TSimpleJob }
|
||||
|
||||
function TSimpleJob.pGetTask: integer;
|
||||
begin
|
||||
if FRunning or Cancelled then
|
||||
Begin
|
||||
if not FRunning then
|
||||
Result := ALL_TASK_COMPLETED
|
||||
else
|
||||
Result:=NO_MORE_TASK
|
||||
end
|
||||
else
|
||||
if FEnded then
|
||||
Result := ALL_TASK_COMPLETED
|
||||
else
|
||||
Result:=1;
|
||||
end;
|
||||
|
||||
procedure TSimpleJob.pTaskStarted(aTask: integer);
|
||||
begin
|
||||
FEnded:=false;
|
||||
FRunning:=True;
|
||||
end;
|
||||
|
||||
procedure TSimpleJob.pTaskEnded(aTask: integer; aExcept: Exception);
|
||||
begin
|
||||
FEnded:=True;
|
||||
FRunning:=False;
|
||||
end;
|
||||
|
||||
function TSimpleJob.Running: boolean;
|
||||
begin
|
||||
Result:=FRunning;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
172
components/lazmapviewer/source/mvmapprovider.pas
Normal file
172
components/lazmapviewer/source/mvmapprovider.pas
Normal file
@ -0,0 +1,172 @@
|
||||
{
|
||||
(c) 2014 ti_dic
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
unit mvMapProvider;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
Type
|
||||
{ TTileId }
|
||||
TTileId = record
|
||||
X,Y : int64;
|
||||
Z : integer;
|
||||
end;
|
||||
|
||||
|
||||
TGetSvrStr = Function (id : integer) : string of object;
|
||||
TGetValStr = Function (const Tile : TTileId) : String of object;
|
||||
|
||||
{ TMapProvider }
|
||||
|
||||
TMapProvider = Class
|
||||
private
|
||||
FLayer : integer;
|
||||
idServer : Array of Integer;
|
||||
FName : String;
|
||||
FUrl : Array of string;
|
||||
FNbSvr : Array of integer;
|
||||
FGetSvrStr : Array of TGetSvrStr;
|
||||
FGetXStr : Array of TGetValStr;
|
||||
FGetYStr : Array of TGetValStr;
|
||||
FGetZStr : Array of TGetValStr;
|
||||
FMinZoom : Array of integer;
|
||||
FMaxZoom : Array of integer;
|
||||
function getLayerCount: integer;
|
||||
procedure SetLayer(AValue: integer);
|
||||
|
||||
public
|
||||
constructor Create(aName : String);
|
||||
destructor Destroy; override;
|
||||
procedure AddURL(Url: String; NbSvr: integer;aMinZoom : integer;aMaxZoom : integer; GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr; GetZStr: TGetValStr);
|
||||
procedure GetZoomInfos(out zMin:integer;out zMax : integer);
|
||||
Function GetUrlForTile(id : TTileId) : String;
|
||||
property Name : String read FName;
|
||||
property LayerCount : integer read getLayerCount;
|
||||
property Layer : integer read FLayer write SetLayer;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{ TMapProvider }
|
||||
|
||||
function TMapProvider.getLayerCount: integer;
|
||||
begin
|
||||
Result:=length(FUrl);
|
||||
end;
|
||||
|
||||
procedure TMapProvider.SetLayer(AValue: integer);
|
||||
begin
|
||||
if FLayer=AValue then Exit;
|
||||
if (aValue<low(FUrl)) and (aValue>high(FUrl)) then
|
||||
Begin
|
||||
Raise Exception.create('bad Layer');
|
||||
end;
|
||||
FLayer:=AValue;
|
||||
end;
|
||||
|
||||
constructor TMapProvider.Create(aName: String);
|
||||
begin
|
||||
FName:=aName;
|
||||
end;
|
||||
|
||||
destructor TMapProvider.Destroy;
|
||||
begin
|
||||
Finalize(idServer);
|
||||
Finalize(FName);
|
||||
Finalize(FUrl);
|
||||
Finalize(FNbSvr);
|
||||
Finalize(FGetSvrStr);
|
||||
Finalize(FGetXStr);
|
||||
Finalize(FGetYStr);
|
||||
Finalize(FGetZStr);
|
||||
Finalize(FMinZoom);
|
||||
Finalize(FMaxZoom);
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TMapProvider.AddURL(Url: String; NbSvr: integer;
|
||||
aMinZoom : integer;aMaxZoom : integer;
|
||||
GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr;
|
||||
GetZStr: TGetValStr);
|
||||
var nb : integer;
|
||||
begin
|
||||
nb:=length(FUrl)+1;
|
||||
SetLength(IdServer,nb);
|
||||
SetLength(FUrl,nb);
|
||||
SetLength(FNbSvr,nb);
|
||||
SetLength(FGetSvrStr,nb);
|
||||
SetLength(FGetXStr,nb);
|
||||
SetLength(FGetYStr,nb);
|
||||
SetLength(FGetZStr,nb);
|
||||
SetLength(FMinZoom,nb);
|
||||
SetLength(FMaxZoom,nb);
|
||||
nb:=high(FUrl);
|
||||
FUrl[nb]:=Url;
|
||||
FNbSvr[nb]:=NbSvr;
|
||||
FMinZoom[nb]:=aMinZoom;
|
||||
FMaxZoom[nb]:=aMaxZoom;
|
||||
FGetSvrStr[nb]:=GetSvrStr;
|
||||
FGetXStr[nb]:=GetXStr;
|
||||
FGetYStr[nb]:=GetYStr;
|
||||
FGetZStr[nb]:=GetZStr;
|
||||
FLayer:=low(FUrl);
|
||||
end;
|
||||
|
||||
procedure TMapProvider.GetZoomInfos(out zMin: integer; out zMax: integer);
|
||||
begin
|
||||
zMin:=FMinZoom[layer];
|
||||
zMax:=FMaxZoom[layer];
|
||||
end;
|
||||
|
||||
function TMapProvider.GetUrlForTile(id: TTileId): String;
|
||||
var i : integer;
|
||||
XVal,yVal,zVal,SvrVal : String;
|
||||
idsvr: integer;
|
||||
begin
|
||||
Result:='';
|
||||
i:=layer;
|
||||
if (i>high(idServer)) or (i<low(idServer)) or (FNbSvr[i]=0) then
|
||||
exit;
|
||||
|
||||
idsvr:=idServer[i] mod FNbSvr[i];
|
||||
idServer[i]+=1;
|
||||
|
||||
SvrVal:=inttostr(idsvr);
|
||||
XVal:=inttostr(id.X);
|
||||
YVal:=inttostr(id.Y);
|
||||
ZVal:=inttostr(id.Z);
|
||||
if Assigned(FGetSvrStr[i]) then
|
||||
SvrVal:=FGetSvrStr[i](idsvr);
|
||||
if Assigned(FGetXStr[i]) then
|
||||
XVal:=FGetXStr[i](id);
|
||||
if Assigned(FGetYStr[i]) then
|
||||
YVal:=FGetYStr[i](id);
|
||||
if Assigned(FGetZStr[i]) then
|
||||
ZVal:=FGetZStr[i](id);
|
||||
Result:=StringReplace(FUrl[i],'%serv%',SvrVal,[rfreplaceall]);
|
||||
Result:=StringReplace(Result,'%x%',XVal,[rfreplaceall]);
|
||||
Result:=StringReplace(Result,'%y%',YVal,[rfreplaceall]);
|
||||
Result:=StringReplace(Result,'%z%',ZVal,[rfreplaceall]);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
834
components/lazmapviewer/source/mvmapviewer.pas
Normal file
834
components/lazmapviewer/source/mvmapviewer.pas
Normal file
@ -0,0 +1,834 @@
|
||||
{ (c) 2014 ti_dic MapViewer component for lazarus
|
||||
Parts of this component are based on :
|
||||
Map Viewer Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
|
||||
unit mvmapviewer;
|
||||
|
||||
{$MODE objfpc}{$H+}
|
||||
|
||||
// Activate one of the following defines
|
||||
{$DEFINE USE_LAZINTFIMAGE}
|
||||
{.$DEFINE USE_RGBGRAPHICS} // NOTE: This needs package "rgb_graphics" in requirements
|
||||
|
||||
// Make sure that one of the USE_XXXX defines is active. Default is USE_LAZINTFIMAGE
|
||||
{$IFNDEF USE_RGBGRAPHICS}{$IFNDEF USE_LAZINTFIMAGE}{$DEFINE USE_LAZINTFIMAGES}{$ENDIF}{$ENDIF}
|
||||
{$IFDEF USE_RGBGRAPHICS}{$IFDEF USE_LAZINTFIMAGE}{$UNDEF USE_RGBGRAPHICS}{$ENDIF}{$ENDIF}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Controls, Graphics, IntfGraphics,
|
||||
{$IFDEF USE_RGBGRAPHICS}RGBGraphics,{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}FPCanvas,{$ENDIF}
|
||||
MvTypes, MvGPSObj, MvEngine, MvMapProvider, MVDLESynapse;
|
||||
|
||||
Type
|
||||
|
||||
{ TMapView }
|
||||
|
||||
TMapView = class(TCustomControl)
|
||||
private
|
||||
dl : TMVDESynapse;
|
||||
FEngine : TMapViewerEngine;
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer : TRGB32Bitmap;
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
Buffer: TLazIntfImage;
|
||||
BufferCanvas: TFPCustomCanvas;
|
||||
{$ENDIF}
|
||||
FActive: boolean;
|
||||
FGPSItems: TGPSObjectList;
|
||||
FInactiveColor: TColor;
|
||||
FPOIImage: TBitmap;
|
||||
procedure CallAsyncInvalidate;
|
||||
procedure DoAsyncInvalidate(Data: PtrInt);
|
||||
procedure DrawObjects(const TileId: TTileId; aLeft, aTop, aRight,aBottom: integer);
|
||||
procedure DrawPt(const Area: TRealArea;aPOI: TGPSPoint);
|
||||
procedure DrawTrk(const Area: TRealArea;trk: TGPSTrack);
|
||||
function GetCacheOnDisk: boolean;
|
||||
function GetCachePath: String;
|
||||
function GetCenter: TRealPoint;
|
||||
function GetMapProvider: String;
|
||||
function GetOnCenterMove: TNotifyEvent;
|
||||
function GetOnChange: TNotifyEvent;
|
||||
function GetOnZoomChange: TNotifyEvent;
|
||||
function GetUseThreads: boolean;
|
||||
function GetZoom: integer;
|
||||
procedure SetActive(AValue: boolean);
|
||||
procedure SetCacheOnDisk(AValue: boolean);
|
||||
procedure SetCachePath(AValue: String);
|
||||
procedure SetCenter(AValue: TRealPoint);
|
||||
procedure SetInactiveColor(AValue: TColor);
|
||||
procedure SetMapProvider(AValue: String);
|
||||
procedure SetOnCenterMove(AValue: TNotifyEvent);
|
||||
procedure SetOnChange(AValue: TNotifyEvent);
|
||||
procedure SetOnZoomChange(AValue: TNotifyEvent);
|
||||
procedure SetUseThreads(AValue: boolean);
|
||||
procedure SetZoom(AValue: integer);
|
||||
|
||||
protected
|
||||
AsyncInvalidate : boolean;
|
||||
procedure ActivateEngine;
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
procedure CreateLazIntfImageAndCanvas(out ABuffer: TLazIntfImage;
|
||||
out ACanvas: TFPCustomCanvas; AWidth, AHeight: Integer);
|
||||
{$ENDIF}
|
||||
procedure DblClick; override;
|
||||
Procedure DoDrawTile(const TileId: TTileId; X,Y: integer; TileImg: TLazIntfImage);
|
||||
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override;
|
||||
procedure DoOnResize; override;
|
||||
Function IsActive : Boolean;
|
||||
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y:Integer); override;
|
||||
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
|
||||
procedure MouseMove(Shift: TShiftState; X,Y: Integer); override;
|
||||
procedure Paint; override;
|
||||
procedure OnGPSItemsModified(Sender: TObject; objs: TGPSObjList;Adding : boolean);
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
procedure ClearBuffer;
|
||||
procedure GetMapProviders(lstProviders : TStrings);
|
||||
function GetVisibleArea: TRealArea;
|
||||
function LonLatToScreen(aPt: TRealPoint): TPoint;
|
||||
function ScreenToLonLat(aPt: TPoint): TRealPoint;
|
||||
procedure CenterOnObj(obj: TGPSObj);
|
||||
procedure ZoomOnArea(const aArea: TRealArea);
|
||||
procedure ZoomOnObj(obj: TGPSObj);
|
||||
procedure WaitEndOfRendering;
|
||||
property Center: TRealPoint read GetCenter write SetCenter;
|
||||
property Engine: TMapViewerEngine read FEngine;
|
||||
property GPSItems: TGPSObjectList read FGPSItems;
|
||||
published
|
||||
property Active: boolean read FActive write SetActive;
|
||||
property Align;
|
||||
property CacheOnDisk: boolean read GetCacheOnDisk write SetCacheOnDisk;
|
||||
property CachePath: String read GetCachePath write SetCachePath;
|
||||
property Height default 150;
|
||||
property InactiveColor: TColor read FInactiveColor write SetInactiveColor;
|
||||
property MapProvider: String read GetMapProvider write SetMapProvider;
|
||||
property POIImage: TBitmap read FPOIImage write FPOIImage;
|
||||
property PopupMenu;
|
||||
property UseThreads: boolean read GetUseThreads write SetUseThreads;
|
||||
property Width default 150;
|
||||
property Zoom: integer read GetZoom write SetZoom;
|
||||
property OnCenterMove: TNotifyEvent read GetOnCenterMove write SetOnCenterMove;
|
||||
property OnZoomChange: TNotifyEvent read GetOnZoomChange write SetOnZoomChange;
|
||||
property OnChange: TNotifyEvent Read GetOnChange write SetOnChange;
|
||||
property OnMouseDown;
|
||||
property OnMouseEnter;
|
||||
property OnMouseLeave;
|
||||
property OnMouseMove;
|
||||
property OnMouseUp;
|
||||
end;
|
||||
|
||||
procedure Register;
|
||||
|
||||
implementation
|
||||
uses
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
Math, FPImgCanv, FPImage, LCLVersion,
|
||||
{$ENDIF}
|
||||
GraphType, mvjobqueue, mvextradata, LResources;
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
{$I mvmapviewer_icon.lrs}
|
||||
RegisterComponents('Maps',[TMapView]);
|
||||
end;
|
||||
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
// Workaround for http://mantis.freepascal.org/view.php?id=27144
|
||||
procedure CopyPixels(ASource, ADest: TLazIntfImage;
|
||||
XDst: Integer = 0; YDst: Integer = 0;
|
||||
AlphaMask: Boolean = False; AlphaTreshold: Word = 0);
|
||||
var
|
||||
SrcHasMask, DstHasMask: Boolean;
|
||||
x, y, xStart, yStart, xStop, yStop: Integer;
|
||||
c: TFPColor;
|
||||
SrcRawImage, DestRawImage: TRawImage;
|
||||
begin
|
||||
ASource.GetRawImage(SrcRawImage);
|
||||
ADest.GetRawImage(DestRawImage);
|
||||
|
||||
if DestRawImage.Description.IsEqual(SrcRawImage.Description) and (XDst = 0) and (YDst = 0) then
|
||||
begin
|
||||
// same description -> copy
|
||||
if DestRawImage.Data <> nil then
|
||||
System.Move(SrcRawImage.Data^, DestRawImage.Data^, DestRawImage.DataSize);
|
||||
if DestRawImage.Mask <> nil then
|
||||
System.Move(SrcRawImage.Mask^, DestRawImage.Mask^, DestRawImage.MaskSize);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// copy pixels
|
||||
XStart := IfThen(XDst < 0, -XDst, 0);
|
||||
YStart := IfThen(YDst < 0, -YDst, 0);
|
||||
XStop := IfThen(ADest.Width - XDst < ASource.Width, ADest.Width - XDst, ASource.Width) - 1;
|
||||
YStop := IfTHen(ADest.Height - YDst < ASource.Height, ADest.Height - YDst, ASource.Height) - 1;
|
||||
|
||||
SrcHasMask := SrcRawImage.Description.MaskBitsPerPixel > 0;
|
||||
DstHasMask := DestRawImage.Description.MaskBitsPerPixel > 0;
|
||||
|
||||
if DstHasMask then begin
|
||||
for y:= yStart to yStop do
|
||||
for x:=xStart to xStop do
|
||||
ADest.Masked[x+XDst,y+YDst] := SrcHasMask and ASource.Masked[x,y];
|
||||
end;
|
||||
|
||||
for y:=yStart to yStop do
|
||||
for x:=xStart to xStop do
|
||||
begin
|
||||
c := ASource.Colors[x,y];
|
||||
if not DstHasMask and SrcHasMask and (c.alpha = $FFFF) then // copy mask to alpha channel
|
||||
if ASource.Masked[x,y] then
|
||||
c.alpha := 0;
|
||||
|
||||
ADest.Colors[x+XDst,y+YDst] := c;
|
||||
if AlphaMask and (c.alpha < AlphaTreshold) then
|
||||
ADest.Masked[x+XDst,y+YDst] := True;
|
||||
end;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
Type
|
||||
|
||||
{ TDrawObjJob }
|
||||
|
||||
TDrawObjJob = Class(TJob)
|
||||
private
|
||||
AllRun : boolean;
|
||||
Viewer : TMapView;
|
||||
FRunning : boolean;
|
||||
FLst : TGPSObjList;
|
||||
FStates : Array of integer;
|
||||
FArea : TRealArea;
|
||||
protected
|
||||
function pGetTask : integer;override;
|
||||
procedure pTaskStarted(aTask: integer);override;
|
||||
procedure pTaskEnded(aTask : integer;aExcept : Exception);override;
|
||||
public
|
||||
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);override;
|
||||
function Running : boolean;override;
|
||||
public
|
||||
Constructor Create(aViewer : TMapView;aLst : TGPSObjList;const aArea : TRealArea);
|
||||
destructor Destroy;override;
|
||||
end;
|
||||
|
||||
{ TDrawObjJob }
|
||||
|
||||
function TDrawObjJob.pGetTask: integer;
|
||||
var i : integer;
|
||||
begin
|
||||
if not(AllRun) and not(Cancelled) then
|
||||
Begin
|
||||
For i:=low(FStates) to high(FStates) do
|
||||
if FStates[i]=0 then
|
||||
Begin
|
||||
result:=i+1;
|
||||
Exit;
|
||||
end;
|
||||
AllRun:=True;
|
||||
end;
|
||||
Result:=ALL_TASK_COMPLETED;
|
||||
For i:=low(FStates) to high(FStates) do
|
||||
if FStates[i]=1 then
|
||||
Begin
|
||||
Result:=NO_MORE_TASK;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDrawObjJob.pTaskStarted(aTask: integer);
|
||||
begin
|
||||
FRunning:=True;
|
||||
FStates[aTask-1]:=1;
|
||||
end;
|
||||
|
||||
procedure TDrawObjJob.pTaskEnded(aTask: integer; aExcept: Exception);
|
||||
begin
|
||||
if Assigned(aExcept) then
|
||||
FStates[aTask-1]:=3
|
||||
Else
|
||||
FStates[aTask-1]:=2;
|
||||
end;
|
||||
|
||||
procedure TDrawObjJob.ExecuteTask(aTask: integer; FromWaiting: boolean);
|
||||
var iObj : integer;
|
||||
Obj : TGpsObj;
|
||||
begin
|
||||
iObj:=aTask-1;
|
||||
Obj:=FLst[iObj];
|
||||
if Obj.InheritsFrom(TGPSTrack) then
|
||||
Begin
|
||||
Viewer.DrawTrk(FArea,TGPSTrack(Obj));
|
||||
End;
|
||||
if Obj.InheritsFrom(TGPSPoint) then
|
||||
Begin
|
||||
Viewer.DrawPt(FArea,TGPSPoint(Obj));
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDrawObjJob.Running: boolean;
|
||||
begin
|
||||
Result:=FRunning;
|
||||
end;
|
||||
|
||||
constructor TDrawObjJob.Create(aViewer: TMapView; aLst: TGPSObjList;
|
||||
const aArea: TRealArea);
|
||||
begin
|
||||
FArea:=aArea;
|
||||
FLst:=aLst;
|
||||
SetLEngth(FStates,FLst.Count);
|
||||
Viewer:=aViewer;
|
||||
AllRun:=false;
|
||||
Name:='DrawObj';
|
||||
end;
|
||||
|
||||
destructor TDrawObjJob.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
FreeAndNil(FLst);
|
||||
if not(Cancelled) then
|
||||
Viewer.CallAsyncInvalidate;
|
||||
end;
|
||||
|
||||
|
||||
{ TMapView }
|
||||
|
||||
procedure TMapView.SetActive(AValue: boolean);
|
||||
begin
|
||||
if FActive=AValue then Exit;
|
||||
FActive:=AValue;
|
||||
if FActive then
|
||||
ActivateEngine
|
||||
else
|
||||
Engine.Active:=false;
|
||||
end;
|
||||
|
||||
function TMapView.GetCacheOnDisk: boolean;
|
||||
begin
|
||||
Result:=Engine.CacheOnDisk;
|
||||
end;
|
||||
|
||||
function TMapView.GetCachePath: String;
|
||||
begin
|
||||
Result:=Engine.CachePath;
|
||||
end;
|
||||
|
||||
function TMapView.GetCenter: TRealPoint;
|
||||
begin
|
||||
Result:=Engine.Center;
|
||||
end;
|
||||
|
||||
function TMapView.GetMapProvider: String;
|
||||
begin
|
||||
result:=Engine.MapProvider;
|
||||
end;
|
||||
|
||||
function TMapView.GetOnCenterMove: TNotifyEvent;
|
||||
begin
|
||||
result:=Engine.OnCenterMove;
|
||||
end;
|
||||
|
||||
function TMapView.GetOnChange: TNotifyEvent;
|
||||
begin
|
||||
Result:=Engine.OnChange;
|
||||
end;
|
||||
|
||||
function TMapView.GetOnZoomChange: TNotifyEvent;
|
||||
begin
|
||||
Result:=Engine.OnZoomChange;
|
||||
end;
|
||||
|
||||
function TMapView.GetUseThreads: boolean;
|
||||
begin
|
||||
Result:=Engine.UseThreads;
|
||||
end;
|
||||
|
||||
function TMapView.GetZoom: integer;
|
||||
begin
|
||||
result:=Engine.Zoom;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetCacheOnDisk(AValue: boolean);
|
||||
begin
|
||||
Engine.CacheOnDisk:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetCachePath(AValue: String);
|
||||
begin
|
||||
Engine.CachePath:=CachePath;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetCenter(AValue: TRealPoint);
|
||||
begin
|
||||
Engine.Center:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetInactiveColor(AValue: TColor);
|
||||
begin
|
||||
if FInactiveColor=AValue then Exit;
|
||||
FInactiveColor:=AValue;
|
||||
if not(IsActive) then
|
||||
invalidate;
|
||||
end;
|
||||
|
||||
procedure TMapView.ActivateEngine;
|
||||
begin
|
||||
Engine.SetSize(ClientWidth,ClientHeight);
|
||||
if IsActive then
|
||||
Engine.Active:=true
|
||||
else
|
||||
Engine.Active:=false;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetMapProvider(AValue: String);
|
||||
begin
|
||||
Engine.MapProvider:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetOnCenterMove(AValue: TNotifyEvent);
|
||||
begin
|
||||
Engine.OnCenterMove:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetOnChange(AValue: TNotifyEvent);
|
||||
begin
|
||||
Engine.OnChange:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetOnZoomChange(AValue: TNotifyEvent);
|
||||
begin
|
||||
Engine.OnZoomChange:=AValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetUseThreads(AValue: boolean);
|
||||
begin
|
||||
Engine.UseThreads:=aValue;
|
||||
end;
|
||||
|
||||
procedure TMapView.SetZoom(AValue: integer);
|
||||
begin
|
||||
Engine.Zoom:=AValue;
|
||||
end;
|
||||
|
||||
function TMapView.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
|
||||
MousePos: TPoint): Boolean;
|
||||
begin
|
||||
Result:=inherited DoMouseWheel(Shift, WheelDelta, MousePos);
|
||||
if IsActive then
|
||||
Engine.MouseWheel(self,Shift,WheelDelta,MousePos,Result);
|
||||
end;
|
||||
|
||||
procedure TMapView.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
||||
Y: Integer);
|
||||
begin
|
||||
inherited MouseDown(Button, Shift, X, Y);
|
||||
if IsActive then
|
||||
Engine.MouseDown(self,Button,Shift,X,Y);
|
||||
end;
|
||||
|
||||
procedure TMapView.MouseUp(Button: TMouseButton; Shift: TShiftState;
|
||||
X: Integer; Y: Integer);
|
||||
begin
|
||||
inherited MouseUp(Button, Shift, X, Y);
|
||||
if IsActive then
|
||||
Engine.MouseUp(self,Button,Shift,X,Y);
|
||||
end;
|
||||
|
||||
procedure TMapView.MouseMove(Shift: TShiftState; X: Integer; Y: Integer);
|
||||
var aPt : TPoint;
|
||||
begin
|
||||
inherited MouseMove(Shift, X, Y);
|
||||
if IsActive then
|
||||
Engine.MouseMove(self,Shift,X,Y);
|
||||
end;
|
||||
|
||||
procedure TMapView.DblClick;
|
||||
begin
|
||||
inherited DblClick;
|
||||
if IsActive then
|
||||
Engine.DblClick(self);
|
||||
end;
|
||||
|
||||
procedure TMapView.DoOnResize;
|
||||
begin
|
||||
inherited DoOnResize;
|
||||
//cancel all rendering threads
|
||||
Engine.CancelCurrentDrawing;
|
||||
FreeAndNil(Buffer);
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer := TRGB32Bitmap.Create(ClientWidth,ClientHeight);
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
BufferCanvas.Free;
|
||||
CreateLazIntfImageAndCanvas(Buffer, BufferCanvas, ClientWidth, ClientHeight);
|
||||
{$ENDIF}
|
||||
if IsActive then
|
||||
Engine.SetSize(ClientWidth, ClientHeight);
|
||||
end;
|
||||
|
||||
procedure TMapView.Paint;
|
||||
var
|
||||
bmp: TBitmap;
|
||||
begin
|
||||
inherited Paint;
|
||||
if IsActive and Assigned(Buffer) then
|
||||
begin
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer.Canvas.DrawTo(Canvas,0,0);
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
bmp := TBitmap.Create;
|
||||
try
|
||||
bmp.SetSize(Buffer.Width, Buffer.Height);
|
||||
bmp.LoadFromIntfImage(Buffer);
|
||||
Canvas.Draw(0, 0, bmp);
|
||||
finally
|
||||
bmp.Free;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end
|
||||
else
|
||||
begin
|
||||
Canvas.Brush.Color:=InactiveColor;
|
||||
Canvas.Brush.Style:=bsSolid;
|
||||
Canvas.FillRect(0,0,ClientWidth,ClientHeight);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapView.OnGPSItemsModified(Sender: TObject; objs: TGPSObjList;
|
||||
Adding: boolean);
|
||||
var Area,ObjArea,vArea : TRealArea;
|
||||
begin
|
||||
if Adding and assigned(Objs) then
|
||||
Begin
|
||||
ObjArea:=GetAreaOf(Objs);
|
||||
vArea:=GetVisibleArea;
|
||||
if hasIntersectArea(ObjArea,vArea) then
|
||||
Begin
|
||||
Area:=IntersectArea(ObjArea,vArea);
|
||||
Engine.Jobqueue.AddJob(TDrawObjJob.Create(self,Objs,Area),Engine);
|
||||
end
|
||||
else
|
||||
objs.Free;
|
||||
end
|
||||
else
|
||||
Begin
|
||||
Engine.Redraw;
|
||||
Objs.free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapView.DrawTrk(const Area : TRealArea;trk : TGPSTrack);
|
||||
var Old,New : TPoint;
|
||||
i : integer;
|
||||
aPt : TRealPoint;
|
||||
LastInside,IsInside : boolean;
|
||||
trkColor : TColor;
|
||||
Begin
|
||||
if trk.Points.Count>0 then
|
||||
Begin
|
||||
trkColor:=clRed;
|
||||
if trk.ExtraData<>nil then
|
||||
Begin
|
||||
if trk.ExtraData.inheritsFrom(TDrawingExtraData) then
|
||||
trkColor:=TDrawingExtraData(trk.ExtraData).Color;
|
||||
end;
|
||||
LastInside:=false;
|
||||
For i:=0 to pred(trk.Points.Count) do
|
||||
Begin
|
||||
aPt:=trk.Points[i].RealPoint;
|
||||
IsInside:=PtInsideArea(aPt,Area);
|
||||
if IsInside or LastInside then
|
||||
Begin
|
||||
New:=Engine.LonLatToScreen(aPt);
|
||||
if i>0 then
|
||||
Begin
|
||||
if not(LastInside) then
|
||||
Old:=Engine.LonLatToScreen(trk.Points[pred(i)].RealPoint);
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer.canvas.OutlineColor := trkColor;
|
||||
Buffer.canvas.Line(Old.X,Old.y,New.X,New.Y);
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
BufferCanvas.Pen.FPColor := TColorToFPColor(trkColor);
|
||||
BufferCanvas.Line(Old.X, Old.Y, New.X, New.Y);
|
||||
{$ENDIF}
|
||||
end;
|
||||
Old:=New;
|
||||
LastInside:=IsInside;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapView.DrawPt(const Area: TRealArea; aPOI: TGPSPoint);
|
||||
var
|
||||
PT : TPoint;
|
||||
PtColor : TColor;
|
||||
begin
|
||||
Pt:=Engine.LonLatToScreen(aPOI.RealPoint);
|
||||
PtColor:=clRed;
|
||||
if aPOI.ExtraData<>nil then
|
||||
Begin
|
||||
if aPOI.ExtraData.inheritsFrom(TDrawingExtraData) then
|
||||
PtColor:=TDrawingExtraData(aPOI.ExtraData).Color;
|
||||
end;
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer.canvas.OutlineColor:=ptColor;
|
||||
Buffer.canvas.Line(Pt.X,Pt.y-5,Pt.X,Pt.Y+5);
|
||||
Buffer.canvas.Line(Pt.X-5,Pt.y,Pt.X+5,Pt.Y);
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
BufferCanvas.Pen.FPColor := TColorToFPColor(ptColor);
|
||||
BufferCanvas.Line(Pt.X, Pt.Y-5, Pt.X, Pt.Y+5);
|
||||
BufferCanvas.Line(Pt.X-5, Pt.Y, Pt.X+5, Pt.Y);
|
||||
{$ENDIF}
|
||||
|
||||
// Buffer.Draw();
|
||||
end;
|
||||
|
||||
procedure TMapView.CallAsyncInvalidate;
|
||||
Begin
|
||||
if not(AsyncInvalidate) then
|
||||
Begin
|
||||
AsyncInvalidate:=true;
|
||||
Engine.Jobqueue.QueueAsyncCall(@DoAsyncInvalidate,0);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapView.DrawObjects(const TileId: TTileId; aLeft, aTop,aRight,aBottom: integer);
|
||||
var aPt : TPoint;
|
||||
Area : TRealArea;
|
||||
lst : TGPSObjList;
|
||||
i : integer;
|
||||
trk : TGPSTrack;
|
||||
begin
|
||||
aPt.X:=aLeft;
|
||||
aPt.Y:=aTop;
|
||||
Area.TopLeft:=Engine.ScreenToLonLat(aPt);
|
||||
aPt.X:=aRight;
|
||||
aPt.Y:=aBottom;
|
||||
Area.BottomRight:=Engine.ScreenToLonLat(aPt);
|
||||
if GPSItems.count>0 then
|
||||
begin
|
||||
lst:=GPSItems.GetObjectsInArea(Area);
|
||||
if lst.Count>0 then
|
||||
Engine.Jobqueue.AddJob(TDrawObjJob.Create(self,lst,Area),Engine)
|
||||
else
|
||||
begin
|
||||
freeAndNil(Lst);
|
||||
CallAsyncInvalidate;
|
||||
end;
|
||||
end
|
||||
Else
|
||||
CallAsyncInvalidate;
|
||||
end;
|
||||
|
||||
procedure TMapView.DoAsyncInvalidate(Data: PtrInt);
|
||||
Begin
|
||||
Invalidate;
|
||||
AsyncInvalidate:=false;
|
||||
end;
|
||||
|
||||
procedure TMapView.DoDrawTile(const TileId: TTileId; X, Y: integer;
|
||||
TileImg: TLazIntfImage);
|
||||
var
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
temp : TRGB32Bitmap;
|
||||
ri : TRawImage;
|
||||
BuffLaz : TLazIntfImage;
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
temp: TBitmap;
|
||||
{$ENDIF}
|
||||
begin
|
||||
if Assigned(Buffer) then
|
||||
begin
|
||||
if Assigned(TileImg) then
|
||||
Begin
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
if (X>=0) and (Y>=0) then //http://mantis.freepascal.org/view.php?id=27144
|
||||
begin
|
||||
ri.Init;
|
||||
ri.Description.Init_BPP32_R8G8B8A8_BIO_TTB(Buffer.Width,Buffer.Height);
|
||||
ri.Data:=Buffer.Pixels;
|
||||
BuffLaz := TLazIntfImage.Create(ri,false);
|
||||
try
|
||||
BuffLaz.CopyPixels(TileImg,X,y);
|
||||
ri.Init;
|
||||
finally
|
||||
FreeandNil(BuffLaz);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
//i think it take more memory then the previous method but work in all case
|
||||
temp:=TRGB32Bitmap.CreateFromLazIntfImage(TileImg);
|
||||
try
|
||||
Buffer.Draw(X,Y,temp);
|
||||
finally
|
||||
FreeAndNil(Temp);
|
||||
end;
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
{$IF LCL_FULLVERSION < 1090000}
|
||||
{ Workaround for //http://mantis.freepascal.org/view.php?id=27144 }
|
||||
CopyPixels(TileImg, Buffer, X, Y);
|
||||
{$ELSE}
|
||||
Buffer.CopyPixels(TileImg, X, Y);
|
||||
{$IFEND}
|
||||
{$ENDIF}
|
||||
end
|
||||
else
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer.Canvas.FillRect(X,Y,X+TILE_SIZE,Y+TILE_SIZE);
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
begin
|
||||
BufferCanvas.Brush.FPColor := ColWhite;
|
||||
BufferCanvas.FillRect(X, Y, X + TILE_SIZE, Y + TILE_SIZE);
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
DrawObjects(TileId,X,Y,X+TILE_SIZE,Y+TILE_SIZE);
|
||||
end;
|
||||
|
||||
function TMapView.IsActive: Boolean;
|
||||
begin
|
||||
if not(csDesigning in ComponentState) then
|
||||
Result:=FActive
|
||||
else
|
||||
Result:=false;
|
||||
end;
|
||||
|
||||
constructor TMapView.Create(AOwner: TComponent);
|
||||
begin
|
||||
Active := false;
|
||||
FGPSItems := TGPSObjectList.Create;
|
||||
FGPSItems.OnModified := @OnGPSItemsModified;
|
||||
FInactiveColor := clWhite;
|
||||
FEngine := TMapViewerEngine.Create(self);
|
||||
dl := TMVDESynapse.Create(self);
|
||||
{$IFDEF USE_RGBGRAPHICS}
|
||||
Buffer := TRGB32Bitmap.Create(Width,Height);
|
||||
{$ENDIF}
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
CreateLazIntfImageAndCanvas(Buffer, BufferCanvas, Width, Height);
|
||||
{$ENDIF}
|
||||
Engine.CachePath := 'cache/';
|
||||
Engine.CacheOnDisk := true;
|
||||
Engine.OnDrawTile := @DoDrawTile;
|
||||
Engine.DrawTitleInGuiThread := false;
|
||||
Engine.DownloadEngine := dl;
|
||||
inherited Create(AOwner);
|
||||
Width := 150;
|
||||
Height := 150;
|
||||
end;
|
||||
|
||||
destructor TMapView.Destroy;
|
||||
begin
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
BufferCanvas.Free;
|
||||
{$ENDIF}
|
||||
Buffer.Free;
|
||||
inherited Destroy;
|
||||
FreeAndNil(FGPSItems);
|
||||
end;
|
||||
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
procedure TMapView.CreateLazIntfImageAndCanvas(out ABuffer: TLazIntfImage;
|
||||
out ACanvas: TFPCustomCanvas; AWidth, AHeight: Integer);
|
||||
var
|
||||
rawImg: TRawImage;
|
||||
begin
|
||||
rawImg.Init;
|
||||
rawImg.Description.Init_BPP24_B8G8R8_BIO_TTB(AWidth, AHeight);
|
||||
rawImg.CreateData(True);
|
||||
ABuffer := TLazIntfImage.Create(rawImg, true);
|
||||
ACanvas := TFPImageCanvas.Create(ABuffer);
|
||||
ACanvas.Brush.FPColor := colWhite;
|
||||
ACanvas.FillRect(0, 0, AWidth, AHeight);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function TMapView.ScreenToLonLat(aPt: TPoint): TRealPoint;
|
||||
begin
|
||||
Result:=Engine.ScreenToLonLat(aPt);
|
||||
end;
|
||||
|
||||
function TMapView.LonLatToScreen(aPt: TRealPoint): TPoint;
|
||||
begin
|
||||
Result:=LonLatToScreen(aPt);
|
||||
end;
|
||||
|
||||
procedure TMapView.GetMapProviders(lstProviders: TStrings);
|
||||
begin
|
||||
Engine.GetMapProviders(lstProviders);
|
||||
end;
|
||||
|
||||
procedure TMapView.WaitEndOfRendering;
|
||||
begin
|
||||
Engine.Jobqueue.WaitAllJobTerminated(Engine);
|
||||
end;
|
||||
|
||||
procedure TMapView.CenterOnObj(obj: TGPSObj);
|
||||
var Area : TRealArea;
|
||||
Pt : TRealPoint;
|
||||
begin
|
||||
obj.GetArea(Area);
|
||||
Pt.Lon:=(Area.TopLeft.Lon+Area.BottomRight.Lon) /2;
|
||||
Pt.Lat:=(Area.TopLeft.Lat+Area.BottomRight.Lat) /2;
|
||||
Center:=Pt;
|
||||
end;
|
||||
|
||||
procedure TMapView.ZoomOnObj(obj: TGPSObj);
|
||||
var Area : TRealArea;
|
||||
begin
|
||||
obj.GetArea(Area);
|
||||
Engine.ZoomOnArea(Area);
|
||||
end;
|
||||
|
||||
procedure TMapView.ZoomOnArea(const aArea: TRealArea);
|
||||
begin
|
||||
Engine.ZoomOnArea(aArea);
|
||||
end;
|
||||
|
||||
function TMapView.GetVisibleArea: TRealArea;
|
||||
var aPt : TPoint;
|
||||
begin
|
||||
aPt.X:=0;
|
||||
aPt.Y:=0;
|
||||
Result.TopLeft:=Engine.ScreenToLonLat(aPt);
|
||||
aPt.X:=Width;
|
||||
aPt.Y:=Height;
|
||||
Result.BottomRight:=Engine.ScreenToLonLat(aPt);;
|
||||
end;
|
||||
|
||||
procedure TMapView.ClearBuffer;
|
||||
begin
|
||||
{$IFDEF USE_LAZINTFIMAGE}
|
||||
CreateLazIntfImageAndCanvas(Buffer, BufferCanvas, ClientWidth, ClientHeight);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
end.
|
||||
|
54
components/lazmapviewer/source/mvmapviewer_icon.lrs
Normal file
54
components/lazmapviewer/source/mvmapviewer_icon.lrs
Normal file
@ -0,0 +1,54 @@
|
||||
LazarusResources.Add('TMapViewer','PNG',[
|
||||
#137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0
|
||||
+#0#0#6'bKGD'#0#255#0#255#0#255#160#189#167#147#0#0#0#9'pHYs'#0#0#11#19#0#0#11
|
||||
+#19#1#0#154#156#24#0#0#4#127'IDATH'#199#165#150#217'n'#20'W'#16#134#191':'
|
||||
+#231#244'63'#158#5#143#205'"c'#2'Al'#10#216'(w'#201#3'D'#17#202#211'"'#30'!'
|
||||
+#185#9#138#29#161#128#162#160#16#2'x'#155#177#199#179#245#222#231#228'b'#198
|
||||
+'c'#6'B'#20'%u'#211']'#173#174#255'T'#213#255'Wu'#203#147#221']'#231#128'@k'
|
||||
+#186#181#144#184'(8I2.D!'#183#186'-'#146#188#228#217#209#9#255#213#12'@d4_^Y'
|
||||
+'C'#128#131'I'#194#141'N'#11#17#8#148'b'#130#163#29#250#12#179#28#231#254#30
|
||||
+#196#211#138#210':'#220#252#5#1#206'^U'#206#193#221#181#14'''IF'#229#28'F'#9
|
||||
+'u_'#19#25#141#3'V'#195#128#245'z'#180#0#215'"l4'#235#212'<'#131#3#26#190'G'
|
||||
+#168'5'#206'9D'#160'r'#142#235#157'&v'#30#160'.'#173#212'8'#156'$'#212'='#195
|
||||
+'o'#199'C'#154#129#191#148#169#18#225#221'x'#186#240'WB'#15#173#20'qQ"'#192
|
||||
+'8/'#24#229#197','#198#205#18'8'#156'&'#172'F!'#14'PqQ'#2'0'#201#11#250'q'
|
||||
+#202'(/'#22#167'3/'#213'('#189#240'Gi'#193#171#193'h'#225#203#156#191#11#181
|
||||
+'`'#6'('#130#167#132'['#221#22#129'V'#168#202'Z'#140#18#6'i'#142#18#225'Eo'
|
||||
+#192#193'4Y'#0#148#214#145#149#229#194#183#206#161'E'#150'8'#168'y'#134'A'
|
||||
+#146#1'p'#183#219#230#254#250#5#4#161#29#5#168'n=$'#173'*.7"'#30'\\E'#139'0L'
|
||||
+'s'#206'0Jk'#153#230#179'v'#156'U'#20'z'#134#134#167#169#220#140#216#180',Y'
|
||||
+#171'G<'#188#212#165#19#5#243#170#133';'#171'mLd'#12#235#181#136#131'I'#140
|
||||
+#136#176'^'#143#24'e9'#130#144#219#138#231#189#1#145#167#201'+;S'#140#18#238
|
||||
+#172'D'#248#190#225'('#171#168#156#165#27#133'h'#165'(m'#181'T'#153'u'#14#181
|
||||
+'V'#11#17#129#180#172'(l'#133'u'#142#172#156']'#159#190#235'1'#201#11#174'4'
|
||||
+#235#139#128#205'f'#157#17#130'C'#209#9#3'6'#155#13'j'#158'!'#208#138#186#231
|
||||
+'}$a'#5#240#250't'#194#222'8'#230#179'V'#147#154'g'#200'+'#203#211#189#30#213
|
||||
+#156#236'W'#131'1F)'#2#163#169'{'#30#135#211#148#10#136#188's'#242#229#3'^'
|
||||
+#150#6#237#222'Z'#135'v'#24#160#4#174#183'W8I2FY'#190#164#148#150'o'#176#14
|
||||
+#178#170#226'j='#164'H'#19'"'#223#195'ZK^'#20'h'#165'p'#206#225#251'>UU!"h'
|
||||
+#173'QY'#158'3'#156'N'#241'e'#150#237'/'#189#1'Z'#132#15#135#246'8'#201#216
|
||||
+'l5 '#137'I'#135'C'#252'0b'#146#164#140#227#152' '#8#240'<'#15#223#247#24#156
|
||||
+#158'.'#218'y|2'#192#4#190'O'#0#164'E'#193'8+8'#142'S*'#231'x'#191'`'#7'l'
|
||||
+#214'B'#142#147#140#161#21'"'#17#252#188'@'#128#195#211'1'#27#8'e'#158'S'#139
|
||||
+'B:'#237'6'#206'9'#242#162#160#211'n'#161#242'|'#222#10#165'x'#222#31','#250
|
||||
+#254#161#137'o'#184#216#136'X'#247'=\'#16'r'#146#21#216'$'#230#218'j'#135#192
|
||||
+'h'#162'0$'#207#11'D'#4#17'!'#240'}'#140'R'#24#223#247#249#225#205#1'F'#169
|
||||
+'On'#196'P'#11'+'#206#18#26'M'''#10#184#28#248'T'#214'2'#173','#206'A?I'#209
|
||||
+#2'W'#218'-'#246#143#250'xF'#211'\Y!'#1#204#143'{='#174#214'Cz'#147#148'J'#9
|
||||
+'JdiU `'#16'|'#223''''#142#19#130#192#167#172','#198'h'#166#195'1Q'#24#240'v'
|
||||
+#18'SX'#199#197'f'#131'WY'#201#26#138#184#223#231'u'#238'PYY'#241#199'8%'#21
|
||||
+#184#223#237#240#237#214#22#29'-'#139'V='#218#218'&'#174','#189'i'#194#149
|
||||
+#171'7X]'#223' '#201'RF'#163'1wn'#222#225#218#198'u'#190'y'#176#133#0'?'#237
|
||||
+#247#177#206'1*J'#250'N'#211'4z&S'#165#4'_+TY'#0#240#213#253'-^'#190'}'#197
|
||||
+#205#141#235#11#146#183'n'#223#227#241#206#14#235#129#199#198#213#207'y'#251
|
||||
+#231'K'#0#30#239#236#160'Dx'#180#189#205#147#221']'#0#10#231#232#134#1#158
|
||||
+#146#217#1#206'9'#226#162#196#206''''#241#244'x'#159#246#234'e'#190#255#245#5
|
||||
+'_'#223#190#187#180#186#147#185#190#178't'#182#220#190'{'#248#16'`'#1#14'PT'
|
||||
+#150#189'I|>hg'#193#207#142#6#179#224','#227#224#232#29';'#251#253'%'#178#31
|
||||
+'mo/'#238#27#245#8#128#159#127#127#201#155#209#228'c'#213#1#155#173#198#249#1
|
||||
+#239'[YYv'#143'z'#31'=?'#203#242#209#246'6'#251#201'L'#222'o'#134#227'O'#174
|
||||
+#137#192'h'#228#201#238#238'B2'#13#223#227#139#245#14'/z'#167#12#223'['#21#31
|
||||
+'Ze'#29'J'#132'O'#224#158#15#168's'#231#21#184#249#242'z'#209';'#229'4'#203
|
||||
+#249#167'X'#173#228'_'#253'Q'#136#8'K'#211'U'#148#21'qQ.'#190'X"'#194#255#181
|
||||
+#191#0#1#137#23#12'Mu'#148#1#0#0#0#0'IEND'#174'B`'#130
|
||||
]);
|
54
components/lazmapviewer/source/mvtypes.pas
Normal file
54
components/lazmapviewer/source/mvtypes.pas
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
(c) 2014 ti_dic
|
||||
Parts of this component are based on :
|
||||
Map Viewer Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
}
|
||||
|
||||
unit mvtypes;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
|
||||
const
|
||||
TILE_SIZE = 256;
|
||||
|
||||
Type
|
||||
{ TArea }
|
||||
TArea = record
|
||||
top, left, bottom, right: Int64;
|
||||
end;
|
||||
|
||||
{ TRealPoint }
|
||||
TRealPoint = Record
|
||||
Lon : Double;
|
||||
Lat : Double;
|
||||
end;
|
||||
|
||||
{ TRealArea }
|
||||
TRealArea = Record
|
||||
TopLeft : TRealPoint;
|
||||
BottomRight : TRealPoint;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user