Recent

Author Topic: Very rough version of a shape file viewer.  (Read 1329 times)

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Very rough version of a shape file viewer.
« on: June 05, 2026, 09:02:17 pm »
Hi,

I made a first start with a viewer that can open Esri shapes and read the data. It is a very very rough version and more intended as an exercise. This has to be set up properly (the view separated from the data etc.)
I have added 1 simple shape file if anyone wants to watch. It Uses LazMapViewer.


What is roughly possible now:
  • Open shapefiles (all types: point, line, polygon, 3D B/M)
  • Automatic.prj detection and coordinate conversion (RD New → WGS84) (For now only the Dutch coordinate system)
  • Multi-layer system with unique colors per layer
  • Layer management (turn on/off via CheckListBox)
  • DBF attributes in DBGrid Click on map → selection + DBF data in Memo Clicking in DBGrid → map centers on object
  • Hit-testing for points, lines and polygons

Xenno

  • Full Member
  • ***
  • Posts: 131
    • BS Programs
Re: Very rough version of a shape file viewer.
« Reply #1 on: June 06, 2026, 10:19:04 am »
Hello, @Hansvb

This is awesome! A little request or a suggestion, is it possible the ShapeReader or TSimpleShapefile use some trick to avoid ANR flag from OS when loading large SHP files? I tested to load 25 MB SHP and I have more larger ones.
Lazarus 4.6, Windows 10, https://www.youtube.com/@bsprograms
If I want to share, I give. If I want money, I sell. I don't set traps.

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Re: Very rough version of a shape file viewer.
« Reply #2 on: June 06, 2026, 11:21:57 am »
Hi,
I don't know yet. This is a very simple version to see if I could make some kind of viewer. There is still a lot to be done. I even quickly put the components on the form.
While building I used a small shape files with a few hundred records. I will test it with larger shapes soon. What I also want to work on is being able to mutate shapes and after that see if a geopackage is possible. That is a real open source gis format.

I'm glad you like it, that gives motivation to take this further. Maybe I'll put it on something like github when I'm a little further

Xenno

  • Full Member
  • ***
  • Posts: 131
    • BS Programs
Re: Very rough version of a shape file viewer.
« Reply #3 on: June 06, 2026, 12:40:32 pm »
I only familiar with TThread, I imagine a separated thread reading the shape file and fires a OnNewShape event for each shape found for the caller to keep. While avoiding ANR flag it could also an opportunity to abort.

For a 91 MB SHP file, your program only takes 59 MB memory here in my Win10-64. Very reasonable for the capability to multi layers/SHPs and the power of LazMapViewer.

A simple suggestion on the splitter, you may want to set its ResizeStyle to rsPattern. Nonetheless, I believe you would this program more sophisticated and practical. Non-techy bosses would very happy they could play geostatistical reports themselves.
Lazarus 4.6, Windows 10, https://www.youtube.com/@bsprograms
If I want to share, I give. If I want money, I sell. I don't set traps.

Xenno

  • Full Member
  • ***
  • Posts: 131
    • BS Programs
Re: Very rough version of a shape file viewer.
« Reply #4 on: June 06, 2026, 02:28:47 pm »
A rough idea:

Code: Pascal  [Select][+][-]
  1.   TSHPFeatureFoundEvent = procedure (NewFeature: TSimpleFeature) of object;
  2.  
  3.  
  4.   TShapeReaderThread = class(TThread)
  5.   private
  6.     FFileName: String;
  7.     FBoundingBoxMaxX: Double;
  8.     FBoundingBoxMaxY: Double;
  9.     FBoundingBoxMinX: Double;
  10.     FBoundingBoxMinY: Double;
  11.     FOnFeatureFound: TSHPFeatureFoundEvent;
  12.     FSuccess: Boolean;
  13.     procedure ReadHeader(fs: TFileStream);
  14.     function ReadInt32BE(fs: TFileStream): Integer;
  15.     function ReadInt32LE(fs: TFileStream): Integer;
  16.     function ReadDoubleLE(fs: TFileStream): Double;
  17.     procedure SkipDoubles(fs: TFileStream; Count: Integer);
  18.     procedure SyncOnFound;
  19.   protected
  20.     procedure Execute; override;
  21.   public
  22.     constructor Create(const FName: String);
  23.     // properties to read in OnTerminate
  24.     property Success: Boolean read FSuccess;    
  25.     property ErrorMessage: String read FErrorMessage;
  26.     property BoundingBoxMinX: Double read FBoundingBoxMinX;
  27.     property BoundingBoxMinY: Double read FBoundingBoxMinY;
  28.     property BoundingBoxMaxX: Double read FBoundingBoxMaxX;
  29.     property BoundingBoxMaxY: Double read FBoundingBoxMaxY;
  30.     // event fires with Synchronize
  31.     property OnFeatureFound: TSHPFeatureFoundEvent read FOnFeatureFound write FOnFeatureFound;
  32.     // or several features at once; fires in an interval with Synchronize
  33.     // property OnFeaturesFound: TSHPFeaturesFoundEvent read FOnFeaturesFound write FOnFeaturesFound;
  34.   end;
  35.  
  36.  
  37.   TSimpleShapefileWithThread = class
  38.   private
  39.     fFeatures: TObjectList;
  40.     FOnLoaded: TNotifyEvent;
  41.     // event handler for thread
  42.     procedure ShapeReaderFeatureFound(NewFeature: TSimpleFeature);
  43.     // or several features at once
  44.     // procedure ShapeReaderFeaturesFound(NewFeatureList: TObjectList);
  45.     procedure ShapeReaderTerminate(Sender: TObject);
  46.   public
  47.     BoundingBoxMinX, BoundingBoxMinY, BoundingBoxMaxX, BoundingBoxMaxY: Double;
  48.     constructor Create;
  49.     destructor Destroy; override;    
  50.     procedure LoadFromFile(const AFileName: string);
  51.     property Features: TObjectList read fFeatures;
  52.     property OnLoaded: TNotifyEvent read FOnLoaded write FOnLoaded;
  53.   end;
Lazarus 4.6, Windows 10, https://www.youtube.com/@bsprograms
If I want to share, I give. If I want money, I sell. I don't set traps.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12942
  • FPC developer.
Re: Very rough version of a shape file viewer.
« Reply #5 on: June 06, 2026, 02:37:44 pm »
A rough idea:

Functions added to tstream by helper in streamex:
Quote
    function  ReadWordLE :word;
    function  ReadDWordLE:dword;
    function  ReadQWordLE:qword;
    procedure WriteWordLE (w:word);
    procedure WriteDWordLE(dw:dword);
    procedure WriteQWordLE(dq:qword);
    function  ReadWordBE :word;
    function  ReadDWordBE:dword;
    function  ReadQWordBE:qword;
    procedure WriteWordBE (w:word);
    procedure WriteDWordBE(dw:dword);
    procedure WriteQWordBE(dq:qword);
    function  ReadSingle:Single;
    function  ReadDouble:Double;
    procedure WriteSingle(s:Single);
    procedure WriteDouble(d:double);

stream.readwordBE etc.

Xenno

  • Full Member
  • ***
  • Posts: 131
    • BS Programs
Re: Very rough version of a shape file viewer.
« Reply #6 on: June 06, 2026, 03:01:55 pm »
Thank you, @marcov. That's great. Similar functions already available. That rough idea is based on the original code of this shape file viewer.
Lazarus 4.6, Windows 10, https://www.youtube.com/@bsprograms
If I want to share, I give. If I want money, I sell. I don't set traps.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12942
  • FPC developer.
Re: Very rough version of a shape file viewer.
« Reply #7 on: June 06, 2026, 03:56:13 pm »
Same with bounding box stuff, that is TRectF.  However I'm not entirely sure how much of it is in 3.2.2.

The fixes branch (and even the older RC1) do probably have all of it.

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Re: Very rough version of a shape file viewer.
« Reply #8 on: June 06, 2026, 04:36:42 pm »
Before I can continue I have an error to fix. I see that donuts in the polygon surfaces are also filled. That is not allowed. For Windows, I almost changed that. But I want to get that working for Linux as well. In the meantime I added panning with the middle mouse button and arrow keys.

1 thing is still bothering me. I use a TPaintBox as an overlay to get the polygons visible. I do that because I couldn't find a function for that in LazMapViewer. But actually that's a shame. Panning is now unnecessarily difficult. (Have to build it yourself instead of being able to use panning from the lazmapviewer. But for now it works).

I've never used threads before so it will take a while before I get that in to improve loading. :-[

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Re: Very rough version of a shape file viewer.
« Reply #9 on: June 06, 2026, 08:56:35 pm »
The shape viewer (still just a proof of concept) has been expanded a bit more with a few new features:
  • Bug fix. Donuts are no longer filled. (windows only for now).
  • Middle mouse button panning and pan with the arrow keys
  • Move layers up and down. Drawing order of the layers shifts too. (Select the shape name, mouse right-click)
  • Removing layer also works now.
  • You can change the color of the layer. (Select the layer, right-click change properties) This is more of a proof of concept.
  • Dutch converted to English as much as possible. Must have forgotten something  :)


 
 



hedgehog

  • Full Member
  • ***
  • Posts: 130
Re: Very rough version of a shape file viewer.
« Reply #10 on: June 07, 2026, 08:24:00 am »
Hi, Hans!

I'm not very familiar with the MapViewer component, but my idea is to use the AfterPaint event to draw the Shapefile.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.MapView1AfterPaint(Sender: TObject);
  2. begin
  3.   DrawShapefileOnCanvas(MapView1.Canvas);
  4. end;  

I remove PaintBox and everything seems to be working as intended.

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Re: Very rough version of a shape file viewer.
« Reply #11 on: June 13, 2026, 11:48:04 am »
I converted the code to a simple MVP setup. ((Yet) not the robust MVP setup of cdbc). Other than that, it still does the same functionally as the previous version. This will be a "stop job project". I now have an idea for a tool that I can use for my work. I'm going to start with that first.

hedgehog

  • Full Member
  • ***
  • Posts: 130
Re: Very rough version of a shape file viewer.
« Reply #12 on: June 14, 2026, 07:21:25 am »
Hello, @Hansvb

Longitude panning is broken in this version (Windows 10)
I fixed it as follows:
Code: Pascal  [Select][+][-]
  1. procedure TShapePresenter.DoPan(const DeltaX, DeltaY: Integer);
  2. ..........
  3.   if Abs(CenterLat) >= 89.0 then
  4.     DegPerPixelLat:= DegPerPixelLon
  5.   else
  6.     DegPerPixelLat:= DegPerPixelLon / cos(DegToRad(CenterLon))/pi*2; // <<<---- this
  7. ..........

One more question: I still don't understand why you need a PaintBox.

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Re: Very rough version of a shape file viewer.
« Reply #13 on: June 14, 2026, 12:44:31 pm »
Hi,
DoPan worked well for me, Win 11. I see no difference with the existing and new code line. Where I still have trouble with is that panning is way too slow. With a somewhat larger shape it no longer works well.
The paintbox came in because in the beginning I kept "losing" the geometry as soon as mapviewer updated. By putting a paintbox on top of it, I got rid of that. And later I didn't look at whether it can be done without a paintbox. And because I'm now running into a max zoom level, I'll leave the paintbox for a while. I haven't yet checked whether it is possible to zoom in further when the map viewer turns off.

Hansvb

  • Hero Member
  • *****
  • Posts: 929
Re: Very rough version of a shape file viewer.
« Reply #14 on: June 27, 2026, 07:58:06 am »
Hi,

I started completely over again and almost back to the point that the new setup can do the same as the first setup. Yesterday I tested it on Linux for the first time and only now really understand what is meant by the ANR flag. So I have to look at loading files. I have more challenges. I can zoom in far now, but when I zoom out far there is still some speed to gain. (I use allready methods to simplify geometry) To be able to zoom in far, I now load an openstreetmap wms myself. (Left LazMapViewer) To get that faster I have to start using threads. Ditto for reading the geojson files. So it's about time I try threads for the first time.
I have also been experimenting with an "event bus" like construction. With that I do a progress bar but that turns out to be a bad idea. In windows the bar never reaches 100% (except during debugging) and under Linux it goes to 100% way too fast with exactly the same code.

 

TinyPortal © 2005-2018