LazMapViewer: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | - | ||
| 2 | - | ||
| 3 | - | ||
| 4 | - | ||
| 1 | + |  | |
| 5 | 2 | ||
| 6 | 3 | ## About | |
| 7 | 4 | ||
| 8 | 5 | **LazMapViewer** is a component for embedding maps obtained from the internet, such as Google maps or OpenStreetView, into a Lazarus form. | |
| 9 | 6 | ||
| 10 | 7 | 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). | |
| 11 | 8 | ||
| 12 | 9 | License: Modified LGPL (with linking exception, like Lazarus LCL). | |
| 13 | 10 | ||
| 14 | 11 | ## Download and Installation | |
| 15 | 12 | ||
| 16 | 13 | **Development version** | |
| 17 | 14 | ||
| 18 | 15 | 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. | |
| 19 | 16 | ||
| 20 | 17 | **Release version** | |
| 21 | 18 | ||
| 22 | 19 | Occasionally, release versions are made available via the [[Online Package Manager]] for easy one-click-installation directly from Lazarus. | |
| 23 | 20 | ||
| 24 | 21 | **Installation** | |
| 25 | 22 | ||
| 26 | 23 | 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**. | |
| 27 | 24 | ||
| 28 | 25 | There are optional, supporting packages to extend the basic functionality. They must be installed in the same way, after `lazmapviewerpkg.lpk`. | |
| 29 | 26 | ||
| 30 | 27 | | Package file name | Contained components | Purpose | | |
| 31 | 28 | |----|----|----| | |
| 32 | 29 | | lazmapviewerpkg.lpk | TMapView | Main component to display maps | | |
| 33 | 30 | | | TMvGeoNames | Access to geo coordinates of cities | | |
| 34 | 31 | | | TMvDEFpc | Default download engine using the internal fpc routines | | |
| 35 | 32 | | lazmapviewer_synapse.lpk | TMvDESynapse | Alternative download engine based on the Synapse library | | |
| 36 | 33 | | lazmapviewer_rgbgraphics.lpk | TMvRGBGraphicsDrawingEngine | Alternative drawing engine based on the RGBGraphics package | | |
| 37 | 34 | | lazmapviewer_bgra.lpk | TMvBGRADrawingEngine | Alternative drawing engine based on the BGRABitmap package | | |
| 38 | 35 | ||
| 39 | 36 | **Requirements** | |
| 40 | 37 | ||
| 41 | 38 | 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. | |
| 42 | 39 | ||
| 43 | 40 | ## The Main Map Viewer: TMapView | |
| 44 | 41 | ||
| 45 | 42 | ### Getting Started | |
| 46 | 43 | ||
| 47 | 44 | Here is a short tutorial to create your first map. | |
| 48 | 45 | ||
| 49 | 46 | #### Preparation | |
| 50 | 47 | ||
| 51 | 48 | - Drop a `TMapView` component on the form and size it as needed. The component is on the *Misc* tab of the Lazarus component palette. | |
| 52 | 49 | - Add this handler for the form's `OnShow` or `OnActivate` event and set the `Active` property of the `MapView` component to `true`; in principle, this should be possible also in the object inspector, however, does not work at the time of this writing. | |
| 53 | 50 | ||
| 54 | 51 | ``` Pascal | |
| 55 | 52 | procedure TForm1.FormActivate(Sender: TObject); | |
| 56 | 53 | begin | |
| 57 | 54 | MapView1.Active := true; | |
| 58 | 55 | end; | |
| 59 | 56 | ``` | |
| 60 | 57 | ||
| 61 | 58 | - That's all. Compile, run and see your fist map! | |
| 62 | 59 | - In the background the `MapView` component has established an internet connection to the default map provider and downloaded the default map. The maps are delivered as a series of **tiled images** at given size, usually 256x256 pixels, and usually in png format. They are stored in a cache directory (property `CachePath`) and used primarily to reduce internet traffic; only when an image is not found another download from the internet is triggered again. | |
| 63 | 60 | ||
| 64 | 61 | #### Magnification | |
| 65 | 62 | ||
| 66 | 63 | - The map images are provided in different magnifications depending on the `Zoom` level of the `MapView`. Each step in `Zoom` level corresponds to doubling the magnification. The maximum `Zoom` level for most map providers is 18 -- this means that the most detailed maps cover a fraction of `1/2^18` of the earth circumference, about 150 m. | |
| 67 | 64 | - So, if you want to see **more details** you must increase the `Zoom` value of the `MapView`. You can enter the requested value in the Object Inspector, or add a `TScrollbar` or `TTrackbar` to the form to change the magnfication interactively by using the following simple `OnChange` event handler (set the `Max` of the bar to, say, 18: | |
| 68 | 65 | ||
| 69 | 66 | ``` Pascal | |
| 70 | 67 | procedure TForm1.TrackBar1Change(Sender: TObject); | |
| 71 | 68 | begin | |
| 72 | 69 | MapView1.Zoom := TrackBar1.Position; | |
| 73 | 70 | end; | |
| 74 | 71 | ``` | |
| 75 | 72 | ||
| 76 | 73 | - Alternatively, zooming can also be achieved by rotating the **mouse wheel**. | |
| 77 | 74 | ||
| 78 | 75 | #### Location | |
| 79 | 76 | ||
| 80 | 77 | - By default the **center of the map** is the intersection of the 0-degree meridian with the equator - which is a bit off of the coast of western Africa. In order to focus onto a different location you must specify its longitude and latitude in the `Center` property of the `MapView`. This is a `TRealPoint` record having the longitude and latitude in the `Lon` and `Lat` record elements. | |
| 81 | 78 | - Suppose we want to zoom into Manhattan. Use your favorite search engine to determine the geo coordinates of Manhattan: Longitude = -73.985130°, Latitude = 40.758896°. Alternatively you can also use the TGeoNames component which comes with the LazMapViewer package and provides access to a database of the geo coordinates of a huge number of locations via internet. | |
| 82 | 79 | ||
| 83 | 80 | ``` Pascal | |
| 84 | 81 | procedure TForm1.FormActivate(Sender: TObject); | |
| 85 | 82 | var | |
| 86 | 83 | P: TRealPoint; | |
| 87 | 84 | begin | |
| 88 | 85 | MapView1.Active := true; | |
| 89 | 86 | P.Lon := -73.985130; | |
| 90 | 87 | P.Lat := 40.758896; | |
| 91 | 88 | MapView1.Center := P; | |
| 92 | 89 | end; | |
| 93 | 90 | ``` | |
| 94 | 91 | ||
| 95 | 92 | - In addition to specifying the location numerically the you can also change location by **dragging the map with the mouse**. Just press the left mouse button and slowly move the mouse in the direction where you want to see more - the map will follow. But you should be aware that usually neighboring maps will have to be loaded from the internet, and this makes the entire action a bit sluggish. | |
| 96 | 93 | ||
| 97 | 94 | ### Basic Documentation | |
| 98 | 95 | ||
| 99 | - | ||
| 100 | - | ||
| 101 | - | ||
| 102 | - | ||
| 96 | + |  | |
| 103 | 97 | ||
| 104 | 98 | #### Properties | |
| 105 | 99 | ||
| 106 | 100 | These are the main properties of the `TMapView` component: | |
| 107 | 101 | ||
| 108 | 102 | - `Active (boolean)`: must be set to `true` before the `MapView` component can display maps. | |
| 109 | 103 | - `CacheOnDisk (boolean)`: when set to `true` (default) dowloaded map tiles are stored in a directory to reduce internet traffic and for faster access. It is not recommended to turn this property off. The cache is not deleted automatically. | |
| 110 | 104 | - `CachePath (string)`: name of the directory in which downloaded map images are buffered. | |
| 111 | 105 | - `DownloadEngine (TMvCustomDownloadEngine)`: By default, the `TFPHttpClient` is employed to download the images from the map servers. If a different download engine is required the corresponding component can be hooked to this property. The standard installation of the *LazMapViewer* package contains the default `TMvDEFPC` downloader (based on FPC's `TFPHttpClient`) and the `TMvDESynapse` based on the *Synapse* library). | |
| 112 | 106 | - `DrawingEngine (TMvCustomDrawingEngine)`: Painting of the tiled images is a speed-critical task. By default, this is done using routines from the *IntfGraphics* unit; the corresponding drawing engine is in the `TMvInfGraphicsDrawingEngine` class. However, it is possible to provide a different drawing engine here. The standard installation of *LazMapViewer* comes with the alternative `TMvRGBGraphicsDrawingEngine` which is based on the *RGBGraphics* package, and with the `TMvBGRADrawingEngine` utilizing the *BGRABitmap* package. | |
| 113 | 107 | - `MapProvider (string)`: This string identifies the provider from which the maps are downloaded. Built-in providers allow to choose between *OpenStreetMaps*, *GoogleMaps*, *Virtual Earth*, *Yandex* etc. Details are given in section Map Providers. | |
| 114 | 108 | - `Options = [mvoMouseDragging, mvoMouseZooming]`: Allows to disable dragging of the map with the mouse and zooming with the mouse wheel when the corresponding option is removed from the set (in v0.2.7 and newer). Default: both options active. | |
| 115 | 109 | - `UseThreads (boolean)`: When set to `true` downloading and drawing of maps is delegated to several threads in order to achieve a smoother response. It is not recommended to turn this property off. | |
| 116 | 110 | - `Zoom (integer)`: Magnfication of the map: 0 = coarsest magnification, earth view, 17 or 18 = highest magnification. Each zoom step results in doubling of the magnfication factor. | |
| 117 | 111 | - `ZoomToCursor (boolean)`: When this is `true` zooming occurs relative to the mouse position, otherwise to the center of the map. This feature is interesting for zooming with the mouse wheel. | |
| 118 | 112 | ||
| 119 | 113 | Here are properties related to overlayed GPS objects (points of interest, tracks): | |
| 120 | 114 | ||
| 121 | 115 | - `GPSItems: TGPSObjectList`: list of GPS objects assigned to the MapView See below for details. | |
| 122 | 116 | - `DefaultTrackColor: TColor`, `DefaultTrackWidth: Integer`: the default color and line width, respectively, of overlayed tracks. See below for details. | |
| 123 | 117 | - `POIImage: TBitmap`: bitmap which will be overlayed to identify a "point of interest" (POI). | |
| 124 | 118 | - `POITextBgColor: TColor`: background color of the overlayed text describing a point of interest. Turn off the text background by selecting `clNone`. | |
| 125 | 119 | ||
| 126 | 120 | #### Events | |
| 127 | 121 | ||
| 128 | 122 | - `OnCenterMove`: fires whenever the `Center` of the `MapView` have been changed. | |
| 129 | 123 | - `OnChange`: fires whenever the `Center`, size or `Zoom` factor of the `MapView` change. | |
| 130 | 124 | - `OnDrawGpsPoint`: see below | |
| 131 | 125 | - `OnZoomChange`: fires whenever the `Zoom` factor of the `MapView` changes. | |
| 132 | 126 | - `OnMouseDown, OnMouseEnter, OnMouseLeave, OnMouseMove, OnMouseUp`: standard mouse events. | |
| 133 | 127 | ||
| 134 | 128 | #### Main methods | |
| 135 | 129 | ||
| 136 | 130 | - `procedure GetMapProviders(lstProviders: TStrings)`: Returns in `lstProviders` the names of all registered map providers. When one of these strings is assigned to the `MapProvider` property of the `MapVieew` the servers of the corresponding provider will become the source of the displayed maps. | |
| 137 | 131 | - `function GetVisibleArea: TRealArea`: returns the top/left and bottom/right corner points of the displayed rectangle in geo coordinates. `TRealArea` is a record consisting of the `TRealPoint` records `TopLeft` and `BottomRight`. | |
| 138 | 132 | - `function LonLatToScreen(aPt: TRealPoint): TPoint`: maps a geo point (longitude, latitude) to screen pixels (relative to the `TMapView` instance). | |
| 139 | 133 | - `function ScreenToLonLat(aPt: TPoint): TRealPoint`: maps a the coordinates of a screen pixel (relative to the `MapView` instance) to geo coordinates (longitude, latitude). Here is an example how the geo coordinates of the mouse cursor can be displayed in two labels by means of the `OnMouseMove` event of the `MapView`: | |
| 140 | 134 | ||
| 141 | 135 | ``` Pascal | |
| 142 | 136 | uses | |
| 143 | 137 | mvTypes, // for TRealPoint | |
| 144 | 138 | mvEngine; // for LonToStr() and LatToStr() funtions | |
| 145 | 139 | ||
| 146 | 140 | procedure TForm1.MapView1MouseMove(Sender: TObject; Shift: TShiftState; | |
| 147 | 141 | X, Y: Integer); | |
| 148 | 142 | var | |
| 149 | 143 | P: TRealPoint; | |
| 150 | 144 | begin | |
| 151 | 145 | P := MapView1.ScreenToLonLat(Point(X, Y)); | |
| 152 | 146 | Label1.Caption := 'Longitude: ' + LonToStr(P.Lon, true); | |
| 153 | 147 | Label2.Caption := 'Latitude: ' + LatToStr(P.Lat, true); | |
| 154 | 148 | end; | |
| 155 | 149 | ``` | |
| 156 | 150 | ||
| 157 | 151 | - `procedure SaveToFile(AClass: TRasterImageClass; const AFileName: String)`: Save the currently displayed map as bitmap of the given class to a file. Example for saving to a jpg image: | |
| 158 | 152 | ||
| 159 | 153 | ``` Pascal | |
| 160 | 154 | procedure TForm1.Button1Click(Sender: TObject); | |
| 161 | 155 | begin | |
| 162 | 156 | MapView1.SaveToFile(TJpegImage, 'mapview.jpg'); | |
| 163 | 157 | end; | |
| 164 | 158 | ``` | |
| 165 | 159 | ||
| 166 | 160 | - `procedure SaveToStream(AClass: TRasterImageClass; AStream: TStream)`: Similar to `SaveToFile`, but output is not in a file, but in the stream provided. | |
| 167 | 161 | - `function SaveToImage(AClass: TRasterImageClass): TRasterImage`: creates an instance of the given image class and writes the currently visible view port image to it. | |
| 168 | 162 | - `procedure CenterOnObj(obj: TGPSObj)`: Centers the map on the provided GPS object. More on GPS objects below. | |
| 169 | 163 | - `procedure ZoomOnArea(const aArea: TRealArea)`: Adjusts the `Zoom` level such that the given area is completely shown and fills the component bounds as much as possible. | |
| 170 | 164 | - `procedure ZoomOnObj(obj: TGPSObj)`: Adjusts the `Zoom` level such that the given GPS object is completely seen at highest magnification. More about GPS objects below. | |
| 171 | 165 | ||
| 172 | 166 | ### Map Providers | |
| 173 | 167 | ||
| 174 | 168 | 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. | |
| 175 | 169 | ||
| 176 | 170 | Here is a list of the names of the built-in map providers: | |
| 177 | 171 | ||
| 178 | 172 | - OpenStreetMap Mapnik | |
| 179 | 173 | - OpenStreetMap Wikipedia | |
| 180 | 174 | - OpenStreetMap Sputnik | |
| 181 | 175 | - OpenStreetMap.fr Hot | |
| 182 | 176 | - OpenStreetMap.fr Cycle Map | |
| 183 | 177 | - Open Topo Map | |
| 184 | 178 | - Google Maps | |
| 185 | 179 | - Google Satellite | |
| 186 | 180 | - Yandex.Maps | |
| 187 | 181 | - Yandex.Maps Satellite | |
| 188 | 182 | - Virtual Earth Bing | |
| 189 | 183 | - Virtual Earth Aerial | |
| 190 | 184 | - Virtual Earth Hybrid | |
| 191 | 185 | ||
| 192 | 186 | 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. | |
| 193 | 187 | ||
| 194 | 188 | - Registration at <https://www.thunderforest.com/docs/apikeys/>, store API key in the variable `ThunderForest_ApiKey`: | |
| 195 | 189 | - Open Cycle Map | |
| 196 | 190 | - OpenStreetMap Transport | |
| 197 | 191 | - Registration at <https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account>, store the received APP ID and APP CODE in the variables `HERE_AppID` and `HERE_AppCode`, respectively: | |
| 198 | 192 | - Here WeGo Map | |
| 199 | 193 | - Here WeGo Grey Map | |
| 200 | 194 | - Here WeGo Reduced Map | |
| 201 | 195 | - Here WeGo Transit Map | |
| 202 | 196 | - Here WeGo POI Map | |
| 203 | 197 | - Here WeGo Pedestrian Map | |
| 204 | 198 | - Here WeGo DreamWorks Map | |
| 205 | 199 | - Registration at <https://home.openweathermap.org/users/sign_up>, store the API Key in variable `OpenWeatherMap_ApiKey`: | |
| 206 | 200 | - OpenWeatherMap Clouds | |
| 207 | 201 | - OpenWeatherMap Precipitation | |
| 208 | 202 | - OpenWeatherMap Pressure | |
| 209 | 203 | - OpenWeatherMap Temperature | |
| 210 | 204 | - OpenWeatherMap Wind | |
| 211 | 205 | ||
| 212 | 206 | Please respect the license requirements of the map providers. | |
| 213 | 207 | ||
| 214 | 208 | ### GPS Objects | |
| 215 | 209 | ||
| 216 | 210 | 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 | |
| 217 | 211 | ||
| 218 | 212 | ``` Pascal | |
| 219 | 213 | type | |
| 220 | 214 | TGPSObj = class | |
| 221 | 215 | ... | |
| 222 | 216 | public | |
| 223 | 217 | destructor Destroy; override; | |
| 224 | 218 | property Name: String read FName write FName; | |
| 225 | 219 | property ExtraData: TObject read FExtraData write SetExtraData; | |
| 226 | 220 | property IdOwner: Integer read FIdOwner; | |
| 227 | 221 | property BoundingBox: TRealArea read GetBoundingBox write SetBoundingBox; | |
| 228 | 222 | end; | |
| 229 | 223 | ``` | |
| 230 | 224 | ||
| 231 | 225 | The `Name` can be displayed near the item in the map. | |
| 232 | 226 | ||
| 233 | 227 | `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`. | |
| 234 | 228 | ||
| 235 | 229 | `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. | |
| 236 | 230 | ||
| 237 | 231 | #### Points | |
| 238 | 232 | ||
| 239 | 233 | A special `TGPSObj` item is a `TGPSPoint`, for example a scenic "Point-of-Interest" (POI), a way point along a hiking path etc. | |
| 240 | 234 | ||
| 241 | 235 | ``` Pascal | |
| 242 | 236 | TGPSPoint = class(TGPSObj) | |
| 243 | 237 | public | |
| 244 | 238 | constructor Create(ALon,ALat: double; AEle: double=NO_ELE; ADateTime: TDateTime=NO_DATE); | |
| 245 | 239 | class function CreateFrom(aPt: TRealPoint): TGPSPoint; | |
| 246 | 240 | ||
| 247 | 241 | function HasEle: boolean; | |
| 248 | 242 | function HasDateTime: Boolean; | |
| 249 | 243 | function DistanceInKmFrom(OtherPt: TGPSPoint; UseEle: boolean=true): double; | |
| 250 | 244 | ||
| 251 | 245 | property Lon: Double read GetLon; | |
| 252 | 246 | property Lat: Double read GetLat; | |
| 253 | 247 | property Ele: double read FEle; | |
| 254 | 248 | property DateTime: TDateTime read FDateTime; | |
| 255 | 249 | property RealPoint: TRealPoint read FRealPt; | |
| 256 | 250 | end; | |
| 257 | 251 | ``` | |
| 258 | 252 | ||
| 259 | 253 | 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. | |
| 260 | 254 | ||
| 261 | 255 | #### Tracks | |
| 262 | 256 | ||
| 263 | 257 | 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. | |
| 264 | 258 | ||
| 265 | 259 | ``` Pascal | |
| 266 | 260 | type | |
| 267 | 261 | TGPSTrack = class(TGPSObj) | |
| 268 | 262 | private | |
| 269 | 263 | FDateTime: TDateTime; | |
| 270 | 264 | FPoints: TGPSPointList; | |
| 271 | 265 | function GetDateTime: TDateTime; | |
| 272 | 266 | public | |
| 273 | 267 | constructor Create; | |
| 274 | 268 | destructor Destroy; override; | |
| 275 | 269 | ||
| 276 | 270 | procedure GetArea(out Area: TRealArea); override; | |
| 277 | 271 | function TrackLengthInKm(UseEle: Boolean=true): double; | |
| 278 | 272 | ||
| 279 | 273 | property Points: TGPSPointList read FPoints; | |
| 280 | 274 | property DateTime: TDateTime read GetDateTime write FDateTime; | |
| 281 | 275 | end; | |
| 282 | 276 | ``` | |
| 283 | 277 | ||
| 284 | 278 | #### List of GPS Objects | |
| 285 | 279 | ||
| 286 | 280 | The property `GpsItems` of the `TMapView` component is the main class collecting all the GPS objects. It is an instance of the `TGPSObjectList`: | |
| 287 | 281 | ||
| 288 | 282 | ``` Pascal | |
| 289 | 283 | type | |
| 290 | 284 | TGPSObjectList = class(TGPSObj) | |
| 291 | 285 | ... | |
| 292 | 286 | constructor Create; | |
| 293 | 287 | destructor Destroy; override; | |
| 294 | 288 | ||
| 295 | 289 | Procedure Clear(OwnedBy: integer); | |
| 296 | 290 | procedure ClearExcept(OwnedBy: integer; const ExceptLst: TIdArray; out Notfound: TIdArray); | |
| 297 | 291 | procedure GetArea(out Area: TRealArea); override; | |
| 298 | 292 | function GetObjectsInArea(const Area: TRealArea): TGPSObjList; | |
| 299 | 293 | function GetIdsArea(const Ids: TIdArray; AIdOwner: integer): TRealArea; | |
| 300 | 294 | ||
| 301 | 295 | function Add(aItem: TGpsObj; AIdOwner: integer): integer; | |
| 302 | 296 | procedure DeleteById(const Ids: Array of integer); | |
| 303 | 297 | ||
| 304 | 298 | procedure BeginUpdate; | |
| 305 | 299 | procedure EndUpdate; | |
| 306 | 300 | ||
| 307 | 301 | property Count: integer read GetCount; | |
| 308 | 302 | property Items[AIndex: Integer]: TGpsObj read GetItem; default; | |
| 309 | 303 | ||
| 310 | 304 | property OnModified: TModifiedEvent read FOnModified write FOnModified; | |
| 311 | 305 | end; | |
| 312 | 306 | ``` | |
| 313 | 307 | ||
| 314 | 308 | 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. | |
| 315 | 309 | ||
| 316 | 310 | 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. | |
| 317 | 311 | ||
| 318 | 312 | `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). | |
| 319 | 313 | ||
| 320 | 314 | #### Example: Adding a Point of Interest | |
| 321 | 315 | ||
| 322 | 316 | 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`: | |
| 323 | 317 | ||
| 324 | 318 | ``` Pascal | |
| 325 | 319 | uses | |
| 326 | 320 | mvTypes, mvGPSObj; | |
| 327 | 321 | ||
| 328 | 322 | const | |
| 329 | 323 | _POI_ = 10; | |
| 330 | 324 | ||
| 331 | 325 | procedure TForm1.MapView1MouseUp(Sender: TObject; Button: TMouseButton; | |
| 332 | 326 | Shift: TShiftState; X, Y: Integer); | |
| 333 | 327 | var | |
| 334 | 328 | pt: TRealPoint; | |
| 335 | 329 | gpsPt: TGpsPoint; | |
| 336 | 330 | ptName: String; | |
| 337 | 331 | begin | |
| 338 | 332 | ptName := ''; | |
| 339 | 333 | if InputQuery('Point of Interest', 'Enter name:', ptName) then | |
| 340 | 334 | begin | |
| 341 | 335 | pt := MapView1.ScreenToLonLat(Point(X, Y)); | |
| 342 | 336 | gpsPt := TGpsPoint.CreateFrom(pt, NO_ELE, Now() ); | |
| 343 | 337 | gpsPt.Name := ptName; | |
| 344 | 338 | Mapview1.GPSItems.Add(gpsPt, _POI_); | |
| 345 | 339 | end; | |
| 346 | 340 | end; | |
| 347 | 341 | ``` | |
| 348 | 342 | ||
| 349 | 343 | 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). | |
| 350 | 344 | ||
| 351 | 345 | 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: | |
| 352 | 346 | ||
| 353 | 347 | ``` Pascal | |
| 354 | 348 | procedure TForm1.MapView1DrawGpsPoint(Sender: TObject; | |
| 355 | 349 | ADrawer: TMvCustomDrawingEngine; APoint: TGpsPoint); | |
| 356 | 350 | const | |
| 357 | 351 | R = 8; | |
| 358 | 352 | var | |
| 359 | 353 | p: TPoint; | |
| 360 | 354 | begin | |
| 361 | 355 | // Screen coordinates of the GPS point | |
| 362 | 356 | p := MapView1.LonLatToScreen(APoint.RealPoint); | |
| 363 | 357 | ||
| 364 | 358 | // Draw a blue circle | |
| 365 | 359 | ADrawer.PenColor := clBlack; | |
| 366 | 360 | ADrawer.BrushColor := clBlue; | |
| 367 | 361 | ADrawer.BrushStyle := bsSolid; | |
| 368 | 362 | ADrawer.Ellipse(p.X-R, p.Y-R, P.X+R, p.Y+R); | |
| 369 | 363 | ||
| 370 | 364 | // Draw the point label | |
| 371 | 365 | ADrawer.BrushStyle := bsClear; | |
| 372 | 366 | ADrawer.FontName := 'SegoeUI'; | |
| 373 | 367 | ADrawer.FontSize := 16; | |
| 374 | 368 | ADrawer.FontStyle := [fsBold]; | |
| 375 | 369 | ADrawer.TextOut( | |
| 376 | 370 | p.X - ADrawer.TextWidth(APoint.Name) div 2, | |
| 377 | 371 | p.Y + R + 4, | |
| 378 | 372 | APoint.Name | |
| 379 | 373 | ); | |
| 380 | 374 | end; | |
| 381 | 375 | ``` | |
| 382 | 376 | ||
| 383 | 377 | ## Finding Geo Locations: TMvGeoNames | |
| 384 | 378 | ||
| 385 | 379 | `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. | |
| 386 | 380 | ||
| 387 | - | ||
| 388 | - | ||
| 389 | - | ||
| 390 | - | ||
| 381 | + |  | |
| 391 | 382 | ||
| 392 | 383 | ### Getting Started | |
| 393 | 384 | ||
| 394 | 385 | - Assuming that you already have set up an application for the `TMapView` component as described above, you simply drop a `TMvGeoNames` component on the form; it is located next to the `TMapView` icon in the *Misc* component palette. | |
| 395 | 386 | - Add a button which is supposed to trigger the search. | |
| 396 | 387 | - Write an `OnClick` handler for the button which calls the `TMvGeoNames` method `Search`. Enter the search destination as first parameter, and the download engine to be used as second parameter. The function returns the found longitude and latitude as a `TRealPoint` record which can be passed immediately to the `Center` property of the `MapView` component. This way, the viewer can immediately jump to the found location: | |
| 397 | 388 | ||
| 398 | 389 | ``` pascal | |
| 399 | 390 | procedure TForm1.Button1Click(Sender: TObject); | |
| 400 | 391 | begin | |
| 401 | 392 | MapView1.Center := MvGeoNames1.Search('Grand Canyon National Park', MapView1.DownloadEngine); | |
| 402 | 393 | end; | |
| 403 | 394 | ``` | |
| 404 | 395 | ||
| 405 | 396 | ### Documentation | |
| 406 | 397 | ||
| 407 | 398 | #### Methods | |
| 408 | 399 | ||
| 409 | 400 | - `function Search(ALocationName: String; ADownloadEngine: TMvCustomDownloadEngine): TRealPoint`: searches the requested location using the specified download engine. Return value are the geo coordinates of the location given as a `TRealPoint`. The search returns also locations with similar names, however, they must be extracted by handling the `OnNameFound` event. | |
| 410 | 401 | ||
| 411 | 402 | #### Properties | |
| 412 | 403 | ||
| 413 | 404 | - `LocationName: string`: Is the name of the (first) found location as listed by the *geonames* site. | |
| 414 | 405 | ||
| 415 | 406 | #### Events | |
| 416 | 407 | ||
| 417 | 408 | - `OnNameFound`: This event is triggered while the received response of the *geonames* server is being analyzed. The html string usually contains a variety of locations. Whenver a location has been extracted from the received string the event is fired and tells the name, a description, and the longitude/latitude `TRealPoint` record for this location. Handling this event makes it possible to list all the found locations for example in a combobox or listbox to give the user the opportunity to select any one of them: | |
| 418 | 409 | ||
| 419 | 410 | ``` pascal | |
| 420 | 411 | type | |
| 421 | 412 | TGeoLocation = class | |
| 422 | 413 | Name: String; | |
| 423 | 414 | Descr: String; | |
| 424 | 415 | Coords: TRealPoint; | |
| 425 | 416 | end; | |
| 426 | 417 | ||
| 427 | 418 | procedure TForm1.MVGeoNames1NameFound(const AName: string; | |
| 428 | 419 | const ADescr: String; const ALoc: TRealPoint); | |
| 429 | 420 | var | |
| 430 | 421 | loc: TGeoLocation; | |
| 431 | 422 | begin | |
| 432 | 423 | loc := TGeoLocation.Create; | |
| 433 | 424 | loc.Name := AName; | |
| 434 | 425 | loc.Descr := ADescr; | |
| 435 | 426 | loc.Coords := ALoc; | |
| 436 | 427 | ComboBox1.Items.AddObject(AName, loc); | |
| 437 | 428 | end; | |
| 438 | 429 | ``` | |
| 439 | 430 | ||
| 440 | 431 | --- | |
| 441 | 432 | *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](/wiki-contact).* |
