Natural Earth Data

For a recent project I needed to produce a globe display, similar to Google Earth. However, it needed to be completely embedded and not require an active internet connection.  To keep it compact, I wanted a good quality vector dataset for national boundaries.  It needed to be under a liberal licence so that I could modify it if needed.  It also had to be free from any licence tracking requirements and permit distribution with my application.

Fortunately my research lead me to discover the Natural Earth project.  It contains exactly what I needed and more besides, in both vector and tiled raster formats.  It is released into the public domain and so its reuse is completely unrestricted.

In the 1:10M cultural vector data is an 8.2Mb shape file containing country multi-polygons:  ne_10m_admin_0_countries.shp.  With line simplification this could be reduced to just under 1Mb as Well Known Text and when Z compressed reduced further to 334Kb. This was then directly linked as a resource file into the application.  The built test program itself was 2.5Mb (Linux 64bit GTK2) with no additional external dependencies.

Globe

So if you need good quality global mapping data, supplied under liberal licensing terms, I strongly recommend that you investigate the Natural Earth website.

Lazarus Cross-platform Fullscreen Support

I’m currently working on fast bitmap techniques for Lazarus, for which I will be posting a separate article in the future. However, whilst working on this I have encountered an old bug-bear of mine, implementing full-screen support. If your not familiar with the concept, most browsers now support this mode of operation, where they can take over use of the whole screen, removing all traces of the operating system from the display. This is also common in computer games and video players. It is very likely that the browser you are reading this in supports this feature. On PCs pressing F11 should swap into and out of fullscreen mode.

In Lazarus’ LCL library there is now an additional WindowState property for forms of wsFullScreen. This aims to simplify the process of taking over control of the whole display in a cross-platform manner for all LCL based applications. A naive use of this technique within a Lazarus application would look like this:

Unit Main;

{$mode objfpc}{$H+}

Interface

Uses
  Classes, SysUtils, FileUtil, Forms,
  Controls, Graphics, Dialogs, StdCtrls;

Type
  TMainForm = Class(TForm)
    FullscreenButton: TButton;
    RestoreButton: TButton;
    Procedure FullscreenButtonClick(Sender: TObject);
    Procedure RestoreButtonClick(Sender: TObject);
  End;

Var
  MainForm: TMainForm;

Implementation

{$R *.lfm}

Procedure TMainForm.FullscreenButtonClick(Sender: TObject);
Begin
  WindowState := wsFullScreen;
End;

Procedure TMainForm.RestoreButtonClick(Sender: TObject);
Begin
  WindowState := wsNormal;
End;

End.


This works perfectly on Linux(QT), but on Windows the form border is not hidden in fullscreen mode and worse still Linux(GTK2) completely fails to restore the window. No doubt these are teething problems that will be resolved in due course, but it is frustrating if you want to create a reliable cross-platform solution using the LCL framework. Fortunately, there are a couple of simple tweaks that can be applied to this code to make it work reliably across the main Lazarus target platforms.

Firstly, the GTK2 failure to restore seems to be due to the WindowState change not actually being applied. The trick here is to change the state to maximized immediately before the change to normal. This persuades GTK2 to do the right thing without adversely effecting the other platforms. So the restore procedure now looks like this:


Procedure TMainForm.RestoreButtonClick(Sender: TObject);
Begin
  WindowState := wsMaximized;
  WindowState := wsNormal;
End;

To deal with the failure to remove the border on Windows, we have to do that explicitly using the BorderStyle property. This leads to the procedures looking like this:


Procedure TMainForm.FullscreenButtonClick(Sender: TObject);
Begin
  BorderStyle := bsNone;
  WindowState := wsFullScreen;
End;

Procedure TMainForm.RestoreButtonClick(Sender: TObject);
Begin
  WindowState := wsMaximized;
  WindowState := wsNormal;
  BorderStyle := bsSizeable;
End;

Unfortunately, changing the border style interferes with the position of the restored window. So to tidy this up, the BoundsRect of the window needs to be recorded prior to changing to fullscreen, then set again upon restoration. I like to wrap this behaviour in an auto-checking Action so that it can be associated with a keyboard short cut (F11). Thus, the final routine I use in production code looks like this:


Var
  WindowRect: TRect;

Procedure TMainForm.FullscreenActionExecute(Sender: TObject);
Begin
  Begin
    If FullscreenAction.Checked Then
      Begin
        WindowRect := BoundsRect;
        BorderStyle := bsNone;
        WindowState := wsFullScreen;
      End
    Else
      Begin
        BorderStyle := bsSizeable;
        WindowState := wsMaximized;
        WindowState := wsNormal;
        BoundsRect := WindowRect;
      End;
  End;
End;