Recent

Author Topic: LazMapView - adding a scale  (Read 1532 times)

wschulte

  • New Member
  • *
  • Posts: 34
LazMapView - adding a scale
« on: November 28, 2024, 03:51:09 pm »
I am playing around with the LazMapViewer (0.2.7) and it works as a charm. I want to use it in a project, but first want to play around a bit.
Most is pretty straightforward, except one thing: how to implement a ruler line (indicating a distance) ?
Just writing to th canvas doesn't work of course. But adding a track as such a line is quite tedious: it has to be updated with every move and or zoom.
Is there a way to tie such a line to a fixed position in the view (eg. bottom right) ?

alpine

  • Hero Member
  • *****
  • Posts: 1315
Re: LazMapView - adding a scale
« Reply #1 on: December 01, 2024, 12:51:22 pm »
You can put a TPanel on top of the map view, anchor it at the bottom right corner with some offset. Then, assuming the name of the map view is MapView and the panel is Ruler, put at Ruler.OnPaint something like this:
Code: Pascal  [Select][+][-]
  1. procedure TMainForm.RulerPaint(Sender: TObject);
  2. var
  3.   LPt, RPt: TRealPoint;
  4.   Dist, V: Double;
  5.   Digits: Integer;
  6.   Km: Boolean = False;
  7. begin
  8.   LPt := MapView.ScreenToLatLon(Ruler.ClientToParent(Point(0, Ruler.Width - 250)));
  9.   RPt := MapView.ScreenToLatLon(Ruler.ClientToParent(Point(0, Ruler.Width)));
  10.   Dist := mvGeoMath.CalcGeoDistance(LPt.Lat, LPt.Lon, RPt.Lat, RPt.Lon, duMeters);
  11.   Km := Dist >= 1000;
  12.   if Km then
  13.     Dist := Dist * 0.001;
  14.   Digits := Trunc(Math.Log10(Dist));
  15.   V := Power(10, Digits);
  16.   if V + V < Dist then
  17.     V := V + V;
  18.   Ruler.Width := Round(250 * (V / Dist));
  19.   Ruler.Caption := Round(V).ToString + IfThen(Km, ' Km', ' m');
  20.   with Ruler do
  21.   begin
  22.     Canvas.Pen.Color := clBlack;
  23.     Canvas.Pen.EndCap := pecFlat;
  24.     Canvas.Pen.Width := 3;
  25.     Canvas.Polyline([Point(0, 10), Point(0, 1), Point(Width - 1, 1),
  26.       Point(Width - 1, 10)]);
  27.   end;
  28. end;
Here the MapView and the Ruler have same parent and MapView is at (0, 0). Otherwise, MapView.ScreenToClient(Ruler.ClientToScreen(x)) shall be used instead of  Ruler.ClientToParent(x).

Also, call Ruler.Invalidate into MapView.OnZoomChange and MapView.OnCenterMove.

EDIT: You must be aware that there is an issues with that code when the zoom level is too small (<8 ).
« Last Edit: December 01, 2024, 05:54:09 pm by alpine »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

wp

  • Hero Member
  • *****
  • Posts: 12513
Re: LazMapView - adding a scale
« Reply #2 on: December 01, 2024, 06:32:03 pm »
I think a magnification scale is a key requirement for displaying maps and should be provided by the TMapView itself. I opened a bug report for it (https://gitlab.com/freepascal.org/lazarus/ccr/-/issues/39081)

wschulte

  • New Member
  • *
  • Posts: 34
Re: LazMapView - adding a scale
« Reply #3 on: December 02, 2024, 04:31:40 am »
You can put a TPanel on top of the map view, anchor it at the bottom right corner with some offset. Then, assuming the name of the map view is MapView and the panel is Ruler, put at Ruler.OnPaint something like this:

Here the MapView and the Ruler have same parent and MapView is at (0, 0). Otherwise, MapView.ScreenToClient(Ruler.ClientToScreen(x)) shall be used instead of  Ruler.ClientToParent(x).

Also, call Ruler.Invalidate into MapView.OnZoomChange and MapView.OnCenterMove.

EDIT: You must be aware that there is an issues with that code when the zoom level is too small (<8 ).

That came to my mind also, but I prefer the scale to overlay the map, like a track (which i did, but then you lack the text).

Btw. .. what issue are you referring to regarding the zoom level? That the map becomes smaller then the control size .. ?

wschulte

  • New Member
  • *
  • Posts: 34
Re: LazMapView - adding a scale
« Reply #4 on: December 02, 2024, 04:32:43 am »
I think a magnification scale is a key requirement for displaying maps and should be provided by the TMapView itself. I opened a bug report for it (https://gitlab.com/freepascal.org/lazarus/ccr/-/issues/39081)

Thats a very good idea. I look into it.

alpine

  • Hero Member
  • *****
  • Posts: 1315
Re: LazMapView - adding a scale
« Reply #5 on: December 02, 2024, 03:05:23 pm »
Here is the revised code measuring at the middle of the view, the previous had X,Y swapped:
Code: Pascal  [Select][+][-]
  1. procedure TMainForm.RulerPaint(Sender: TObject);
  2. var
  3.   LPt, RPt: TRealPoint;
  4.   Dist, V: Double;
  5.   Digits: Integer;
  6.   Km: Boolean = False;
  7. begin
  8.   LPt := MapView.ScreenToLatLon(Point(0, MapView.Height div 2));
  9.   RPt := MapView.ScreenToLatLon(Point(250, MapView.Height div 2));
  10.   Dist := mvGeoMath.CalcGeoDistance(LPt.Lat, LPt.Lon, RPt.Lat, RPt.Lon, duMeters);
  11.   Km := Dist >= 1000;
  12.   if Km then
  13.     Dist := Dist * 0.001;
  14.   Digits := Trunc(Math.Log10(Dist));
  15.   V := Power(10, Digits);
  16.   if V + V < Dist then
  17.     V := V + V;
  18.   with Sender as TPanel do
  19.   begin
  20.     Width := Round(250 * (V / Dist));
  21.     Caption := Round(V).ToString + IfThen(Km, ' Km', ' m');
  22.     Canvas.Pen.Color := clBlack;
  23.     Canvas.Pen.EndCap := pecFlat;
  24.     Canvas.Pen.Width := 3;
  25.     Canvas.Polyline([Point(0, 10), Point(0, 1), Point(Width - 1, 1),
  26.       Point(Width - 1, 10)]);
  27.   end;
  28. end;
  29.  
Since it is also not tied to a specific panel position, you can anchor it anywhere you like.

That came to my mind also, but I prefer the scale to overlay the map, like a track (which i did, but then you lack the text).
Please explain why you would prefer it this way.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

wschulte

  • New Member
  • *
  • Posts: 34
Re: LazMapView - adding a scale
« Reply #6 on: December 02, 2024, 03:53:40 pm »
Its a preference from habit and idea: map+scale are one thing. It isn't something principal (at least not for me).

MarkMLl

  • Hero Member
  • *****
  • Posts: 8080
Re: LazMapView - adding a scale
« Reply #7 on: December 02, 2024, 04:22:37 pm »
I think a magnification scale is a key requirement for displaying maps and should be provided by the TMapView itself. I opened a bug report for it (https://gitlab.com/freepascal.org/lazarus/ccr/-/issues/39081)

Thats a very good idea. I look into it.

But at the same time, different applications will have different requirements for whether the map can be panned and/or zoomed (at least in the normal case), whether there is a "restore to default view" button, where the buttons should be placed, whether there could usefully be other legend information grouped with the buttons and so on... and I found that it was very easy to overlay some buttons in a corner. And I'm definitely one of the less practiced graphics programmers around here...

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

alpine

  • Hero Member
  • *****
  • Posts: 1315
Re: LazMapView - adding a scale
« Reply #8 on: December 02, 2024, 05:26:28 pm »
Quote
and I found that it was very easy to overlay some buttons in a corner. And I'm definitely one of the less practiced graphics programmers around here...
IMO the keyword here is "easy" - only two specific LMV functions were used into my code above for example.

If someone wants to draw into the MapViewer canvas, he must do it through the viewer drawing engine, which is technically a different way of drawing than LCL. Even more so that all objects there have a map coordinates, no notion for another (screen) coordinate space, thus anchoring an artifact on screen means constant movements into the map space. It requires some effort, that's why I wanted to know the benefit, according to some other person, of embedding such extra gadgets.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

 

TinyPortal © 2005-2018