Sign in Join
Wiki copytemporary

Revision 1 of 4, by Wp on 1-29-2024. The page as it is now.

LazMapViewer

<figure> <img src="lazmapviewer.png" title="lazmapviewer.png" /> <figcaption>lazmapviewer.png</figcaption> </figure>

About

LazMapViewer is a component for embedding maps obtained from the internet, such as Google maps or OpenStreetView, into a Lazarus form.

The initial version of the package was written by Maciej Kaczkowski and later improved by members of the Lazarus forum. The package is currently maintained by Werner Pamler (wp_xxyyzzz-at-gmx-dot-net).

License: Modified LGPL (with linking exception, like Lazarus LCL).

Download and Installation

Development version

Use an SVN client to download the current trunk version from svn://svn.code.sf.net/p/lazarus-ccr/svn/components/lazmapviewer. Alternatively download the zipped snapshot from https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/lazmapviewer/ and unzip it to some folder.

Release version

Occasionally, release versions are made available via the Online Package Manager for easy one-click-installation directly from Lazarus.

Installation

In Lazarus, go to "Package" > "Open Package File .lpk". Navigate to the folder with the LazMapViewer sources, and select lazmapviewerpkg.lkp. Click "Compile", then "Use" > "Install". This will rebuild the IDE (it may take some time). When the process is finished the IDE will restart, and you'll find the MapViewer in the palette Misc.

There are optional, supporting packages to extend the basic functionality. They must be installed in the same way, after lazmapviewerpkg.lpk.

Package file name Contained components Purpose
lazmapviewerpkg.lpk TMapView Main component to display maps
TMvGeoNames Access to geo coordinates of cities
TMvDEFpc Default download engine using the internal fpc routines
lazmapviewer_synapse.lpk TMvDESynapse Alternative download engine based on the Synapse library
lazmapviewer_rgbgraphics.lpk TMvRGBGraphicsDrawingEngine Alternative drawing engine based on the RGBGraphics package
lazmapviewer_bgra.lpk TMvBGRADrawingEngine Alternative drawing engine based on the BGRABitmap package

Requirements

Release v0.2.6 was tested successfully with the following tool combinations: Laz/main + FPC/main, Laz/main + FPC/fixes, Laz 3.0 + FPC 3.2.2, Laz 2.0.8 + FPC 3.0.4, Laz 1.6.4 + FPC 3.0.2 on Windows, with Laz 3.0 + FPC 3.2.2 on Linux Mint gtk2/gtk3/qt5, and with Laz/main + FPC 3.2.2 on MacOS cocoa.

The Main Map Viewer: TMapView

Getting Started

Here is a short tutorial to create your first map.

Preparation

pascal
procedure TForm1.FormActivate(Sender: TObject);
begin
  MapView1.Active := true;
end;

Magnification

pascal
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  MapView1.Zoom := TrackBar1.Position;
end;

Location

pascal
procedure TForm1.FormActivate(Sender: TObject);
var
  P: TRealPoint;
begin
  MapView1.Active := true;
  P.Lon := -73.985130;
  P.Lat := 40.758896;
  MapView1.Center := P;
end;

Basic Documentation

<figure> <img src="tmapview_200.png" title="tmapview_200.png" /> <figcaption>tmapview_200.png</figcaption> </figure>

Properties

These are the main properties of the TMapView component:

Here are properties related to overlayed GPS objects (points of interest, tracks):

Events

Main methods

pascal
uses
  mvTypes,    // for TRealPoint
  mvEngine;   // for LonToStr() and LatToStr() funtions

procedure TForm1.MapView1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  P: TRealPoint;
begin
  P := MapView1.ScreenToLonLat(Point(X, Y));
  Label1.Caption := 'Longitude: ' + LonToStr(P.Lon, true);
  Label2.Caption := 'Latitude: ' + LatToStr(P.Lat, true);
end;
pascal
procedure TForm1.Button1Click(Sender: TObject);
begin
  MapView1.SaveToFile(TJpegImage, 'mapview.jpg');
end;

Map Providers

The MapView component can display maps from various providers. To activate a given provider its name must be specified in the MapProvider property of the component.

Here is a list of the names of the built-in map providers:

The following providers require an API key to access their service. The API key can be obtained by registering at the provider sites. Usually the API keys are free, however, a charge may be required for commercial usage - please see the details on the provider sites. The strings received as API keys must be stored in global variables of your application.

Please respect the license requirements of the map providers.

GPS Objects

The public TMapView property GPSItems collects data on points of interest and tracks to be overlayed on the map. The common data type of these overlay items is

pascal
type
  TGPSObj = class
    ...
  public
    destructor Destroy; override;
    property Name: String read FName write FName;
    property ExtraData: TObject read FExtraData write SetExtraData;
    property IdOwner: Integer read FIdOwner;
    property BoundingBox: TRealArea read GetBoundingBox write SetBoundingBox;
  end;

The Name can be displayed near the item in the map.

ExtraData can be used freely, for example to define the color of a track. An example how this could be done is found in unit mvExtraData, classes TDrawingExtraData and TTrackExtraData.

IdOwner is the ID of the owner TGPSObj instance to which the current item belongs. BoundingBox gives the geo coordinates of the top/left and bottom/right corner points of the rectangle containing all points of the item.

Points

A special TGPSObj item is a TGPSPoint, for example a scenic "Point-of-Interest" (POI), a way point along a hiking path etc.

pascal
  TGPSPoint = class(TGPSObj)
  public
    constructor Create(ALon,ALat: double; AEle: double=NO_ELE; ADateTime: TDateTime=NO_DATE);
    class function CreateFrom(aPt: TRealPoint): TGPSPoint;

    function HasEle: boolean;
    function HasDateTime: Boolean;
    function DistanceInKmFrom(OtherPt: TGPSPoint; UseEle: boolean=true): double;

    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;

In its constructor, the geo coordinate longitude and latitude must be specified. They are also available as read-only properties Lon and Lat. Optional parameters are the elevation of the point (property Ele as well as some date/time information (property DateTime), for example the date when this point was visited. A special function, DistanceInKmFrom, is available to calculate the on-earth distance from another GPS point.

Tracks

The second important TGPSObj descendant is TGPSTrack which stores the points along a path, for example points visited on a trip or a hike. Each point is a instance of the TGPSPoint class, and the individual points are collected by the list Points. Again, there is a DataTime property usable for example to hold the date of the hike. Function TrackLengthInKm calculates the length of the entire path with the points being connected by straight line segments.

pascal
type
  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;

List of GPS Objects

The property GpsItems of the TMapView component is the main class collecting all the GPS objects. It is an instance of the TGPSObjectList:

pascal
type
  TGPSObjectList = class(TGPSObj)
  ...
    constructor Create;
    destructor Destroy; override;

    Procedure Clear(OwnedBy: integer);
    procedure ClearExcept(OwnedBy: integer; const ExceptLst: TIdArray; out Notfound: TIdArray);
    procedure GetArea(out Area: TRealArea); override;
    function GetObjectsInArea(const Area: TRealArea): TGPSObjList;
    function GetIdsArea(const Ids: TIdArray; AIdOwner: integer): TRealArea;

    function Add(aItem: TGpsObj; AIdOwner: integer): integer;
    procedure DeleteById(const Ids: Array of integer);

    procedure BeginUpdate;
    procedure EndUpdate;

    property Count: integer read GetCount;
    property Items[AIndex: Integer]: TGpsObj read GetItem; default;

    property OnModified: TModifiedEvent read FOnModified write FOnModified;
  end;

Objects can be added to the list by calling the Add method. Since each addition is accompanied by a repaint of the MapView you should call BeginUpdate before and EndUpdate after adding the objects. Every added object must be assigned to an arbitrary ID which is used to group the objects.

Method DeleteByID deletes all objects sharing the same IDE. Clear, on the other hand, clears all the objects which are owned by object having the specified ID. An extension is ClearExcept which does the same but skips IDs listed in the ExceptLst array.

GetObjectsInArea creates a TFPObjectlist (of type TGpsObjList here) with all the objects enclosed by the given rectangle (Area). GetIDsArea, conversely, returns the rectangle enclosing all the objects with the IDs listed in parameter IDs (which is a simple array here).

Example: Adding a Point of Interest

Suppose you want to mark a special point in the map by a mouse click and identify it with some descriptive text. Write a handler for the OnMouseUp event in which you query the description and then take the pixel coordinates of the clicked point, convert it to geo coordinates and create a TGpsPoint from it which you add to the GpsItems of the MapView:

pascal
uses
  mvTypes, mvGPSObj;

const
  _POI_ = 10;

procedure TForm1.MapView1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  pt: TRealPoint;
  gpsPt: TGpsPoint;
  ptName: String;
begin
  ptName := '';
  if InputQuery('Point of Interest', 'Enter name:', ptName) then
  begin
    pt := MapView1.ScreenToLonLat(Point(X, Y));
    gpsPt := TGpsPoint.CreateFrom(pt, NO_ELE, Now() );
    gpsPt.Name := ptName;
    Mapview1.GPSItems.Add(gpsPt, _POI_);
  end;
end;

In this example the constant _POI_ is used as ID of the added point. By default, the point is drawn as a red cross, the name is drawn underneath it. You can highlight the text by changing its background color in property POITextBgColor of the MapView. You can also replace the red cross by an arbitrary bitmap which must be loaded into the POIImage property (the folder example of the LazMapViewer installation contains a ready-to-use pin-cushion icon).

There is also an event, OnDrawGpsPoint, which can be used to replace the entire labeling process by custom routines. The event has the GpsPoint as parameter. Drawing style can be defined based on the data stored in the GpsPoint. The other event parameter is the DrawingEngine which provides methods for drawing; it will be explained below. Here is an example in which the added Point-of-Interest is drawn by a blue circle and labeled by a large bold font:

pascal
procedure TForm1.MapView1DrawGpsPoint(Sender: TObject;
  ADrawer: TMvCustomDrawingEngine; APoint: TGpsPoint);
const
  R = 8;
var
  p: TPoint;
begin
  // Screen coordinates of the GPS point
  p := MapView1.LonLatToScreen(APoint.RealPoint);

  // Draw a blue circle
  ADrawer.PenColor := clBlack;
  ADrawer.BrushColor := clBlue;
  ADrawer.BrushStyle := bsSolid;
  ADrawer.Ellipse(p.X-R, p.Y-R, P.X+R, p.Y+R);

  // Draw the point label
  ADrawer.BrushStyle := bsClear;
  ADrawer.FontName := 'SegoeUI';
  ADrawer.FontSize := 16;
  ADrawer.FontStyle := [fsBold];
  ADrawer.TextOut(
    p.X - ADrawer.TextWidth(APoint.Name) div 2,
    p.Y + R + 4,
    APoint.Name
  );
end;

Finding Geo Locations: TMvGeoNames

TMvGeoNames is a component which searches the geo coordinates (longitude, latitude) of many cities or other locations in the world. Using the download engine of the MapView component it sends a query to the site http://geonames.org/search.html and analyzes the returned html string.

<figure> <img src="tmvgeonames_200.png" title="tmvgeonames_200.png" /> <figcaption>tmvgeonames_200.png</figcaption> </figure>

Getting Started

pascal
procedure TForm1.Button1Click(Sender: TObject);
begin
  MapView1.Center := MvGeoNames1.Search('Grand Canyon National Park', MapView1.DownloadEngine);
end;

Documentation

Methods

Properties

Events

pascal
type
  TGeoLocation = class
    Name: String;
    Descr: String;
    Coords: TRealPoint;
  end;

procedure TForm1.MVGeoNames1NameFound(const AName: string;
  const ADescr: String; const ALoc: TRealPoint);
var
  loc: TGeoLocation;
begin
  loc := TGeoLocation.Create;
  loc.Name := AName;
  loc.Descr := ADescr;
  loc.Coords := ALoc;
  ComboBox1.Items.AddObject(AName, loc);
end;

From the Free Pascal wiki, page "LazMapViewer", as it stood on 2024-01-29 after a change by Wp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.