
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9306 8e941d3f-bd1b-0410-a28a-d453659cc2b4
3077 lines
79 KiB
ObjectPascal
3077 lines
79 KiB
ObjectPascal
{ Initial map viewer library:
|
|
Copyright (C) 2011 Maciej Kaczkowski / keit.co
|
|
|
|
Extensions:
|
|
(C) 2014 ti_dic@hotmail.com
|
|
(C) 2019 Werner Pamler (user wp at Lazarus forum https://forum.lazarus.freepascal.org)
|
|
(C) 2023 Yuliyan Ivanov (user alpine at Lazarus forum https://forum.lazarus.freepascal.org)
|
|
|
|
License: modified LGPL with linking exception (like RTL, FCL and LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in the Lazarus distribution,
|
|
for details about the license.
|
|
|
|
See also: https://wiki.lazarus.freepascal.org/FPC_modified_LGPL
|
|
}
|
|
|
|
// ToDo: Make Active work at designtime.
|
|
|
|
// "Deprecated" warnings:
|
|
// - function names containing "LonLat" were copied and named to contain "LatLon"
|
|
// (will be removed in v1.0)
|
|
|
|
unit mvMapViewer;
|
|
|
|
{$MODE objfpc}{$H+}
|
|
{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined}
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Controls, GraphType, Graphics, FPImage, IntfGraphics,
|
|
Forms, ImgList, LCLVersion, fgl,
|
|
MvTypes, MvGPSObj, MvEngine, MvMapProvider, MvDownloadEngine, MvDrawingEngine,
|
|
mvCache, mvExtraData;
|
|
|
|
Type
|
|
|
|
TDrawGpsPointEvent = procedure (Sender: TObject;
|
|
ADrawer: TMvCustomDrawingEngine; APoint: TGpsPoint) of object;
|
|
|
|
TMapViewOption =
|
|
(
|
|
mvoMouseDragging, // Allow dragging of the map with the mouse
|
|
mvoMouseZooming, // Allow zooming into the map with the mouse
|
|
mvoLatLonInDMS // Use Degrees, Minutes and Seconds for Lat/Lon
|
|
);
|
|
|
|
TMapViewOptions = set of TMapViewOption;
|
|
|
|
TCacheLocation = (clProfile, clTemp, clCustom);
|
|
|
|
const
|
|
DefaultMapViewOptions = [mvoMouseDragging, mvoMouseZooming];
|
|
|
|
type
|
|
TMapItem = class;
|
|
TMapView = class;
|
|
TMapPoint = class;
|
|
TMapLayer = class;
|
|
TMapLayers = class;
|
|
TPointOfInterest = class;
|
|
TPointsOfInterest = class;
|
|
TMapTrack = class;
|
|
TMapTracks = class;
|
|
TGPSTileLayer = class;
|
|
TGPSComboLayer = class;
|
|
|
|
TPointOfInterestDrawEvent = procedure(Sender: TObject;
|
|
ADrawer: TMvCustomDrawingEngine; APoint: TPointOfInterest) of object;
|
|
|
|
TMapTrackDrawEvent = procedure(Sender: TObject;
|
|
ADrawer: TMvCustomDrawingEngine; ATrack: TMapTrack) of object;
|
|
|
|
{ TMapObjectList }
|
|
|
|
TMapObjectList = class(specialize TFPGObjectList<TObject>)
|
|
public
|
|
constructor Create(ASingleObj: TObject = Nil); reintroduce;
|
|
constructor Create(AList: TMapObjectList);
|
|
class function AddListToResult(AList, AResult: TMapObjectList): TMapObjectList;
|
|
end;
|
|
|
|
{ TMapItem }
|
|
|
|
TMapItem = class(TCollectionItem)
|
|
private
|
|
FCaption: TCaption;
|
|
FTag: PtrInt;
|
|
FVisible: Boolean;
|
|
function GetGPSObj: TGPSObj; virtual; abstract;
|
|
function GetView: TMapView; virtual;
|
|
function GetLayer: TMapLayer; virtual;
|
|
procedure SetCaption(AValue: TCaption);
|
|
procedure SetVisible(AValue: Boolean);
|
|
protected
|
|
function GetDisplayName: string; override;
|
|
procedure SetIndex(Value: Integer); override;
|
|
procedure ItemChanged; virtual; abstract;
|
|
public
|
|
function HitTest(constref Area: TRealArea): TMapObjectList; virtual; abstract;
|
|
property View: TMapView read GetView;
|
|
property Layer: TMapLayer read GetLayer;
|
|
PROPERTY GPSObj: TGPSObj read GetGPSObj;
|
|
published
|
|
property Caption: TCaption read FCaption write SetCaption;
|
|
property Visible: Boolean read FVisible write SetVisible default True;
|
|
property Tag: PtrInt read FTag write FTag default 0;
|
|
end;
|
|
|
|
{ TMapCollectionBase }
|
|
|
|
TMapCollectionBase = class(TOwnedCollection)
|
|
private
|
|
FBaseZ: Integer;
|
|
protected
|
|
function GetView: TMapView; virtual;
|
|
function GetLayer: TMapLayer; virtual;
|
|
procedure FixOrder(APrevIndex, AIndex: Integer); virtual;
|
|
procedure Update(Item: TCollectionItem); override;
|
|
public
|
|
property View: TMapView read GetView;
|
|
property Layer: TMapLayer read GetLayer;
|
|
property BaseZ: Integer read FBaseZ write FBaseZ;
|
|
end;
|
|
|
|
{ TMapCollection }
|
|
|
|
generic TMapCollection<T: TMapItem; OT: class> = class(TMapCollectionBase)
|
|
private
|
|
type
|
|
TItemClass = T;
|
|
TOwnerClass = OT;
|
|
private
|
|
FMCOwner: TOwnerClass;
|
|
function GetFirst: TItemClass;
|
|
function GetItems(Index: Integer): TItemClass;
|
|
function GetLast: TItemClass;
|
|
procedure SetItems(Index: Integer; AValue: TItemClass);
|
|
public
|
|
constructor Create(AOwner: OT; ABaseZ: Integer);
|
|
function HitTest(constref Area: TRealArea): TMapObjectList; virtual;
|
|
property MCOwner: TOwnerClass read FMCOwner;
|
|
property First: TItemClass read GetFirst;
|
|
property Last: TItemClass read GetLast;
|
|
property Items[Index: Integer]: TItemClass read GetItems write SetItems; default;
|
|
end;
|
|
|
|
{ TMapLayer }
|
|
|
|
TMapLayer = class(TMapItem)
|
|
strict private
|
|
FComboLayer: TGPSComboLayer;
|
|
FDrawMode: TItemDrawMode;
|
|
FUseThreads: Boolean;
|
|
FMapProvider: String;
|
|
FOpacity: Single;
|
|
FPointsOfInterest: TPointsOfInterest;
|
|
FTracks: TMapTracks;
|
|
private
|
|
function GetGPSObj: TGPSObj; override;
|
|
function GetView: TMapView; override;
|
|
function GetLayer: TMapLayer; override;
|
|
function GetMapProvider: String;
|
|
function GetPointsOfInterest: TPointsOfInterest;
|
|
function GetTracks: TMapTracks;
|
|
function GetUseThreads: Boolean;
|
|
procedure SetDrawMode(AValue: TItemDrawMode);
|
|
procedure SetMapProvider(AValue: String);
|
|
procedure SetOpacity(AValue: Single);
|
|
procedure SetPointsOfInterest(AValue: TPointsOfInterest);
|
|
procedure SetTracks(AValue: TMapTracks);
|
|
procedure SetUseThreads(AValue: Boolean);
|
|
protected
|
|
procedure ItemChanged; override;
|
|
public
|
|
constructor Create(ACollection: TCollection); override;
|
|
destructor Destroy; override;
|
|
function HitTest(constref Area: TRealArea): TMapObjectList; override;
|
|
procedure AssignFromGPSList(AList: TGPSObjectList);
|
|
property ComboLayer: TGPSComboLayer read FComboLayer;
|
|
published
|
|
property MapProvider: String read GetMapProvider write SetMapProvider;
|
|
property UseThreads: Boolean read GetUseThreads write SetUseThreads default True;
|
|
property DrawMode: TItemDrawMode read FDrawMode write SetDrawMode default idmUseOpacity;
|
|
property Opacity: Single read FOpacity write SetOpacity default 0.25;
|
|
property PointsOfInterest: TPointsOfInterest read GetPointsOfInterest write SetPointsOfInterest;
|
|
property Tracks: TMapTracks read GetTracks write SetTracks;
|
|
end;
|
|
|
|
{ TMapLayers }
|
|
|
|
TMapLayers = class(specialize TMapCollection<TMapLayer, TMapView>)
|
|
protected
|
|
function GetView: TMapView; override;
|
|
function GetLayer: TMapLayer; override;
|
|
procedure FixOrder(APrevIndex, AIndex: Integer); override;
|
|
end;
|
|
|
|
{ TMapCenter }
|
|
|
|
TMapCenter = class(TPersistent)
|
|
private
|
|
FLatitude: Double;
|
|
FLongitude: Double;
|
|
FView: TMapView;
|
|
function GetLatLonInDMS: Boolean;
|
|
procedure SetLatitude(AValue: Double);
|
|
procedure SetLongitude(AValue: Double);
|
|
procedure SetViewCenter;
|
|
protected
|
|
function GetOwner: TPersistent; override;
|
|
public
|
|
constructor Create(AView: TMapView);
|
|
property LatLonInDMS: Boolean read GetLatLonInDMS;
|
|
published
|
|
property Longitude: Double read FLongitude write SetLongitude;
|
|
property Latitude: Double read FLatitude write SetLatitude;
|
|
end;
|
|
|
|
{ TMapPoint }
|
|
|
|
TMapPoint = class(TMapItem)
|
|
private
|
|
FDateTime: TDateTime;
|
|
FElevation: Double;
|
|
FLatitude: Double;
|
|
FLongitude: Double;
|
|
FPoint: TGPSPoint;
|
|
function GetLatLonInDMS: Boolean;
|
|
function GetToScreen: TPoint;
|
|
function IsDateTimeStored: Boolean;
|
|
function IsElevationStored: Boolean;
|
|
procedure SetDateTime(AValue: TDateTime);
|
|
procedure SetElevation(AValue: Double);
|
|
procedure SetLatitude(AValue: Double);
|
|
procedure SetLongitude(AValue: Double);
|
|
function GetGPSObj: TGPSObj; override;
|
|
protected
|
|
procedure ItemChanged; override;
|
|
function CreatePoint: TGPSPoint; virtual;
|
|
procedure DestroyPoint; virtual;
|
|
public
|
|
constructor Create(ACollection: TCollection); override;
|
|
destructor Destroy; override;
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
function HitTest(constref Area: TRealArea): TMapObjectList; override;
|
|
property LatLonInDMS: Boolean read GetLatLonInDMS;
|
|
property ToScreen: TPoint read GetToScreen;
|
|
published
|
|
property Longitude: Double read FLongitude write SetLongitude;
|
|
property Latitude: Double read FLatitude write SetLatitude;
|
|
property Elevation: Double read FElevation write SetElevation stored IsElevationStored;
|
|
property DateTime: TDateTime read FDateTime write SetDateTime stored IsDateTimeStored;
|
|
end;
|
|
|
|
{ TMapTrackPoint }
|
|
|
|
TMapTrackPoint = class(TMapPoint)
|
|
private
|
|
FMark: TSegmentExtraData.TSegmentMark;
|
|
function MarkIsStored: Boolean;
|
|
procedure SetMark(AValue: TSegmentExtraData.TSegmentMark);
|
|
protected
|
|
function GPSTrack: TGPSTrack;
|
|
function CreatePoint: TGPSPoint; override;
|
|
procedure DestroyPoint; override;
|
|
public
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
published
|
|
property Mark: TSegmentExtraData.TSegmentMark read FMark write SetMark stored MarkIsStored;
|
|
end;
|
|
|
|
{ TMapTrackPoints }
|
|
|
|
TMapTrackPoints = class(specialize TMapCollection<TMapTrackPoint, TMapTrack>)
|
|
protected
|
|
function GetLayer: TMapLayer; override;
|
|
procedure FixOrder(APrevIndex, AIndex: Integer); override;
|
|
end;
|
|
|
|
{ TPointOfInterest }
|
|
|
|
TPointOfInterest = class(TMapPoint)
|
|
private
|
|
FImageIndex: TImageIndex;
|
|
FOnDrawPoint: TPointOfInterestDrawEvent;
|
|
procedure SetImageIndex(AValue: TImageIndex);
|
|
procedure SetOnDrawPoint(AValue: TPointOfInterestDrawEvent);
|
|
protected
|
|
procedure DrawPoint(Sender: TObject; AGPSObj: TGPSObj; AArea: TRealArea);
|
|
procedure ItemChanged; override;
|
|
function CreatePoint: TGPSPoint; override;
|
|
procedure DestroyPoint; override;
|
|
public
|
|
constructor Create(ACollection: TCollection); override;
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
published
|
|
property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
|
|
property OnDrawPoint: TPointOfInterestDrawEvent read FOnDrawPoint write SetOnDrawPoint;
|
|
end;
|
|
|
|
{ TPointsOfInterest }
|
|
|
|
TPointsOfInterest = class(specialize TMapCollection<TPointOfInterest, TMapLayer>)
|
|
protected
|
|
function GetLayer: TMapLayer; override;
|
|
end;
|
|
|
|
{ TMapPolygon }
|
|
|
|
TMapPolygon = class(TMapItem)
|
|
private
|
|
FPoints: TGPSPointList;
|
|
published
|
|
property Points: TGPSPointList read FPoints;
|
|
end;
|
|
|
|
{ TMapTrack }
|
|
|
|
TMapTrack = class(TMapItem)
|
|
private
|
|
FConnectColor: TColor;
|
|
FConnectWidth: Double;
|
|
FLineColor: TColor;
|
|
FLineWidth: Double;
|
|
FPoints: TMapTrackPoints;
|
|
FTrack: TGPSTrack;
|
|
FOnDrawTrack: TMapTrackDrawEvent;
|
|
function GetGPSObj: TGPSObj; override;
|
|
function GetPoints: TMapTrackPoints;
|
|
procedure SetConnectColor(AValue: TColor);
|
|
procedure SetConnectWidth(AValue: Double);
|
|
procedure SetLineColor(AValue: TColor);
|
|
procedure SetLineWidth(AValue: Double);
|
|
procedure SetOnDrawTrack(AValue: TMapTrackDrawEvent);
|
|
procedure SetPoints(AValue: TMapTrackPoints);
|
|
protected
|
|
procedure DrawTrack(Sender: TObject; AGPSObj: TGPSObj; AArea: TRealArea);
|
|
public
|
|
constructor Create(ACollection: TCollection); override;
|
|
destructor Destroy; override;
|
|
procedure ItemChanged; override;
|
|
function HitTest(constref Area: TRealArea): TMapObjectList; override;
|
|
published
|
|
//property DateTime: TDateTime read GetDateTime write FDateTime;
|
|
property LineColor: TColor read FLineColor write SetLineColor default clDefault;
|
|
property LineWidth: Double read FLineWidth write SetLineWidth;
|
|
property ConnectColor: TColor read FConnectColor write SetConnectColor default clNone;
|
|
property ConnectWidth: Double read FConnectWidth write SetConnectWidth;
|
|
property Points: TMapTrackPoints read GetPoints write SetPoints;
|
|
property OnDrawTrack: TMapTrackDrawEvent read FOnDrawTrack write SetOnDrawTrack;
|
|
end;
|
|
|
|
{ TMapTracks }
|
|
|
|
TMapTracks = class(specialize TMapCollection<TMapTrack, TMapLayer>)
|
|
protected
|
|
function GetLayer: TMapLayer; override;
|
|
end;
|
|
|
|
{ TMapView }
|
|
|
|
TMapView = class(TCustomControl)
|
|
private
|
|
FCacheLocation: TCacheLocation;
|
|
FCachePath, FCacheFullPath: String;
|
|
FCenter: TMapCenter;
|
|
FDownloadEngine: TMvCustomDownloadEngine;
|
|
FBuiltinDownloadEngine: TMvCustomDownloadEngine;
|
|
FEngine: TMapViewerEngine;
|
|
FBuiltinDrawingEngine: TMvCustomDrawingEngine;
|
|
FDrawingEngine: TMvCustomDrawingEngine;
|
|
FDrawPreviewTiles: boolean;
|
|
FActive: boolean;
|
|
FLayers: TMapLayers;
|
|
FGPSItems: array [0..9] of TGPSObjectList;
|
|
FOptions: TMapViewOptions;
|
|
FPOIImage: TBitmap;
|
|
FPOITextBgColor: TColor;
|
|
FOnDrawGpsPoint: TDrawGpsPointEvent;
|
|
FDebugTiles: Boolean;
|
|
FDefaultTrackColor: TColor;
|
|
FDefaultTrackWidth: Integer;
|
|
FFont: TFont;
|
|
FPOIImages: TCustomImageList;
|
|
FPOIImagesWidth: Integer;
|
|
FCacheOnDisk: Boolean;
|
|
FZoomMax: Integer;
|
|
FZoomMin: Integer;
|
|
procedure CallAsyncInvalidate;
|
|
procedure DoAsyncInvalidate({%H-}Data: PtrInt);
|
|
procedure DrawObjects(const {%H-}TileId: TTileId; aLeft, aTop, aRight,aBottom: integer);
|
|
procedure DrawGpsObj(const {%H-}Area: TRealArea; AObj: TGPSObj);
|
|
function GetCacheMaxAge: Integer;
|
|
function GetCacheOnDisk: boolean;
|
|
function GetCenter: TRealPoint;
|
|
function GetCyclic: Boolean;
|
|
function GetDownloadEngine: TMvCustomDownloadEngine;
|
|
function GetDrawingEngine: TMvCustomDrawingEngine;
|
|
function GetDrawPreviewTiles: Boolean;
|
|
function GetGPSItems: TGPSObjectList;
|
|
function GetGPSLayer(Layer: Integer): TGPSObjectList;
|
|
function GetInactiveColor: TColor;
|
|
function GetLayers: TMapLayers;
|
|
function GetMapProvider: String;
|
|
function GetOnCenterMove: TNotifyEvent;
|
|
function GetOnChange: TNotifyEvent;
|
|
function GetOnZoomChange: TNotifyEvent;
|
|
function GetUseThreads: boolean;
|
|
function GetZoom: integer;
|
|
function GetZoomToCursor: Boolean;
|
|
function IsCacheMaxAgeStored: Boolean;
|
|
function IsCachePathStored: Boolean;
|
|
function IsFontStored: Boolean;
|
|
function IsLayersStored: Boolean;
|
|
procedure SetActive(AValue: boolean);
|
|
procedure SetCacheLocation(AValue: TCacheLocation);
|
|
procedure SetCacheMaxAge(AValue: Integer);
|
|
procedure SetCacheOnDisk(AValue: boolean);
|
|
procedure SetCachePath(AValue: String);
|
|
procedure SetCenter(AValue: TRealPoint);
|
|
procedure SetCyclic(AValue: Boolean);
|
|
procedure SetDebugTiles(AValue: Boolean);
|
|
procedure SetDefaultTrackColor(AValue: TColor);
|
|
procedure SetDefaultTrackWidth(AValue: Integer);
|
|
procedure SetDownloadEngine(AValue: TMvCustomDownloadEngine);
|
|
procedure SetDrawingEngine(AValue: TMvCustomDrawingEngine);
|
|
procedure SetDrawPreviewTiles(AValue: Boolean);
|
|
procedure SetFont(AValue: TFont);
|
|
procedure SetInactiveColor(AValue: TColor);
|
|
procedure SetLayers(const ALayers: TMapLayers);
|
|
procedure SetMapProvider(AValue: String);
|
|
procedure SetOnCenterMove(AValue: TNotifyEvent);
|
|
procedure SetOnChange(AValue: TNotifyEvent);
|
|
procedure SetOnZoomChange(AValue: TNotifyEvent);
|
|
procedure SetOptions(AValue: TMapViewOptions);
|
|
procedure SetPOIImage(const AValue: TBitmap);
|
|
procedure SetPOIImages(const AValue: TCustomImageList);
|
|
procedure SetPOIImagesWidth(AValue: Integer);
|
|
procedure SetPOITextBgColor(AValue: TColor);
|
|
procedure SetUseThreads(AValue: boolean);
|
|
procedure SetZoom(AValue: integer);
|
|
procedure SetZoomMax(AValue: Integer);
|
|
procedure SetZoomMin(AValue: Integer);
|
|
procedure SetZoomToCursor(AValue: Boolean);
|
|
procedure UpdateFont(Sender: TObject);
|
|
procedure UpdateImage(Sender: TObject);
|
|
|
|
protected
|
|
AsyncInvalidate : boolean;
|
|
procedure ActivateEngine;
|
|
procedure DblClick; override;
|
|
procedure DoDrawStretchedTile(const TileId: TTileID; X, Y: Integer; TileImg: TPictureCacheItem; const R: TRect);
|
|
procedure DoDrawTile(const TileId: TTileId; X,Y: integer; TileImg: TPictureCacheItem);
|
|
procedure DoDrawTileInfo(const {%H-}TileID: TTileID; X,Y: Integer);
|
|
procedure DoEraseBackground(const R: TRect);
|
|
procedure DoTileDownloaded(const TileId: TTileId);
|
|
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 Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure Paint; override;
|
|
procedure OnGPSItemsModified(Sender: TObject; objs: TGPSObjList;
|
|
Adding: boolean);
|
|
|
|
function CreateLayers: TMapLayers; virtual;
|
|
procedure UpdateLayers;
|
|
|
|
procedure ChangeCachePath(AOldLoc: TCacheLocation; ANewPath: String);
|
|
class function CacheDirectory(ALoc: TCacheLocation; ACustomPath: String): String;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function CyclicPointOf(APoint: TPoint; ARefX: LongInt; Eastwards: Boolean = True): TPoint;
|
|
function CyclicPointsOf(APoint: TPoint): TPointArray;
|
|
function TrackLineColor(AColor: TColor; ExtraData: TObject): TColor;
|
|
function TrackLineWidth(AWidth: Double; ExtraData: TObject): Integer;
|
|
procedure DrawPointOfInterest(const {%H-}Area: TRealArea; APt: TGPSPointOfInterest);
|
|
procedure DrawPt(const {%H-}Area: TRealArea; APt: TGPSPoint);
|
|
procedure DrawTrack(const {%H-}Area: TRealArea; trk: TGPSTrack);
|
|
procedure DrawArea(const {%H-}Area: TRealArea; ar: TGPSArea);
|
|
procedure ClearBuffer;
|
|
procedure GetMapProviders(lstProviders: TStrings);
|
|
function GetVisibleArea: TRealArea;
|
|
function LatLonToScreen(aPt: TRealPoint): TPoint;
|
|
function LatLonToScreen(Lat, Lon: Double): TPoint; overload;
|
|
function LonLatToScreen(aPt: TRealPoint): TPoint; deprecated 'Use LatLonToScreen';
|
|
function ObjsAtScreenPt(X, Y: Integer; ATolerance: Integer = -1): TGPSObjarray;
|
|
procedure SaveToFile(AClass: TRasterImageClass; const AFileName: String);
|
|
function SaveToImage(AClass: TRasterImageClass): TRasterImage;
|
|
procedure SaveToStream(AClass: TRasterImageClass; AStream: TStream);
|
|
function ScreenToLatLon(aPt: TPoint): TRealPoint;
|
|
function ScreenToLonLat(aPt: TPoint): TRealPoint; deprecated 'Use ScreenToLatLon';
|
|
procedure CenterOnObj(obj: TGPSObj);
|
|
procedure Redraw; inline;
|
|
procedure ZoomOnArea(const aArea: TRealArea);
|
|
procedure ZoomOnObj(obj: TGPSObj);
|
|
procedure WaitEndOfRendering;
|
|
procedure StartDragging(X, Y: Integer);
|
|
procedure EndDragging(X, Y: Integer);
|
|
procedure AbortDragging;
|
|
|
|
property Center: TRealPoint read GetCenter write SetCenter;
|
|
property Engine: TMapViewerEngine read FEngine;
|
|
property GPSItems: TGPSObjectList read GetGPSItems;
|
|
property GPSLayer[L: Integer]: TGPSObjectList read GetGPSLayer;
|
|
published
|
|
property Active: boolean read FActive write SetActive default false;
|
|
property Align;
|
|
property CacheOnDisk: boolean read GetCacheOnDisk write SetCacheOnDisk default true;
|
|
property CacheLocation: TCacheLocation read FCacheLocation write SetCacheLocation default clProfile;
|
|
property CachePath: String read FCachePath write SetCachePath stored IsCachePathStored;
|
|
property CacheFullPath: String read FCacheFullPath stored False;
|
|
property CacheMaxAge: Integer read GetCacheMaxAge write SetCacheMaxAge stored IsCacheMaxAgeStored;
|
|
property Cyclic: Boolean read GetCyclic write SetCyclic default false;
|
|
property DebugTiles: Boolean read FDebugTiles write SetDebugTiles default false;
|
|
property DefaultTrackColor: TColor read FDefaultTrackColor write SetDefaultTrackColor default clRed;
|
|
property DefaultTrackWidth: Integer read FDefaultTrackWidth write SetDefaultTrackWidth default 1;
|
|
property DownloadEngine: TMvCustomDownloadEngine read GetDownloadEngine write SetDownloadEngine;
|
|
property DrawingEngine: TMvCustomDrawingEngine read GetDrawingEngine write SetDrawingEngine;
|
|
property DrawPreviewTiles: Boolean read GetDrawPreviewTiles write SetDrawPreviewTiles default true;
|
|
property Options: TMapViewOptions read FOptions write SetOptions default DefaultMapViewOptions;
|
|
property Layers: TMapLayers read GetLayers write SetLayers stored IsLayersStored;
|
|
property Font: TFont read FFont write SetFont stored IsFontStored;
|
|
property Height default 150;
|
|
property InactiveColor: TColor read GetInactiveColor write SetInactiveColor default clWhite;
|
|
property MapProvider: String read GetMapProvider write SetMapProvider;
|
|
property MapCenter: TMapCenter read FCenter write FCenter;
|
|
property POIImage: TBitmap read FPOIImage write SetPOIImage;
|
|
property POIImages: TCustomImageList read FPOIImages write SetPOIImages;
|
|
property POIImagesWidth: Integer read FPOIImagesWidth write SetPOIImagesWidth default 0;
|
|
property POITextBgColor: TColor read FPOITextBgColor write SetPOITextBgColor default clNone;
|
|
property PopupMenu;
|
|
property UseThreads: boolean read GetUseThreads write SetUseThreads default false;
|
|
property Width default 150;
|
|
property Zoom: integer read GetZoom write SetZoom default 1;
|
|
property ZoomMax: Integer read FZoomMax write SetZoomMax default 19;
|
|
property ZoomMin: Integer read FZoomMin write SetZoomMin default 1;
|
|
property ZoomToCursor: Boolean read GetZoomToCursor write SetZoomToCursor default True;
|
|
property OnCenterMove: TNotifyEvent read GetOnCenterMove write SetOnCenterMove;
|
|
property OnZoomChange: TNotifyEvent read GetOnZoomChange write SetOnZoomChange;
|
|
property OnChange: TNotifyEvent read GetOnChange write SetOnChange;
|
|
property OnDrawGpsPoint: TDrawGpsPointEvent read FOnDrawGpsPoint write FOnDrawGpsPoint;
|
|
property OnMouseDown;
|
|
property OnMouseEnter;
|
|
property OnMouseLeave;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
end;
|
|
|
|
{ TGPSTileLayerBase }
|
|
|
|
TGPSTileLayerBase = class(TGPSObj)
|
|
private
|
|
FDrawMode: TItemDrawMode;
|
|
FMapProvider: String;
|
|
FOpacity: Single;
|
|
FParentView: TMapView;
|
|
FEngine: TMapViewerEngine;
|
|
FParentViewChanged: Boolean;
|
|
function GetMapProvider: String;
|
|
function GetUseThreads: Boolean;
|
|
procedure DoTileDownloaded(const TileId: TTileId);
|
|
procedure DoDrawTile(const TileId: TTileId; X, Y: Integer; TileImg: TPictureCacheItem);
|
|
procedure SetDrawMode(AValue: TItemDrawMode);
|
|
procedure SetMapProvider(AValue: String);
|
|
procedure SetOpacity(AValue: Single);
|
|
procedure SetUseThreads(AValue: Boolean);
|
|
procedure SetParentView(AValue: TMapView);
|
|
protected
|
|
procedure TileDownloaded(const TileId: TTileId); virtual;
|
|
procedure DrawTile(const TileId: TTileId; X, Y: Integer; TileImg: TPictureCacheItem); virtual; abstract;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure GetArea(out Area: TRealArea); override;
|
|
procedure Draw(AView: TObject; Area: TRealArea); override;
|
|
procedure ParentViewChanged; virtual;
|
|
|
|
property MapProvider: String read GetMapProvider write SetMapProvider;
|
|
property UseThreads: Boolean read GetUseThreads write SetUseThreads;
|
|
property DrawMode: TItemDrawMode read FDrawMode write SetDrawMode;
|
|
property Opacity: Single read FOpacity write SetOpacity;
|
|
end;
|
|
|
|
{ TGPSTileLayer }
|
|
|
|
TGPSTileLayer = class(TGPSTileLayerBase)
|
|
protected
|
|
procedure DrawTile(const TileId: TTileId; X, Y: Integer;
|
|
TileImg: TPictureCacheItem); override;
|
|
public
|
|
procedure Draw(AView: TObject; Area: TRealArea); override;
|
|
procedure TileDownloaded(const TileId: TTileId); override;
|
|
end;
|
|
|
|
{ TGPSTileLayerLabels }
|
|
|
|
TGPSTileLayerLabels = class(TGPSTileLayerBase)
|
|
protected
|
|
procedure DrawTile(const TileId: TTileId; X, Y: Integer;
|
|
TileImg: TPictureCacheItem); override;
|
|
public
|
|
procedure Draw(AView: TObject; Area: TRealArea); override;
|
|
end;
|
|
|
|
{ TGPSComboLayer }
|
|
|
|
TGPSComboLayer = class(TGPSObjectList)
|
|
FTileLayer: TGPSTileLayer;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure GetArea(out Area: TRealArea); override;
|
|
procedure Draw(AView: TObject; Area: TRealArea); override;
|
|
property TileLayer: TGPSTileLayer read FTileLayer;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
GraphMath, FileUtil, LazLoggerBase, Types, Math,
|
|
mvJobQueue, mvDLEFpc,
|
|
{$IFDEF MSWINDOWS}
|
|
mvDLEWin,
|
|
{$ENDIF}
|
|
mvDE_IntfGraphics;
|
|
|
|
const
|
|
RANGE_Z = (High(Integer) div 4);
|
|
BASE_Z_LAYER = Low(Integer);
|
|
BASE_Z_AREA = Low(Integer);
|
|
BASE_Z_TRACK = BASE_Z_AREA + RANGE_Z;
|
|
BASE_Z_POI = BASE_Z_TRACK + RANGE_Z;
|
|
|
|
_TILELAYERS_ID_ = -42; // OwnerIDs of the tile layers
|
|
|
|
{ Converts a length given in millimeters to screen pixels }
|
|
function mmToPx(AValue: Double): Integer;
|
|
begin
|
|
Result := round(AValue / 25.4 * ScreenInfo.PixelsPerInchX);
|
|
end;
|
|
|
|
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;
|
|
|
|
{ TMapObjectList }
|
|
|
|
constructor TMapObjectList.Create(ASingleObj: TObject);
|
|
begin
|
|
inherited Create(False);
|
|
if Assigned(ASingleObj) then
|
|
Add(ASingleObj);
|
|
end;
|
|
|
|
constructor TMapObjectList.Create(AList: TMapObjectList);
|
|
begin
|
|
inherited Create(False);
|
|
if Assigned(AList) then
|
|
AddList(AList);
|
|
end;
|
|
|
|
class function TMapObjectList.AddListToResult(AList, AResult: TMapObjectList): TMapObjectList;
|
|
begin
|
|
Result := AResult;
|
|
if Assigned(AList) then
|
|
if Assigned(AResult) then
|
|
begin
|
|
Result.AddList(AList);
|
|
AList.Free;
|
|
end
|
|
else
|
|
Result := AList;
|
|
end;
|
|
|
|
{ TMapTrackPoint }
|
|
|
|
function TMapTrackPoint.CreatePoint: TGPSPoint;
|
|
var
|
|
Trk: TGPSTrack;
|
|
begin
|
|
Result := inherited CreatePoint;
|
|
Trk := GPSTrack;
|
|
if Assigned(Trk)
|
|
then Trk.Points.Add(Result);
|
|
end;
|
|
|
|
procedure TMapTrackPoint.DestroyPoint;
|
|
var
|
|
Trk: TGPSTrack;
|
|
begin
|
|
Trk := GPSTrack;
|
|
if Assigned(Trk) and Assigned(FPoint)
|
|
then Trk.Points.Remove(FPoint);
|
|
end;
|
|
|
|
procedure TMapTrackPoint.AssignTo(Dest: TPersistent);
|
|
begin
|
|
inherited AssignTo(Dest);
|
|
if Dest is TMapTrackPoint then
|
|
TMapTrackPoint(Dest).Mark := Self.Mark;
|
|
end;
|
|
|
|
function TMapTrackPoint.MarkIsStored: Boolean;
|
|
begin
|
|
Result := FMark <> smNone;
|
|
end;
|
|
|
|
procedure TMapTrackPoint.SetMark(AValue: TSegmentExtraData.TSegmentMark);
|
|
begin
|
|
if FMark = AValue then
|
|
Exit;
|
|
FMark := AValue;
|
|
if (AValue = smNone) then
|
|
FPoint.ExtraData.Free
|
|
else
|
|
begin
|
|
if not Assigned(FPoint.ExtraData)
|
|
then FPoint.ExtraData := TSegmentExtraData.Create(AValue)
|
|
else TSegmentExtraData(FPoint.ExtraData).Mark := AValue;
|
|
end;
|
|
end;
|
|
|
|
function TMapTrackPoint.GPSTrack: TGPSTrack;
|
|
begin
|
|
Result := Nil;
|
|
if Assigned(Collection) and (Collection is TMapTrackPoints) then
|
|
with (Collection as TMapTrackPoints) do
|
|
if Assigned(MCOwner) and (MCOwner is TMapTrack) then
|
|
Result := (MCOwner as TMapTrack).FTrack;
|
|
end;
|
|
|
|
{ TMapCollectionBase }
|
|
|
|
function TMapCollectionBase.GetView: TMapView;
|
|
begin
|
|
if Assigned(Layer)
|
|
then Result := Layer.View
|
|
else Result := Nil;
|
|
end;
|
|
|
|
function TMapCollectionBase.GetLayer: TMapLayer;
|
|
begin
|
|
Result := Nil;
|
|
end;
|
|
|
|
procedure TMapCollectionBase.FixOrder(APrevIndex, AIndex: Integer);
|
|
var
|
|
I, T, B: Integer;
|
|
begin
|
|
T := Min(APrevIndex, AIndex);
|
|
B := Max(APrevIndex, AIndex);
|
|
if APrevIndex < 0 then
|
|
begin
|
|
T := AIndex;
|
|
B := Pred(Count);
|
|
end;
|
|
for I := T to B do
|
|
Layer.ComboLayer.ChangeZOrder(TMapItem(Items[I]).GPSObj, I + FBaseZ);
|
|
end;
|
|
|
|
procedure TMapCollectionBase.Update(Item: TCollectionItem);
|
|
begin
|
|
inherited Update(Item);
|
|
if Assigned(View) then
|
|
View.Invalidate;
|
|
end;
|
|
|
|
{ TMapTrackPoints }
|
|
|
|
function TMapTrackPoints.GetLayer: TMapLayer;
|
|
begin
|
|
Result := MCOwner.Layer;
|
|
end;
|
|
|
|
procedure TMapTrackPoints.FixOrder(APrevIndex, AIndex: Integer);
|
|
var
|
|
I, T, B: Integer;
|
|
Trk: TGPSTrack;
|
|
O: TGPSPoint;
|
|
begin
|
|
if Assigned(MCOwner) and (MCOwner is TMapTrack)
|
|
then Trk := (MCOwner as TMapTrack).FTrack
|
|
else Exit;
|
|
T := Min(APrevIndex, AIndex);
|
|
B := Max(APrevIndex, AIndex);
|
|
if APrevIndex < 0 then
|
|
begin
|
|
T := AIndex;
|
|
B := Pred(Count);
|
|
end;
|
|
for I := T to B do
|
|
begin
|
|
O := TGPSPoint(TMapItem(Items[I]).GPSObj);
|
|
if Trk.Points.Extract(O) <> Nil then
|
|
Trk.Points.Insert(I, O);
|
|
end;
|
|
end;
|
|
|
|
{ TMapTrack }
|
|
|
|
procedure TMapTrack.SetOnDrawTrack(AValue: TMapTrackDrawEvent);
|
|
begin
|
|
if CompareMem(@FOnDrawTrack, @AValue, SizeOf(TMethod)) then
|
|
Exit;
|
|
FOnDrawTrack := AValue;
|
|
if Assigned(FOnDrawTrack)
|
|
then FTrack.OnDrawObj := @DrawTrack
|
|
else FTrack.OnDrawObj := Nil;
|
|
ItemChanged;
|
|
end;
|
|
|
|
function TMapTrack.GetGPSObj: TGPSObj;
|
|
begin
|
|
Result := FTrack;
|
|
end;
|
|
|
|
function TMapTrack.GetPoints: TMapTrackPoints;
|
|
begin
|
|
Result := FPoints;
|
|
end;
|
|
|
|
procedure TMapTrack.SetConnectColor(AValue: TColor);
|
|
begin
|
|
if FConnectColor=AValue then Exit;
|
|
FConnectColor:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapTrack.SetConnectWidth(AValue: Double);
|
|
begin
|
|
if FConnectWidth=AValue then Exit;
|
|
FConnectWidth:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapTrack.SetLineColor(AValue: TColor);
|
|
begin
|
|
if FLineColor = AValue then Exit;
|
|
FLineColor := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapTrack.SetLineWidth(AValue: Double);
|
|
begin
|
|
if FLineWidth = AValue then Exit;
|
|
FLineWidth := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapTrack.SetPoints(AValue: TMapTrackPoints);
|
|
begin
|
|
FPoints.Assign(AValue);
|
|
end;
|
|
|
|
procedure TMapTrack.DrawTrack(Sender: TObject; AGPSObj: TGPSObj;
|
|
AArea: TRealArea);
|
|
begin
|
|
if Assigned(FOnDrawTrack) then
|
|
FOnDrawTrack(Sender, (Collection as TMapTracks).GetView.DrawingEngine, Self);
|
|
end;
|
|
|
|
constructor TMapTrack.Create(ACollection: TCollection);
|
|
begin
|
|
inherited Create(ACollection);
|
|
FLineColor := clDefault;
|
|
FLineWidth := -1;
|
|
FConnectColor := clNone;
|
|
FConnectWidth := -1;
|
|
FVisible := True;
|
|
FPoints := TMapTrackPoints.Create(Self, 0);
|
|
FTrack := TGPSTrack.Create;
|
|
Layer.ComboLayer.Add(FTrack, Pred(_TILELAYERS_ID_), Self.Index + BASE_Z_TRACK);
|
|
end;
|
|
|
|
destructor TMapTrack.Destroy;
|
|
begin
|
|
FPoints.Free;
|
|
if Assigned(FTrack) then
|
|
Layer.ComboLayer.Delete(FTrack);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMapTrack.ItemChanged;
|
|
begin
|
|
FTrack.Name := Caption;
|
|
FTrack.LineColor := LineColor;
|
|
FTrack.LineWidth := LineWidth;
|
|
FTrack.ConnectColor := ConnectColor;
|
|
FTrack.ConnectWidth := ConnectWidth;
|
|
FTrack.Visible := Visible;
|
|
Changed(False);
|
|
end;
|
|
|
|
function TMapTrack.HitTest(constref Area: TRealArea): TMapObjectList;
|
|
begin
|
|
Result := Points.HitTest(Area);
|
|
if Assigned(Result) then
|
|
Result.Add(Self);
|
|
end;
|
|
|
|
{ TMapTracks }
|
|
|
|
function TMapTracks.GetLayer: TMapLayer;
|
|
begin
|
|
Result := MCOwner;
|
|
end;
|
|
|
|
{ TMapItem }
|
|
|
|
function TMapItem.GetView: TMapView;
|
|
begin
|
|
Result := Layer.View;
|
|
end;
|
|
|
|
function TMapItem.GetLayer: TMapLayer;
|
|
begin
|
|
if Assigned(Collection)
|
|
then Result := (Collection as TMapCollectionBase).Layer
|
|
else Result := Nil;
|
|
end;
|
|
|
|
procedure TMapItem.SetCaption(AValue: TCaption);
|
|
begin
|
|
if FCaption=AValue then Exit;
|
|
FCaption:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapItem.SetVisible(AValue: Boolean);
|
|
begin
|
|
if FVisible=AValue then Exit;
|
|
FVisible:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
function TMapItem.GetDisplayName: string;
|
|
begin
|
|
if FCaption <> ''
|
|
then Result := FCaption
|
|
else Result := ClassName;
|
|
if not FVisible
|
|
then Result := Result + ' (Invisible)';
|
|
end;
|
|
|
|
procedure TMapItem.SetIndex(Value: Integer);
|
|
var
|
|
PrevIndex: Integer;
|
|
begin
|
|
PrevIndex := Index;
|
|
inherited SetIndex(Value);
|
|
if (PrevIndex <> Index) and Assigned(Collection) then
|
|
TMapCollectionBase(Collection).FixOrder(PrevIndex, Index);
|
|
end;
|
|
|
|
{ TMapCollection }
|
|
|
|
function TMapCollection.GetItems(Index: Integer): TItemClass;
|
|
begin
|
|
Result := TItemClass(inherited GetItem(Index));
|
|
end;
|
|
|
|
function TMapCollection.GetFirst: TItemClass;
|
|
begin
|
|
Result := GetItems(0);
|
|
end;
|
|
|
|
function TMapCollection.GetLast: TItemClass;
|
|
begin
|
|
Result := GetItems(Pred(Count));
|
|
end;
|
|
|
|
procedure TMapCollection.SetItems(Index: Integer; AValue: TItemClass);
|
|
begin
|
|
(GetItems(Index) as TPersistent).Assign(AValue);
|
|
end;
|
|
|
|
function TMapCollection.HitTest(constref Area: TRealArea): TMapObjectList;
|
|
var
|
|
I: TCollectionItem;
|
|
begin
|
|
Result := Nil;
|
|
for I in Self do
|
|
Result := TMapObjectList.AddListToResult(TItemClass(I).HitTest(Area), Result);
|
|
if Assigned(Result) then
|
|
Result.Add(Self);
|
|
end;
|
|
|
|
constructor TMapCollection.Create(AOwner: OT; ABaseZ: Integer);
|
|
begin
|
|
inherited Create(AOwner, TItemClass);
|
|
FMCOwner := AOwner;
|
|
FBaseZ := ABaseZ;
|
|
end;
|
|
|
|
{ TGPSComboLayer }
|
|
|
|
procedure TGPSComboLayer.GetArea(out Area: TRealArea);
|
|
begin
|
|
FTileLayer.GetArea(Area);
|
|
end;
|
|
|
|
constructor TGPSComboLayer.Create;
|
|
begin
|
|
inherited Create;
|
|
FTileLayer := TGPSTileLayer.Create;
|
|
end;
|
|
|
|
destructor TGPSComboLayer.Destroy;
|
|
begin
|
|
FTileLayer.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TGPSComboLayer.Draw(AView: TObject; Area: TRealArea);
|
|
var
|
|
I: Integer;
|
|
Objs: TGPSObjList;
|
|
begin
|
|
inherited Draw(AView, Area);
|
|
FTileLayer.Draw(AView, Area);
|
|
Objs := GetObjectsInArea(Area);
|
|
try
|
|
if Objs.Count > 0 then
|
|
begin
|
|
for I := 0 to Pred(Objs.Count) do
|
|
if Objs[I].Visible then
|
|
Objs[I].Draw(AView, Area)
|
|
end;
|
|
finally
|
|
FreeAndNil(Objs);
|
|
end;
|
|
end;
|
|
|
|
{ TPointsOfInterest }
|
|
|
|
function TPointsOfInterest.GetLayer: TMapLayer;
|
|
begin
|
|
Result := MCOwner;
|
|
end;
|
|
|
|
{ TMapPoint }
|
|
|
|
function TMapPoint.IsDateTimeStored: Boolean;
|
|
begin
|
|
Result := not (FDateTime = NO_DATE);
|
|
end;
|
|
|
|
function TMapPoint.IsElevationStored: Boolean;
|
|
begin
|
|
Result := not (FElevation = NO_ELE);
|
|
end;
|
|
|
|
procedure TMapPoint.SetDateTime(AValue: TDateTime);
|
|
begin
|
|
if FDateTime=AValue then Exit;
|
|
FDateTime:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapPoint.SetElevation(AValue: Double);
|
|
begin
|
|
if FElevation=AValue then Exit;
|
|
FElevation:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
function TMapPoint.GetLatLonInDMS: Boolean;
|
|
begin
|
|
Result := Assigned(View) and (mvoLatLonInDMS in View.Options);
|
|
end;
|
|
|
|
function TMapPoint.GetToScreen: TPoint;
|
|
begin
|
|
Result := View.LatLonToScreen(RealPoint(Latitude, Longitude));
|
|
end;
|
|
|
|
procedure TMapPoint.SetLatitude(AValue: Double);
|
|
begin
|
|
if FLatitude = AValue then Exit;
|
|
FLatitude := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapPoint.SetLongitude(AValue: Double);
|
|
begin
|
|
if FLongitude = AValue then Exit;
|
|
FLongitude := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
function TMapPoint.GetGPSObj: TGPSObj;
|
|
begin
|
|
Result := FPoint;
|
|
end;
|
|
|
|
procedure TMapPoint.ItemChanged;
|
|
begin
|
|
FPoint.Lon := Longitude;
|
|
FPoint.Lat := Latitude;
|
|
FPoint.Name := Caption;
|
|
FPoint.Visible := Visible;
|
|
FPoint.Elevation := Elevation;
|
|
FPoint.DateTime := DateTime;
|
|
Changed(False);
|
|
end;
|
|
|
|
function TMapPoint.HitTest(constref Area: TRealArea): TMapObjectList;
|
|
var
|
|
BB: TRealArea;
|
|
begin
|
|
Result := Nil;
|
|
if not Visible then
|
|
Exit;
|
|
BB := Self.GPSObj.BoundingBox;
|
|
if Area.ContainsPoint(BB.TopLeft) and Area.ContainsPoint(BB.BottomRight)
|
|
then Result := TMapObjectList.Create(Self);
|
|
end;
|
|
|
|
function TMapPoint.CreatePoint: TGPSPoint;
|
|
begin
|
|
Result := TGPSPoint.Create(FLongitude, FLatitude);
|
|
end;
|
|
|
|
procedure TMapPoint.DestroyPoint;
|
|
begin
|
|
end;
|
|
|
|
constructor TMapPoint.Create(ACollection: TCollection);
|
|
begin
|
|
inherited Create(ACollection);
|
|
FLongitude := View.Center.Lon;
|
|
FLatitude := View.Center.Lat;
|
|
FVisible := True;
|
|
FElevation := NO_ELE;
|
|
FDateTime := NO_DATE;
|
|
FPoint := CreatePoint;
|
|
end;
|
|
|
|
destructor TMapPoint.Destroy;
|
|
begin
|
|
DestroyPoint;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMapPoint.AssignTo(Dest: TPersistent);
|
|
begin
|
|
if Dest is TMapPoint then
|
|
with TMapPoint(Dest) do
|
|
begin
|
|
Latitude := Self.Latitude;
|
|
Longitude := Self.Longitude;
|
|
Elevation := Self.Elevation;
|
|
DateTime := Self.DateTime;
|
|
end
|
|
else
|
|
inherited AssignTo(Dest);
|
|
end;
|
|
|
|
{ TPointOfInterest }
|
|
|
|
procedure TPointOfInterest.SetImageIndex(AValue: TImageIndex);
|
|
begin
|
|
if FImageIndex = AValue then Exit;
|
|
FImageIndex := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TPointOfInterest.SetOnDrawPoint(AValue: TPointOfInterestDrawEvent);
|
|
begin
|
|
if CompareMem(@FOnDrawPoint, @AValue, SizeOf(TMethod)) then
|
|
Exit;
|
|
FOnDrawPoint := AValue;
|
|
if Assigned(FOnDrawPoint)
|
|
then FPoint.OnDrawObj := @DrawPoint
|
|
else FPoint.OnDrawObj := Nil;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TPointOfInterest.DrawPoint(Sender: TObject; AGPSObj: TGPSObj;
|
|
AArea: TRealArea);
|
|
begin
|
|
if Assigned(FOnDrawPoint) then
|
|
FOnDrawPoint(Sender, View.DrawingEngine, Self);
|
|
end;
|
|
|
|
procedure TPointOfInterest.ItemChanged;
|
|
begin
|
|
TGPSPointOfInterest(FPoint).ImageIndex := FImageIndex;
|
|
inherited ItemChanged;
|
|
end;
|
|
|
|
function TPointOfInterest.CreatePoint: TGPSPoint;
|
|
begin
|
|
Result := TGPSPointOfInterest.Create(FLongitude, FLatitude);
|
|
Layer.ComboLayer.Add(Result, Pred(_TILELAYERS_ID_), Self.Index + BASE_Z_POI);
|
|
end;
|
|
|
|
procedure TPointOfInterest.DestroyPoint;
|
|
begin
|
|
if Assigned(FPoint) then
|
|
Layer.ComboLayer.Delete(FPoint);
|
|
end;
|
|
|
|
constructor TPointOfInterest.Create(ACollection: TCollection);
|
|
begin
|
|
inherited Create(ACollection);
|
|
FImageIndex := -1;
|
|
end;
|
|
|
|
procedure TPointOfInterest.AssignTo(Dest: TPersistent);
|
|
begin
|
|
inherited AssignTo(Dest);
|
|
if Dest is TPointOfInterest then
|
|
TPointOfInterest(Dest).ImageIndex := Self.ImageIndex;
|
|
end;
|
|
|
|
{ TMapCenter }
|
|
|
|
procedure TMapCenter.SetLongitude(AValue: Double);
|
|
begin
|
|
if FLongitude = AValue then Exit;
|
|
FLongitude := AValue;
|
|
SetViewCenter;
|
|
end;
|
|
|
|
procedure TMapCenter.SetLatitude(AValue: Double);
|
|
begin
|
|
if FLatitude = AValue then Exit;
|
|
FLatitude := AValue;
|
|
SetViewCenter;
|
|
end;
|
|
|
|
function TMapCenter.GetLatLonInDMS: Boolean;
|
|
begin
|
|
Result := Assigned(FView) and (mvoLatLonInDMS in FView.Options);
|
|
end;
|
|
|
|
procedure TMapCenter.SetViewCenter;
|
|
var
|
|
R: TRealPoint;
|
|
begin
|
|
R.Init(FLongitude, FLatitude);
|
|
FView.SetCenter(R);
|
|
end;
|
|
|
|
function TMapCenter.GetOwner: TPersistent;
|
|
begin
|
|
Result := FView;
|
|
end;
|
|
|
|
constructor TMapCenter.Create(AView: TMapView);
|
|
begin
|
|
FView := AView;
|
|
end;
|
|
|
|
{ TMapLayer }
|
|
|
|
//function TMapLayer.GetMapView: TMapView;
|
|
//begin
|
|
// if Collection is TMapLayers
|
|
// then Result := (Collection as TMapLayers).MCOwner //MapView
|
|
// else Result := Nil;
|
|
//end;
|
|
|
|
function TMapLayer.GetPointsOfInterest: TPointsOfInterest;
|
|
begin
|
|
Result := FPointsOfInterest;
|
|
end;
|
|
|
|
function TMapLayer.GetTracks: TMapTracks;
|
|
begin
|
|
Result := FTracks;
|
|
end;
|
|
|
|
function TMapLayer.GetGPSObj: TGPSObj;
|
|
begin
|
|
Result := FComboLayer;
|
|
end;
|
|
|
|
function TMapLayer.GetView: TMapView;
|
|
begin
|
|
if (Collection is TMapLayers)
|
|
then Result := (Collection as TMapLayers).View
|
|
else Result := Nil;
|
|
end;
|
|
|
|
function TMapLayer.GetLayer: TMapLayer;
|
|
begin
|
|
Result := Self;
|
|
end;
|
|
|
|
function TMapLayer.GetMapProvider: String;
|
|
begin
|
|
Result := ComboLayer.TileLayer.MapProvider
|
|
end;
|
|
|
|
function TMapLayer.GetUseThreads: Boolean;
|
|
begin
|
|
Result := FUseThreads;
|
|
end;
|
|
|
|
procedure TMapLayer.SetDrawMode(AValue: TItemDrawMode);
|
|
begin
|
|
if FDrawMode=AValue then Exit;
|
|
FDrawMode:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapLayer.SetMapProvider(AValue: String);
|
|
var
|
|
P: TMapProvider;
|
|
LPS, MPS: String;
|
|
begin
|
|
if FMapProvider = AValue then
|
|
Exit;
|
|
// Check compat. of provider projection type against the base provider.
|
|
if Assigned(View) then
|
|
begin
|
|
P := View.Engine.MapProviderByName(AValue);
|
|
if Assigned(P) and (View.Engine.MapProjectionType <> P.ProjectionType) then
|
|
begin
|
|
WriteStr(LPS, View.Engine.MapProjectionType);
|
|
WriteStr(MPS, P.ProjectionType);
|
|
raise EArgumentException.CreateFmt(
|
|
'%s has different projection type (%s) from the base map (%s).',
|
|
[AValue, LPS, MPS]);
|
|
end;
|
|
end;
|
|
FMapProvider := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapLayer.SetOpacity(AValue: Single);
|
|
begin
|
|
AValue := EnsureRange(AValue, 0.0, 1.0);
|
|
if FOpacity = AValue then
|
|
Exit;
|
|
FOpacity:=AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapLayer.SetPointsOfInterest(AValue: TPointsOfInterest);
|
|
begin
|
|
FPointsOfInterest.Assign(AValue);
|
|
end;
|
|
|
|
procedure TMapLayer.SetTracks(AValue: TMapTracks);
|
|
begin
|
|
FTracks.Assign(AValue);
|
|
end;
|
|
|
|
procedure TMapLayer.SetUseThreads(AValue: Boolean);
|
|
begin
|
|
if FUseThreads = AValue then
|
|
Exit;
|
|
FUseThreads := AValue;
|
|
ItemChanged;
|
|
end;
|
|
|
|
procedure TMapLayer.ItemChanged;
|
|
begin
|
|
if Assigned(FComboLayer) then
|
|
begin
|
|
FComboLayer.TileLayer.MapProvider := FMapProvider;
|
|
FComboLayer.TileLayer.UseThreads := FUseThreads;
|
|
FComboLayer.TileLayer.DrawMode := FDrawMode;
|
|
FComboLayer.TileLayer.Opacity := FOpacity;
|
|
FComboLayer.Visible := FVisible;
|
|
end;
|
|
Changed(False);
|
|
end;
|
|
|
|
constructor TMapLayer.Create(ACollection: TCollection);
|
|
begin
|
|
inherited Create(ACollection);
|
|
FUseThreads := True;
|
|
FDrawMode := idmUseOpacity;
|
|
FOpacity := 0.25;
|
|
FVisible := True;
|
|
FTag := 0;
|
|
|
|
FPointsOfInterest := TPointsOfInterest.Create(Self, BASE_Z_POI);
|
|
FTracks := TMapTracks.Create(Self, BASE_Z_TRACK);
|
|
FComboLayer := TGPSComboLayer.Create;
|
|
View.GPSItems.Add(FComboLayer, _TILELAYERS_ID_, Self.Index + BASE_Z_LAYER);
|
|
end;
|
|
|
|
destructor TMapLayer.Destroy;
|
|
begin
|
|
FPointsOfInterest.Free;
|
|
FTracks.Free;
|
|
if Assigned(FComboLayer) then
|
|
View.GPSItems.Delete(FComboLayer);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TMapLayer.HitTest(constref Area: TRealArea): TMapObjectList;
|
|
begin
|
|
Result := TMapObjectList.AddListToResult(PointsOfInterest.HitTest(Area),
|
|
Tracks.HitTest(Area));
|
|
end;
|
|
|
|
procedure TMapLayer.AssignFromGPSList(AList: TGPSObjectList);
|
|
|
|
procedure AddPoint(APoint: TGPSPoint);
|
|
begin
|
|
with PointsOfInterest.Add as TMapPoint do
|
|
begin
|
|
Caption := APoint.Name;
|
|
Longitude := APoint.Lon;
|
|
Latitude := APoint.Lat;
|
|
Elevation := APoint.Elevation;
|
|
DateTime := APoint.DateTime;
|
|
end;
|
|
end;
|
|
|
|
procedure AddTrack(ATrack: TGPSTrack);
|
|
var
|
|
I: Integer;
|
|
P: TGPSPoint;
|
|
begin
|
|
with Tracks.Add as TMapTrack do
|
|
begin
|
|
Caption := ATrack.Name;
|
|
for I := 0 to Pred(ATrack.Points.Count) do
|
|
with Points.Add as TMapTrackPoint do
|
|
begin
|
|
P := ATrack.Points[I];
|
|
Caption := P.Name;
|
|
Longitude := P.Lon;
|
|
Latitude := P.Lat;
|
|
Elevation := P.Elevation;
|
|
DateTime := P.DateTime;
|
|
if ATrack.Points[I].ExtraData is TSegmentExtraData then
|
|
Mark := TSegmentExtraData(ATrack.Points[I].ExtraData).Mark;
|
|
end;
|
|
if ATrack.ExtraData is TTrackExtraData then
|
|
begin
|
|
LineWidth := TTrackExtraData(ATrack.ExtraData).Width;
|
|
LineColor := TTrackExtraData(ATrack.ExtraData).Color;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not Assigned(AList) then
|
|
Exit;
|
|
PointsOfInterest.Clear;
|
|
Tracks.Clear;
|
|
for I := 0 to Pred(AList.Count) do
|
|
if AList[I] is TGPSPoint then
|
|
AddPoint(TGPSPoint(AList[I]))
|
|
else if AList[I] is TGPSTrack then
|
|
AddTrack(TGPSTrack(AList[I]))
|
|
else
|
|
{TODO};
|
|
end;
|
|
|
|
{ TMapLayers }
|
|
|
|
function TMapLayers.GetView: TMapView;
|
|
begin
|
|
Result := MCOwner;
|
|
end;
|
|
|
|
function TMapLayers.GetLayer: TMapLayer;
|
|
begin
|
|
Result := Nil;
|
|
end;
|
|
|
|
procedure TMapLayers.FixOrder(APrevIndex, AIndex: Integer);
|
|
var
|
|
I, T, B: Integer;
|
|
begin
|
|
T := Min(APrevIndex, AIndex);
|
|
B := Max(APrevIndex, AIndex);
|
|
if APrevIndex < 0 then
|
|
begin
|
|
T := AIndex;
|
|
B := Pred(Count);
|
|
end;
|
|
for I := T to B do
|
|
View.GPSItems.ChangeZOrder(TMapItem(Items[I]).GPSObj, I + FBaseZ);
|
|
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];
|
|
Viewer.DrawGpsObj(FArea, Obj);
|
|
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);
|
|
end;
|
|
|
|
|
|
{ TMapView }
|
|
|
|
procedure TMapView.SetActive(AValue: boolean);
|
|
begin
|
|
if FActive = AValue then Exit;
|
|
if AValue and (MapProvider = '') then
|
|
// Raising an exception won't let the component to be loaded
|
|
if not (csLoading in ComponentState) then
|
|
raise Exception.Create('MapProvider is not selected.');
|
|
FActive := AValue;
|
|
if FActive then
|
|
ActivateEngine
|
|
else
|
|
Engine.Active := false;
|
|
end;
|
|
|
|
procedure TMapView.SetCacheLocation(AValue: TCacheLocation);
|
|
var
|
|
NewPath: String;
|
|
OldLoc: TCacheLocation;
|
|
begin
|
|
if FCacheLocation = AValue then
|
|
Exit;
|
|
OldLoc := FCacheLocation;
|
|
FCacheLocation := AValue;
|
|
NewPath := CacheDirectory(AValue, CachePath);
|
|
if NewPath = Engine.CachePath then
|
|
Exit;
|
|
ChangeCachePath(OldLoc, NewPath);
|
|
end;
|
|
|
|
procedure TMapView.SetCacheMaxAge(AValue: Integer);
|
|
begin
|
|
if Engine.CacheMaxAge = AValue then
|
|
Exit;
|
|
Engine.CacheMaxAge := AValue;
|
|
UpdateLayers;
|
|
end;
|
|
|
|
function TMapView.GetCacheOnDisk: boolean;
|
|
begin
|
|
Result := FCacheOnDisk;
|
|
end;
|
|
|
|
function TMapView.GetCenter: TRealPoint;
|
|
begin
|
|
Result := Engine.Center;
|
|
end;
|
|
|
|
function TMapView.GetCyclic: Boolean;
|
|
begin
|
|
Result := Engine.Cyclic;
|
|
end;
|
|
|
|
function TMapView.GetDownloadEngine: TMvCustomDownloadEngine;
|
|
begin
|
|
if FDownloadEngine = nil then
|
|
Result := FBuiltinDownloadEngine
|
|
else
|
|
Result := FDownloadEngine;
|
|
end;
|
|
|
|
function TMapView.GetDrawingEngine: TMvCustomDrawingEngine;
|
|
begin
|
|
if FDrawingEngine = nil then
|
|
Result := FBuiltinDrawingEngine
|
|
else
|
|
Result := FDrawingEngine;
|
|
end;
|
|
|
|
function TMapView.GetDrawPreviewTiles: Boolean;
|
|
begin
|
|
Result := Engine.DrawPreviewTiles;
|
|
end;
|
|
|
|
function TMapView.GetGPSItems: TGPSObjectList;
|
|
begin
|
|
Result := GetGPSLayer(5);
|
|
end;
|
|
|
|
function TMapView.GetGPSLayer(Layer: Integer): TGPSObjectList;
|
|
begin
|
|
Result := FGPSItems[Layer mod 10];
|
|
end;
|
|
|
|
function TMapView.GetInactiveColor: TColor;
|
|
begin
|
|
Result := FPColorToTColor(Engine.BkColor);
|
|
end;
|
|
|
|
function TMapView.GetLayers: TMapLayers;
|
|
begin
|
|
Result := FLayers;
|
|
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;
|
|
|
|
function TMapView.GetZoomToCursor: Boolean;
|
|
begin
|
|
Result := Engine.ZoomToCursor;
|
|
end;
|
|
|
|
function TMapView.IsCacheMaxAgeStored: Boolean;
|
|
begin
|
|
Result := Engine.CacheMaxAge <> MaxInt;
|
|
end;
|
|
|
|
function TMapView.IsCachePathStored: Boolean;
|
|
begin
|
|
Result := not SameText(CachePath, 'cache/');
|
|
end;
|
|
|
|
function TMapView.IsFontStored: Boolean;
|
|
begin
|
|
Result := SameText(FFont.Name, 'default') and (FFont.Size = 0) and
|
|
(FFont.Style = []) and (FFont.Color = clBlack);
|
|
end;
|
|
|
|
function TMapView.IsLayersStored: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TMapView.SetCacheOnDisk(AValue: boolean);
|
|
begin
|
|
FCacheOnDisk := AValue;
|
|
if csDesigning in ComponentState
|
|
then Engine.CacheOnDisk := False
|
|
else Engine.CacheOnDisk := AValue;
|
|
UpdateLayers;
|
|
end;
|
|
|
|
procedure TMapView.SetCachePath(AValue: String);
|
|
var
|
|
NewPath: String;
|
|
begin
|
|
if FCachePath = AValue then
|
|
Exit;
|
|
FCachePath := AValue;
|
|
NewPath := CacheDirectory(CacheLocation, AValue);
|
|
if NewPath = Engine.CachePath then
|
|
Exit;
|
|
ChangeCachePath(CacheLocation, NewPath);
|
|
end;
|
|
|
|
procedure TMapView.SetCenter(AValue: TRealPoint);
|
|
begin
|
|
Engine.Center := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetCyclic(AValue: Boolean);
|
|
begin
|
|
Engine.Cyclic := AValue;
|
|
UpdateLayers;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetDebugTiles(AValue: Boolean);
|
|
begin
|
|
if FDebugTiles = AValue then exit;
|
|
FDebugTiles := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetDefaultTrackColor(AValue: TColor);
|
|
begin
|
|
if FDefaultTrackColor = AValue then exit;
|
|
FDefaultTrackColor := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetDefaultTrackWidth(AValue: Integer);
|
|
begin
|
|
if FDefaultTrackWidth = AValue then exit;
|
|
FDefaultTrackWidth := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetDownloadEngine(AValue: TMvCustomDownloadEngine);
|
|
begin
|
|
FDownloadEngine := AValue;
|
|
FEngine.DownloadEngine := GetDownloadEngine;
|
|
UpdateLayers;
|
|
end;
|
|
|
|
procedure TMapView.SetDrawingEngine(AValue: TMvCustomDrawingEngine);
|
|
begin
|
|
FDrawingEngine := AValue;
|
|
if AValue = nil then
|
|
begin
|
|
FBuiltinDrawingEngine.CreateBuffer(ClientWidth, ClientHeight);
|
|
FEngine.CacheItemClass := FBuiltinDrawingEngine.GetCacheItemClass;
|
|
end
|
|
else begin
|
|
FBuiltinDrawingEngine.CreateBuffer(0, 0);
|
|
FDrawingEngine.CreateBuffer(ClientWidth, ClientHeight);
|
|
FEngine.CacheItemClass := FDrawingEngine.GetCacheItemClass;
|
|
end;
|
|
UpdateFont(nil);
|
|
end;
|
|
|
|
procedure TMapView.SetDrawPreviewTiles(AValue: Boolean);
|
|
begin
|
|
Engine.DrawPreviewTiles := AValue;
|
|
end;
|
|
|
|
procedure TMapView.SetFont(AValue: TFont);
|
|
begin
|
|
FFont.Assign(AValue);
|
|
UpdateFont(nil);
|
|
end;
|
|
|
|
procedure TMapView.SetInactiveColor(AValue: TColor);
|
|
begin
|
|
Engine.BkColor := TColorToFPColor(AValue);
|
|
if not IsActive then
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetLayers(const ALayers: TMapLayers);
|
|
begin
|
|
FLayers.Assign(ALayers);
|
|
end;
|
|
|
|
procedure TMapView.ActivateEngine;
|
|
begin
|
|
Engine.SetSize(ClientWidth,ClientHeight);
|
|
Engine.Active := IsActive;
|
|
end;
|
|
|
|
procedure TMapView.SetMapProvider(AValue: String);
|
|
begin
|
|
//if AValue = '' then
|
|
// raise EArgumentException.Create('Empty map provider is not allowed.');
|
|
Engine.MapProvider := AValue;
|
|
if AValue = '' then
|
|
Active := False;
|
|
Invalidate;
|
|
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.SetOptions(AValue: TMapViewOptions);
|
|
begin
|
|
if FOptions = AValue then Exit;
|
|
FOptions := AValue;
|
|
if Engine.InDrag and not (mvoMouseDragging in FOptions) then
|
|
begin
|
|
Engine.DragObj.AbortDrag;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.SetPOIImage(const AValue: TBitmap);
|
|
begin
|
|
if FPOIImage = AValue then exit;
|
|
FPOIImage := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetPOIImages(const AValue: TCustomImageList);
|
|
begin
|
|
if FPOIImages = AValue then exit;
|
|
FPOIImages := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetPOIImagesWidth(AValue: Integer);
|
|
begin
|
|
if FPOIImagesWidth = AValue then exit;
|
|
FPOIImagesWidth := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetPOITextBgColor(AValue: TColor);
|
|
begin
|
|
if FPOITextBgColor = AValue then exit;
|
|
FPOITextBgColor := AValue;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetUseThreads(AValue: boolean);
|
|
begin
|
|
Engine.UseThreads := aValue;
|
|
end;
|
|
|
|
procedure TMapView.SetZoom(AValue: integer);
|
|
begin
|
|
Engine.Zoom := EnsureRange(AValue, FZoomMin, FZoomMax);
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.SetZoomMax(AValue: Integer);
|
|
begin
|
|
if FZoomMax = AValue then Exit;
|
|
FZoomMax := EnsureRange(AValue, FZoomMin, 19);
|
|
Engine.ZoomMax := FZoomMax;
|
|
Zoom := GetZoom;
|
|
end;
|
|
|
|
procedure TMapView.SetZoomMin(AValue: Integer);
|
|
begin
|
|
if FZoomMin = AValue then Exit;
|
|
FZoomMin := EnsureRange(AValue, 1, FZoomMax);
|
|
Engine.ZoomMin := FZoomMin;
|
|
Zoom := GetZoom;
|
|
end;
|
|
|
|
procedure TMapView.SetZoomToCursor(AValue: Boolean);
|
|
begin
|
|
Engine.ZoomToCursor := AValue;
|
|
end;
|
|
|
|
function TMapView.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
|
|
MousePos: TPoint): Boolean;
|
|
begin
|
|
Result:=inherited DoMouseWheel(Shift, WheelDelta, MousePos);
|
|
if IsActive and (mvoMouseZooming in FOptions) then
|
|
begin
|
|
Engine.MouseWheel(self,Shift,WheelDelta,MousePos,Result);
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
begin
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
if IsActive and (mvoMouseDragging in FOptions) then
|
|
if Button = mbLeft then
|
|
begin
|
|
Engine.MouseDown(self,Button,Shift,X,Y);
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
begin
|
|
inherited MouseUp(Button, Shift, X, Y);
|
|
if IsActive then
|
|
if Button = mbLeft then
|
|
begin
|
|
Engine.MouseUp(self,Button,Shift,X,Y);
|
|
Engine.Redraw;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
inherited MouseMove(Shift, X, Y);
|
|
if IsActive then
|
|
begin
|
|
Engine.MouseMove(self,Shift,X,Y);
|
|
if Engine.InDrag
|
|
then Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited;
|
|
if (AComponent = FPOIImages) and (Operation = opRemove) then
|
|
FPOIImages := nil;
|
|
end;
|
|
|
|
procedure TMapView.DblClick;
|
|
begin
|
|
inherited DblClick;
|
|
if IsActive then
|
|
begin
|
|
Engine.DblClick(self);
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.DoOnResize;
|
|
begin
|
|
inherited DoOnResize;
|
|
//cancel all rendering threads
|
|
Engine.CancelCurrentDrawing;
|
|
DrawingEngine.CreateBuffer(ClientWidth, ClientHeight);
|
|
if IsActive then
|
|
begin
|
|
Engine.SetSize(ClientWidth, ClientHeight);
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.Paint;
|
|
const
|
|
FREE_DRAG = 0; //(TILE_SIZE * TILE_SIZE) div 4;
|
|
|
|
procedure DrawCenter;
|
|
var
|
|
C: TPoint;
|
|
begin
|
|
C := Point(ClientWidth div 2, ClientHeight div 2);
|
|
Canvas.Pen.Color := clBlack;
|
|
Canvas.Pen.Width := 1;
|
|
Canvas.Line(C.X, C.Y - 15, C.X, C.Y + 15);
|
|
Canvas.Line(C.X - 15, C.Y, C.X + 15, C.Y);
|
|
end;
|
|
|
|
procedure InactiveDraw;
|
|
begin
|
|
Canvas.Brush.Color := InactiveColor;
|
|
Canvas.Brush.Style := bsSolid;
|
|
Canvas.FillRect(0, 0, ClientWidth, ClientHeight);
|
|
end;
|
|
|
|
procedure FullRedraw;
|
|
var
|
|
W: Integer;
|
|
begin
|
|
Engine.Redraw;
|
|
W := Canvas.Width;
|
|
if Cyclic then
|
|
W := Min(1 shl Zoom * TILE_SIZE, W);
|
|
DrawObjects(Default(TTileId), 0, 0, W - 1, Canvas.Height);
|
|
DrawingEngine.PaintToCanvas(Canvas);
|
|
if DebugTiles then
|
|
DrawCenter;
|
|
end;
|
|
|
|
procedure DragDraw;
|
|
var
|
|
O: TPoint;
|
|
begin
|
|
O := Point(Engine.DragObj.OfsX, Engine.DragObj.OfsY);
|
|
// Free drag up to half of the tile
|
|
if ((O.X * O.X + O.Y * O.Y) < FREE_DRAG) then
|
|
begin
|
|
DrawingEngine.PaintToCanvas(Canvas);
|
|
DrawingEngine.PaintToCanvas(Canvas, O);
|
|
if DebugTiles then
|
|
DrawCenter;
|
|
end
|
|
else
|
|
FullRedraw;
|
|
end;
|
|
|
|
begin
|
|
inherited Paint;
|
|
if IsActive
|
|
then if Engine.InDrag
|
|
then DragDraw
|
|
else FullRedraw
|
|
else
|
|
InactiveDraw;
|
|
end;
|
|
|
|
procedure TMapView.OnGPSItemsModified(Sender: TObject; objs: TGPSObjList;
|
|
Adding: boolean);
|
|
var
|
|
Area, objArea, visArea: TRealArea;
|
|
begin
|
|
if Adding and Assigned(Objs) then
|
|
begin
|
|
objArea := GetAreaOf(Objs);
|
|
visArea := GetVisibleArea;
|
|
if hasIntersectArea(objArea, visArea) then
|
|
begin
|
|
Area := IntersectArea(objArea, visArea);
|
|
Invalidate;
|
|
end
|
|
end
|
|
else
|
|
Engine.Redraw;
|
|
end;
|
|
|
|
procedure TMapView.StartDragging(X, Y: Integer);
|
|
begin
|
|
Engine.DragObj.MouseDown(Engine, X, Y);
|
|
end;
|
|
|
|
procedure TMapView.EndDragging(X, Y: Integer);
|
|
var
|
|
Drag: Boolean;
|
|
begin
|
|
Drag := Engine.InDrag;
|
|
Engine.DragObj.MouseUp(X, Y);
|
|
if Drag then
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TMapView.AbortDragging;
|
|
begin
|
|
Engine.DragObj.AbortDrag;
|
|
end;
|
|
|
|
function TMapView.TrackLineColor(AColor: TColor; ExtraData: TObject): TColor;
|
|
begin
|
|
if AColor = clDefault then
|
|
begin
|
|
Result := ColorToRGB(FDefaultTrackColor);
|
|
if (ExtraData <> Nil) and ExtraData.InheritsFrom(TDrawingExtraData) then
|
|
Result := TDrawingExtraData(ExtraData).Color;
|
|
end
|
|
else
|
|
Result := ColorToRGB(AColor);
|
|
end;
|
|
|
|
function TMapView.TrackLineWidth(AWidth: Double; ExtraData: TObject): Integer;
|
|
begin
|
|
if AWidth = -1 then
|
|
begin
|
|
Result := FDefaultTrackWidth;
|
|
if (ExtraData <> Nil) and ExtraData.InheritsFrom(TTrackExtraData) then
|
|
Result := mmToPx(TTrackExtraData(ExtraData).Width);
|
|
end
|
|
else
|
|
Result := mmToPx(AWidth);
|
|
if Result < 1 then
|
|
Result := 1;
|
|
end;
|
|
|
|
procedure TMapView.DrawTrack(const Area: TRealArea; trk: TGPSTrack);
|
|
var
|
|
I, L, T, WS: Integer;
|
|
ClipRect: TRect;
|
|
iPt1, iPt2, iPt3, iPt4: TPoint;
|
|
ToEast, EndSegm, ConnSegm: Boolean;
|
|
pt1, pt2: TRealPoint;
|
|
trkColor, connColor: TColor;
|
|
trkWidth, connWidth: Integer;
|
|
|
|
procedure ClipDrawLine(P1, P2: TPoint); inline;
|
|
begin
|
|
if not ClipLineToRect(ClipRect, P1, P2) then
|
|
DrawingEngine.Line(P1.X, P1.Y, P2.X, P2.Y);
|
|
end;
|
|
|
|
begin
|
|
if not trk.Visible or (trk.Points.Count = 0) then
|
|
exit;
|
|
|
|
// Determine track color
|
|
trkColor := TrackLineColor(trk.LineColor, trk.ExtraData);
|
|
|
|
// Determine track width
|
|
trkWidth := TrackLineWidth(trk.LineWidth, trk.ExtraData);
|
|
|
|
ConnSegm := trk.ConnectColor <> clNone;
|
|
if ConnSegm then
|
|
begin
|
|
if trk.ConnectColor = clDefault
|
|
then connColor := trkColor
|
|
else connColor := TrackLineColor(trk.ConnectColor, trk.ExtraData);
|
|
if trk.ConnectWidth < 0.01
|
|
then connWidth := trkWidth
|
|
else connWidth := TrackLineWidth(trk.ConnectWidth, trk.ExtraData);
|
|
end;
|
|
|
|
DrawingEngine.PenColor := trkColor;
|
|
DrawingEngine.PenWidth := trkWidth;
|
|
|
|
// Clipping rectangle
|
|
if Cyclic then
|
|
ClipRect := Rect(0, 0, ClientWidth, ClientHeight)
|
|
else
|
|
begin
|
|
L := Max(0, Engine.MapLeft);
|
|
T := Max(0, Engine.MapTop);
|
|
WS := ZoomFactor(Zoom) * TILE_SIZE;
|
|
ClipRect := Rect(L, T, Min(Engine.MapLeft + WS, ClientWidth),
|
|
Min(Engine.MapTop + WS, ClientHeight));
|
|
end;
|
|
|
|
pt1 := trk.Points[0].RealPoint;
|
|
iPt1 := Engine.LatLonToScreen(pt1);
|
|
EndSegm := TSegmentExtraData.MarkOf(trk.Points[0].ExtraData) = smEnd;
|
|
for I := 1 to Pred(trk.Points.Count) do
|
|
begin
|
|
pt2 := trk.Points[I].RealPoint;
|
|
iPt2 := Engine.LatLonToScreen(pt2);
|
|
ToEast := GoingEast(pt1.Lon, pt2.Lon); // Eastwards?
|
|
iPt2 := CyclicPointOf(iPt2, iPt1.X, ToEast); // Nearest iPt2 to iPt1
|
|
|
|
// Rightmost cyclic copy of the segment
|
|
if ToEast then
|
|
begin
|
|
iPt3 := CyclicPointOf(iPt1, ClipRect.Right); // Left point
|
|
iPt4 := (iPt2 - iPt1); // delta to the right point
|
|
end
|
|
else
|
|
begin
|
|
iPt3 := CyclicPointOf(iPt2, ClipRect.Right); // Left point
|
|
iPt4 := (iPt1 - iPt2); // delta to the right point
|
|
end;
|
|
|
|
if EndSegm and ConnSegm then
|
|
begin
|
|
DrawingEngine.PenColor := connColor;
|
|
DrawingEngine.PenWidth := connWidth;
|
|
end;
|
|
|
|
if not EndSegm or ConnSegm then
|
|
// Draw all copies of the segment, right to left
|
|
repeat
|
|
ClipDrawLine(iPt3, iPt3 + iPt4);
|
|
iPt3 := CyclicPointOf(iPt3, Pred(iPt3.X), False); // Next left cyclic iPt3
|
|
until Max(iPt3.X, iPt3.X + iPt4.X) < ClipRect.Left;
|
|
|
|
if EndSegm and ConnSegm then
|
|
begin
|
|
DrawingEngine.PenColor := trkColor;
|
|
DrawingEngine.PenWidth := trkWidth;
|
|
end;
|
|
|
|
pt1 := pt2;
|
|
iPt1 := iPt2;
|
|
EndSegm := TSegmentExtraData.MarkOf(trk.Points[I].ExtraData) = smEnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.DrawArea(const Area: TRealArea; ar: TGPSArea);
|
|
var
|
|
Pts: array of TPoint;
|
|
I, C: Integer;
|
|
NoFill: Boolean;
|
|
WS: Int64;
|
|
begin
|
|
if not ar.Visible or (ar.Points.Count = 0) then
|
|
Exit;
|
|
|
|
if Cyclic then
|
|
begin
|
|
WS := ZoomFactor(Zoom) * TILE_SIZE;
|
|
if (WS < ClientWidth) then
|
|
begin
|
|
{TODO Draw multiple copies of the area}
|
|
Exit; // Not implemented, exit
|
|
end;
|
|
end;
|
|
{TODO Fix drawing when the area crosses the date line, see DrawTrack}
|
|
|
|
C := ar.Points.Count;
|
|
NoFill := (ar.FillColor = clNone);
|
|
if NoFill then
|
|
Inc(C);
|
|
|
|
SetLength(Pts, C);
|
|
for I := 0 to Pred(ar.Points.Count) do
|
|
Pts[I] := Engine.LatLonToScreen(ar.Points[I].RealPoint);
|
|
if NoFill then
|
|
Pts[Pred(C)] := Pts[0];
|
|
|
|
if ar.LineColor = clNone then
|
|
DrawingEngine.PenStyle := psClear
|
|
else
|
|
begin
|
|
DrawingEngine.PenStyle := psSolid;
|
|
DrawingEngine.PenColor := TrackLineColor(ar.LineColor, ar.ExtraData);
|
|
DrawingEngine.PenWidth := TrackLineWidth(ar.LineWidth, ar.ExtraData);
|
|
end;
|
|
if NoFill then
|
|
DrawingEngine.Polyline(Pts)
|
|
else
|
|
begin
|
|
DrawingEngine.BrushStyle := bsSolid;
|
|
DrawingEngine.BrushColor := ar.FillColor;
|
|
DrawingEngine.Polygon(Pts);
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.DrawPointOfInterest(const Area: TRealArea; APt: TGPSPointOfInterest);
|
|
var
|
|
pt: TPoint;
|
|
ptCyc: TPointArray;
|
|
ptColor: TColor;
|
|
extent: TSize;
|
|
s: String;
|
|
bmp: TBitmap;
|
|
w, h: Integer;
|
|
|
|
procedure DrawOne(pt: TPoint);
|
|
begin
|
|
if Assigned(bmp) then
|
|
DrawingEngine.DrawBitmap(pt.X - w div 2, pt.Y - h, bmp, true)
|
|
else
|
|
begin
|
|
// ... or as cross
|
|
ptColor := clRed;
|
|
if (APt.ExtraData <> nil) and APt.ExtraData.InheritsFrom(TDrawingExtraData) then
|
|
ptColor := TDrawingExtraData(APt.ExtraData).Color;
|
|
DrawingEngine.PenColor := ptColor;
|
|
DrawingEngine.PenWidth := 3;
|
|
DrawingEngine.Line(pt.X, pt.Y - 5, pt.X, pt.Y + 5);
|
|
DrawingEngine.Line(pt.X - 5, pt.Y, pt.X + 5, pt.Y);
|
|
pt.Y := pt.Y + 5;
|
|
end;
|
|
if FPOITextBgColor = clNone then
|
|
DrawingEngine.BrushStyle := bsClear
|
|
else
|
|
begin
|
|
DrawingEngine.BrushStyle := bsSolid;
|
|
DrawingEngine.BrushColor := FPOITextBgColor;
|
|
end;
|
|
DrawingEngine.TextOut(pt.X - extent.CX div 2, pt.Y + 5, s);
|
|
end;
|
|
|
|
begin
|
|
pt := Engine.LatLonToScreen(APt.RealPoint);
|
|
|
|
bmp := Nil;
|
|
try
|
|
// Draw point as symbol from image list ...
|
|
if Assigned(FPOIImages) and (APt.ImageIndex <> -1) and (APt.ImageIndex < FPOIImages.Count) then
|
|
begin
|
|
bmp := TBitmap.Create;
|
|
FPOIImages.GetBitmap(APt.ImageIndex, bmp);
|
|
{$IF LCL_FullVersion >= 2000000}
|
|
w := FPOIImages.WidthForPPI[FPOIImagesWidth, Font.PixelsPerInch];
|
|
h := FPOIImages.HeightForPPI[FPOIImagesWidth, Font.PixelsPerInch];
|
|
{$ELSE}
|
|
w := FPOIImages.Width;
|
|
h := FPOIImages.Height;
|
|
{$IFEND}
|
|
end;
|
|
|
|
// Draw point text
|
|
s := APt.Name;
|
|
if FPOITextBgColor <> clNone then
|
|
s := ' ' + s + ' ';
|
|
extent := DrawingEngine.TextExtent(s);
|
|
if Cyclic then
|
|
begin
|
|
ptCyc := CyclicPointsOf(pt);
|
|
for pt in ptCyc do
|
|
DrawOne(pt);
|
|
end
|
|
else
|
|
DrawOne(pt);
|
|
finally
|
|
bmp.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.DrawPt(const Area: TRealArea; APt: TGPSPoint);
|
|
var
|
|
Pt: TPoint;
|
|
PtCyc: TPointArray;
|
|
PtColor: TColor;
|
|
extent: TSize;
|
|
s: String;
|
|
|
|
procedure DrawOne(Pt: TPoint);
|
|
begin
|
|
// Draw point marker
|
|
if Assigned(FPOIImage) and not (FPOIImage.Empty) then
|
|
DrawingEngine.DrawBitmap(Pt.X - FPOIImage.Width div 2, Pt.Y - FPOIImage.Height, FPOIImage, true)
|
|
else begin
|
|
DrawingEngine.PenColor := ptColor;
|
|
DrawingEngine.PenWidth := 3;
|
|
DrawingEngine.Line(Pt.X, Pt.Y - 5, Pt.X, Pt.Y + 5);
|
|
DrawingEngine.Line(Pt.X - 5, Pt.Y, Pt.X + 5, Pt.Y);
|
|
Pt.Y := Pt.Y + 5;
|
|
end;
|
|
|
|
// Draw point text
|
|
s := APt.Name;
|
|
if FPOITextBgColor = clNone then
|
|
DrawingEngine.BrushStyle := bsClear
|
|
else begin
|
|
DrawingEngine.BrushStyle := bsSolid;
|
|
DrawingEngine.BrushColor := FPOITextBgColor;
|
|
s := ' ' + s + ' ';
|
|
end;
|
|
extent := DrawingEngine.TextExtent(s);
|
|
DrawingEngine.Textout(Pt.X - extent.CX div 2, Pt.Y + 5, s);
|
|
end;
|
|
|
|
begin
|
|
if Assigned(FOnDrawGpsPoint) then begin
|
|
FOnDrawGpsPoint(Self, DrawingEngine, APt);
|
|
exit;
|
|
end;
|
|
|
|
Pt := Engine.LatLonToScreen(APt.RealPoint);
|
|
PtColor := clRed;
|
|
if APt.ExtraData <> nil then
|
|
begin
|
|
if APt.ExtraData.inheritsFrom(TDrawingExtraData) then
|
|
PtColor := TDrawingExtraData(APt.ExtraData).Color;
|
|
end;
|
|
|
|
PtCyc := CyclicPointsOf(Pt);
|
|
for Pt in PtCyc do
|
|
DrawOne(Pt);
|
|
end;
|
|
|
|
procedure TMapView.DrawGpsObj(const Area: TRealArea; AObj: TGPSObj);
|
|
begin
|
|
GPSItems.Lock;
|
|
try
|
|
AObj.Draw(Self, Area);
|
|
finally
|
|
GPSItems.Unlock;
|
|
end;
|
|
end;
|
|
|
|
function TMapView.GetCacheMaxAge: Integer;
|
|
begin
|
|
Result := Engine.CacheMaxAge;
|
|
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
|
|
Area: TRealArea;
|
|
lst: TGPSObjList;
|
|
I, J: Integer;
|
|
begin
|
|
Area.TopLeft := Engine.ScreenToLatLon(Point(aLeft, aTop));
|
|
Area.BottomRight := Engine.ScreenToLatLon(Point(aRight, aBottom));
|
|
|
|
for J := 0 to High(FGPSItems) do
|
|
if FGPSItems[J].Visible and (FGPSItems[J].Count > 0) then
|
|
begin
|
|
lst := FGPSItems[J].GetObjectsInArea(Area);
|
|
try
|
|
if lst.Count > 0 then
|
|
begin
|
|
for I := 0 to Pred(lst.Count) do
|
|
if lst[I].Visible then
|
|
DrawGpsObj(Area, lst[I]);
|
|
end;
|
|
finally
|
|
FreeAndNil(Lst);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.DoAsyncInvalidate(Data: PtrInt);
|
|
Begin
|
|
Invalidate;
|
|
AsyncInvalidate := false;
|
|
end;
|
|
|
|
procedure TMapView.DoDrawStretchedTile(const TileId: TTileID; X, Y: Integer;
|
|
TileImg: TPictureCacheItem; const R: TRect);
|
|
begin
|
|
if Assigned(TileImg) then
|
|
DrawingEngine.DrawScaledCacheItem(Rect(X, Y, X + TILE_SIZE, Y + TILE_SIZE), R, TileImg)
|
|
else
|
|
DrawingEngine.FillPixels(X, Y, X + TILE_SIZE, Y + TILE_SIZE, InactiveColor);
|
|
|
|
if FDebugTiles then
|
|
DoDrawTileInfo(TileID, X, Y);
|
|
|
|
end;
|
|
|
|
procedure TMapView.DoDrawTile(const TileId: TTileId; X, Y: integer;
|
|
TileImg: TPictureCacheItem);
|
|
begin
|
|
if Assigned(TileImg) then
|
|
DrawingEngine.DrawCacheItem(X, Y, TileImg)
|
|
else
|
|
DrawingEngine.FillPixels(X, Y, X + TILE_SIZE, Y + TILE_SIZE, InactiveColor);
|
|
|
|
if FDebugTiles then
|
|
DoDrawTileInfo(TileID, X, Y);
|
|
|
|
end;
|
|
|
|
procedure TMapView.DoDrawTileInfo(const TileID: TTileID; X, Y: Integer);
|
|
begin
|
|
DrawingEngine.PenColor := clGray;
|
|
DrawingEngine.PenWidth := 1;
|
|
DrawingEngine.Line(X, Y, X, Y + TILE_SIZE);
|
|
DrawingEngine.Line(X, Y, X + TILE_SIZE, Y);
|
|
DrawingEngine.Line(X + TILE_SIZE, Y, X + TILE_SIZE, Y + TILE_SIZE);
|
|
DrawingEngine.Line(X, Y + TILE_SIZE, X + TILE_SIZE, Y + TILE_SIZE);
|
|
end;
|
|
|
|
procedure TMapView.DoEraseBackground(const R: TRect);
|
|
begin
|
|
DrawingEngine.FillPixels(R.Left, R.Top, R.Right, R.Bottom, InactiveColor);
|
|
end;
|
|
|
|
procedure TMapView.DoTileDownloaded(const TileId: TTileId);
|
|
begin
|
|
// TODO: Include tile information to optimize redraw.
|
|
CallAsyncInvalidate;
|
|
end;
|
|
|
|
function TMapView.IsActive: Boolean;
|
|
begin
|
|
Result := FActive
|
|
end;
|
|
|
|
constructor TMapView.Create(AOwner: TComponent);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
inherited Create(AOwner);
|
|
Width := 150;
|
|
Height := 150;
|
|
|
|
FLayers := CreateLayers;
|
|
|
|
FActive := false;
|
|
FOptions := DefaultMapViewOptions;
|
|
|
|
FDefaultTrackColor := clRed;
|
|
FDefaultTrackWidth := 1;
|
|
|
|
for I := 0 to High(FGPSItems) do
|
|
begin
|
|
FGPSItems[I] := TGPSObjectList.Create;
|
|
FGPSItems[I].OnModified := @OnGPSItemsModified;
|
|
end;
|
|
|
|
{$IFDEF MSWindows}
|
|
FBuiltinDownloadEngine := TMvDEWin.Create(self);
|
|
{$ELSE}
|
|
FBuiltinDownloadEngine := TMvDEFpc.Create(self);
|
|
{$ENDIF}
|
|
FBuiltinDownloadEngine.Name := 'BuiltInDLE';
|
|
|
|
FCacheLocation := clProfile;
|
|
|
|
FEngine := TMapViewerEngine.Create(self);
|
|
FEngine.BkColor := colWhite;
|
|
{FEngine.}CachePath := 'cache/';
|
|
{FEngine.}CacheOnDisk := true;
|
|
FEngine.OnDrawTile := @DoDrawTile;
|
|
FEngine.OnDrawStretchedTile := @DoDrawStretchedTile;
|
|
FEngine.OnEraseBackground := @DoEraseBackground;
|
|
FEngine.OnTileDownloaded := @DoTileDownloaded;
|
|
FEngine.DrawPreviewTiles := True;
|
|
FEngine.DrawTitleInGuiThread := false;
|
|
FEngine.DownloadEngine := FBuiltinDownloadEngine;
|
|
FEngine.ZoomToCursor := True;
|
|
|
|
FBuiltinDrawingEngine := TMvIntfGraphicsDrawingEngine.Create(self);
|
|
FEngine.CacheItemClass := FBuiltinDrawingEngine.GetCacheItemClass;
|
|
FBuiltinDrawingEngine.Name := 'BuiltInDE';
|
|
FBuiltinDrawingEngine.CreateBuffer(Width, Height);
|
|
|
|
FFont := TFont.Create;
|
|
FFont.Name := 'default';
|
|
FFont.Size := 0;
|
|
FFont.Style := [];
|
|
FFont.Color := clBlack;
|
|
FFont.OnChange := @UpdateFont;
|
|
|
|
FPOIImage := TBitmap.Create;
|
|
FPOIImage.OnChange := @UpdateImage;
|
|
FPOITextBgColor := clNone;
|
|
|
|
FCenter := TMapCenter.Create(Self);
|
|
FCenter.Longitude := 0.0;
|
|
FCenter.Latitude := 0.0;
|
|
|
|
FZoomMin := 1;
|
|
FZoomMax := 19;
|
|
Zoom := 1;
|
|
end;
|
|
|
|
destructor TMapView.Destroy;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Active := False;
|
|
Engine.Jobqueue.RemoveAsyncCalls(Self);
|
|
FFont.Free;
|
|
FreeAndNil(FPOIImage);
|
|
FLayers.Free;
|
|
for I := 0 to High(FGPSItems) do
|
|
FreeAndNil(FGPSItems[I]);
|
|
FCenter.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TMapView.CyclicPointOf(APoint: TPoint; ARefX: LongInt;
|
|
Eastwards: Boolean): TPoint;
|
|
var
|
|
WorldSize: Int64;
|
|
begin
|
|
Result := APoint;
|
|
WorldSize := ZoomFactor(Zoom) * TILE_SIZE;
|
|
if Eastwards then
|
|
begin
|
|
while Result.X < ARefX do
|
|
Inc(Result.X, WorldSize);
|
|
while Result.X >= ARefX + WorldSize do
|
|
Dec(Result.X, WorldSize);
|
|
end
|
|
else
|
|
begin
|
|
while Result.X > ARefX do
|
|
Dec(Result.X, WorldSize);
|
|
while Result.X <= ARefX - WorldSize do
|
|
Inc(Result.X, WorldSize);
|
|
end;
|
|
end;
|
|
|
|
function TMapView.CyclicPointsOf(APoint: TPoint): TPointArray;
|
|
var
|
|
I, R, L, WorldSize, CanvasWidth: LongInt;
|
|
begin
|
|
Result := Default(TPointArray);
|
|
if not Cyclic then
|
|
begin
|
|
SetLength(Result, 1);
|
|
Result[0] := APoint;
|
|
end
|
|
else
|
|
begin
|
|
WorldSize := ZoomFactor(Zoom) * TILE_SIZE;
|
|
CanvasWidth := Canvas.Width;
|
|
SetLength(Result, 1{APoint} + (1{Round} + CanvasWidth div WorldSize));
|
|
Result[0] := APoint;
|
|
I := 1; R := APoint.X + WorldSize; L := APoint.X - WorldSize;
|
|
while (R < CanvasWidth) or (L >= 0) do
|
|
begin
|
|
if R < CanvasWidth then
|
|
begin
|
|
Result[I].Y := APoint.Y;
|
|
Result[I].X := R;
|
|
Inc(I);
|
|
end;
|
|
if L >= 0 then
|
|
begin
|
|
Result[I].Y := APoint.Y;
|
|
Result[I].X := L;
|
|
Inc(I);
|
|
end;
|
|
Inc(R, WorldSize);
|
|
Dec(L, WorldSize);
|
|
end;
|
|
if I < Length(Result) then
|
|
SetLength(Result, I);
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.SaveToFile(AClass: TRasterImageClass; const AFileName: String);
|
|
var
|
|
stream: TFileStream;
|
|
begin
|
|
stream := TFileStream.Create(AFileName, fmCreate + fmShareDenyNone);
|
|
try
|
|
SaveToStream(AClass, stream);
|
|
finally
|
|
stream.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMapView.SaveToImage(AClass: TRasterImageClass): TRasterImage;
|
|
begin
|
|
Result := DrawingEngine.SaveToImage(AClass);
|
|
end;
|
|
|
|
procedure TMapView.SaveToStream(AClass: TRasterImageClass; AStream: TStream);
|
|
var
|
|
img: TRasterImage;
|
|
begin
|
|
img := SaveToImage(AClass);
|
|
try
|
|
img.SaveToStream(AStream);
|
|
finally
|
|
img.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMapView.ScreenToLatLon(aPt: TPoint): TRealPoint;
|
|
begin
|
|
Result := Engine.ScreenToLatLon(aPt);
|
|
end;
|
|
|
|
function TMapView.ScreenToLonLat(aPt: TPoint): TRealPoint;
|
|
begin
|
|
Result := Engine.ScreenToLatLon(aPt);
|
|
end;
|
|
|
|
function TMapView.LatLonToScreen(aPt: TRealPoint): TPoint;
|
|
begin
|
|
Result := Engine.LatLonToScreen(aPt);
|
|
end;
|
|
|
|
function TMapView.LatLonToScreen(Lat, Lon: Double): TPoint;
|
|
begin
|
|
Result := LatLonToScreen(RealPoint(Lat, Lon));
|
|
end;
|
|
|
|
function TMapView.LonLatToScreen(aPt: TRealPoint): TPoint;
|
|
begin
|
|
Result := Engine.LatLonToScreen(aPt);
|
|
end;
|
|
|
|
procedure TMapView.GetMapProviders(lstProviders: TStrings);
|
|
var
|
|
L: TStringList;
|
|
begin
|
|
L := TStringList.Create;
|
|
try
|
|
Engine.GetMapProviders(L);
|
|
L.Sort;
|
|
lstProviders.Assign(L);
|
|
finally
|
|
L.Free;
|
|
end;
|
|
// Engine.GetMapProviders(lstProviders);
|
|
end;
|
|
|
|
procedure TMapView.WaitEndOfRendering;
|
|
begin
|
|
Engine.Jobqueue.WaitAllJobTerminated(Engine);
|
|
end;
|
|
|
|
function TMapView.ObjsAtScreenPt(X, Y: Integer; ATolerance: Integer = -1): TGPSObjarray;
|
|
const
|
|
DELTA = 3;
|
|
var
|
|
rArea: TRealArea;
|
|
gpsList: TGPSObjList;
|
|
i, J: Integer;
|
|
L: TGPSObjectList;
|
|
begin
|
|
Result := nil;
|
|
|
|
if ATolerance = -1 then
|
|
ATolerance := DELTA;
|
|
|
|
// Define area of +/-ATolerance pixels around the screen point
|
|
rArea.TopLeft := ScreenToLatLon(Point(X-ATolerance, Y-ATolerance));
|
|
rArea.BottomRight := ScreenToLatLon(Point(X+ATolerance, Y+ATolerance));
|
|
|
|
// Collect Objects in this are
|
|
for J := 0 to 9 do
|
|
begin
|
|
gpsList := FGPSItems[J].GetObjectsInArea(rArea);
|
|
try
|
|
SetLength(Result, gpsList.Count);
|
|
for i := 0 to gpsList.Count-1 do
|
|
if gpsList[i] is TGPSPoint then
|
|
Result[i] := gpsList[i];
|
|
finally
|
|
gpsList.Free;
|
|
end;
|
|
end;
|
|
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;
|
|
|
|
procedure TMapView.Redraw;
|
|
begin
|
|
Invalidate;
|
|
end;
|
|
|
|
function TMapView.GetVisibleArea: TRealArea;
|
|
var
|
|
mapWidth: Int64;
|
|
begin
|
|
Result.TopLeft := Engine.ScreenToLatLon(Point(0, 0));
|
|
Result.BottomRight := Engine.ScreenToLatLon(Point(Width, Height));
|
|
if Cyclic then
|
|
begin
|
|
mapWidth := ZoomFactor(Engine.Zoom) * TILE_SIZE;
|
|
if Width >= mapWidth then
|
|
begin
|
|
Result.TopLeft.Lon := -180;
|
|
Result.BottomRight.Lon := 180;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapView.ClearBuffer;
|
|
begin
|
|
DrawingEngine.CreateBuffer(ClientWidth, ClientHeight); // ???
|
|
end;
|
|
|
|
procedure TMapView.UpdateFont(Sender: TObject);
|
|
begin
|
|
if SameText(FFont.Name, 'default') then
|
|
DrawingEngine.FontName := Screen.SystemFont.Name
|
|
else
|
|
DrawingEngine.FontName := FFont.Name;
|
|
if FFont.Size = 0 then
|
|
DrawingEngine.FontSize := Screen.SystemFont.Size
|
|
else
|
|
DrawingEngine.FontSize := FFont.Size;
|
|
DrawingEngine.FontStyle := FFont.Style;
|
|
DrawingEngine.FontColor := ColorToRGB(FFont.Color);
|
|
Engine.Redraw;
|
|
end;
|
|
|
|
procedure TMapView.UpdateImage(Sender: TObject);
|
|
begin
|
|
Engine.Redraw;
|
|
end;
|
|
|
|
function TMapView.CreateLayers: TMapLayers;
|
|
begin
|
|
Result := TMapLayers.Create(Self, BASE_Z_LAYER);
|
|
end;
|
|
|
|
procedure TMapView.UpdateLayers;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Pred(FLayers.Count) do
|
|
FLayers[I].ComboLayer.TileLayer.ParentViewChanged;
|
|
end;
|
|
|
|
procedure TMapView.ChangeCachePath(AOldLoc: TCacheLocation; ANewPath: String);
|
|
var
|
|
OldPath: String;
|
|
begin
|
|
OldPath := Engine.CachePath;
|
|
FCacheFullPath := ANewPath;
|
|
//ForceDirectories(ANewPath);
|
|
Engine.CachePath := ANewPath;
|
|
UpdateLayers;
|
|
if AOldLoc = clTemp then
|
|
DeleteDirectory(OldPath, False);
|
|
end;
|
|
|
|
class function TMapView.CacheDirectory(ALoc: TCacheLocation;
|
|
ACustomPath: String): String;
|
|
const
|
|
LazMVCacheFolder: String = '.lazmapcache/';
|
|
begin
|
|
case ALoc of
|
|
clProfile: Result := Concat(GetUserDir, LazMVCacheFolder);
|
|
clTemp: Result := Concat(GetTempDir(True), LazMVCacheFolder);
|
|
otherwise
|
|
Result := ACustomPath;
|
|
end;
|
|
end;
|
|
|
|
{ TGPSTileLayerBase }
|
|
|
|
function TGPSTileLayerBase.GetMapProvider: String;
|
|
begin
|
|
Result := FEngine.MapProvider;
|
|
end;
|
|
|
|
function TGPSTileLayerBase.GetUseThreads: Boolean;
|
|
begin
|
|
Result := FEngine.UseThreads;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.SetParentView(AValue: TMapView);
|
|
begin
|
|
if (FParentView = AValue) and not FParentViewChanged then
|
|
Exit;
|
|
FEngine.Active := False;
|
|
FParentView := AValue;
|
|
if not Assigned(FParentView) then
|
|
Exit;
|
|
FEngine.DownloadEngine := FParentView.DownloadEngine;
|
|
FEngine.CacheItemClass := FParentView.Engine.CacheItemClass;
|
|
FEngine.CachePath := FParentView.Engine.CachePath;
|
|
FEngine.CacheOnDisk := FParentView.Engine.CacheOnDisk;
|
|
FEngine.CacheMaxAge := FParentView.Engine.CacheMaxAge;
|
|
FEngine.Cyclic := FParentView.Engine.Cyclic;
|
|
FEngine.CopyMapWindowFrom(FParentView.Engine);
|
|
FEngine.Active := True;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.DoTileDownloaded(const TileId: TTileId);
|
|
begin
|
|
TileDownLoaded(TileId);
|
|
if Assigned(FParentView) then
|
|
FParentView.Redraw;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.DoDrawTile(const TileId: TTileId; X, Y: Integer;
|
|
TileImg: TPictureCacheItem);
|
|
begin
|
|
DrawTile(TileId, X, Y, TileImg);
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.SetDrawMode(AValue: TItemDrawMode);
|
|
begin
|
|
if FDrawMode = AValue then Exit;
|
|
FDrawMode := AValue;
|
|
if Assigned(FParentView) then
|
|
FParentView.Redraw;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.TileDownloaded(const TileId: TTileId);
|
|
begin
|
|
; // Intentionally empty
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.SetMapProvider(AValue: String);
|
|
begin
|
|
if AValue = FMapProvider then
|
|
Exit;
|
|
FMapProvider := AValue;
|
|
FEngine.MapProvider := FMapProvider;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.SetOpacity(AValue: Single);
|
|
begin
|
|
if FOpacity = AValue then Exit;
|
|
FOpacity := AValue;
|
|
if Assigned(FParentView) then
|
|
FParentView.Redraw;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.SetUseThreads(AValue: Boolean);
|
|
begin
|
|
FEngine.UseThreads := AValue;
|
|
end;
|
|
|
|
constructor TGPSTileLayerBase.Create;
|
|
begin
|
|
inherited;
|
|
FEngine := TMapViewerEngine.Create(Nil);
|
|
FMapProvider := FEngine.MapProvider;
|
|
FEngine.OnTileDownloaded := @DoTileDownloaded;
|
|
FEngine.OnDrawTile := @DoDrawTile;
|
|
end;
|
|
|
|
destructor TGPSTileLayerBase.Destroy;
|
|
begin
|
|
FEngine.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.GetArea(out Area: TRealArea);
|
|
begin
|
|
if Assigned(FParentView)
|
|
then Area := FParentView.GetVisibleArea // Always over visible area
|
|
else Area.Init(-180.0, 90.0, 180.0, -90.0); // Worldwide
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.Draw(AView: TObject; Area: TRealArea);
|
|
begin
|
|
SetParentView(AView as TMapView);
|
|
FEngine.CopyMapWindowFrom(FParentView.Engine);
|
|
end;
|
|
|
|
procedure TGPSTileLayerBase.ParentViewChanged;
|
|
begin
|
|
FParentViewChanged := True;
|
|
end;
|
|
|
|
{ TGPSTileLayerLabels }
|
|
|
|
procedure TGPSTileLayerLabels.DrawTile(const TileId: TTileId; X, Y: Integer;
|
|
TileImg: TPictureCacheItem);
|
|
begin
|
|
; // Intentionally blank
|
|
end;
|
|
|
|
procedure TGPSTileLayerLabels.Draw(AView: TObject; Area: TRealArea);
|
|
var
|
|
V: TMapView;
|
|
PtTL, PtBR, Pt0, Pt: TPoint;
|
|
X, Y, Z, W, H: Integer;
|
|
S: String;
|
|
extent: TSize;
|
|
begin
|
|
inherited Draw(AView, Area);
|
|
V := FParentView;
|
|
PtTL := V.Engine.LatLonToWorldScreen(Area.TopLeft);
|
|
PtBR := V.Engine.LatLonToWorldScreen(Area.BottomRight);
|
|
X := -PtTL.X div TILE_SIZE;
|
|
Y := -PtTL.Y div TILE_SIZE;
|
|
Pt0 := Point(V.Engine.MapLeft + X * TILE_SIZE,
|
|
V.Engine.MapTop + Y * TILE_SIZE);
|
|
Pt := Pt0;
|
|
H := Y + (PtBR.Y - PtTL.Y) div TILE_SIZE;
|
|
while Y <= H do
|
|
begin
|
|
X := -PtTL.X div TILE_SIZE;
|
|
W := X + (PtBR.X - PtTL.X) div TILE_SIZE;
|
|
while X <= W do
|
|
begin
|
|
Z := V.Zoom;
|
|
V.DrawingEngine.BrushStyle := bsSolid;
|
|
V.DrawingEngine.BrushColor := clCream;
|
|
S := Format(' %d-%d-%d ', [X, Y, Z]);
|
|
extent := V.DrawingEngine.TextExtent(S);
|
|
V.DrawingEngine.TextOut(Pt.X + (TILE_SIZE - extent.CX) div 2,
|
|
Pt.Y + (TILE_SIZE - extent.CY) div 2, S);
|
|
Inc(Pt.X, TILE_SIZE);
|
|
Inc(X);
|
|
end;
|
|
Pt.X := Pt0.X;
|
|
Inc(Pt.Y, TILE_SIZE);
|
|
Inc(Y);
|
|
end;
|
|
end;
|
|
|
|
{ TGPSTileLayer }
|
|
|
|
procedure TGPSTileLayer.DrawTile(const TileId: TTileId; X, Y: Integer;
|
|
TileImg: TPictureCacheItem);
|
|
begin
|
|
if not Assigned(FParentView) or not Assigned(TileImg) then
|
|
Exit;
|
|
FParentView.DrawingEngine.DrawCacheItem(X, Y, TileImg, FDrawMode, FOpacity);
|
|
end;
|
|
|
|
procedure TGPSTileLayer.Draw(AView: TObject; Area: TRealArea);
|
|
begin
|
|
inherited Draw(AView, Area);
|
|
FEngine.Redraw;
|
|
end;
|
|
|
|
procedure TGPSTileLayer.TileDownloaded(const TileId: TTileId);
|
|
begin
|
|
FEngine.Redraw;
|
|
end;
|
|
|
|
end.
|
|
|