Lazarus

Programming => Graphics and Multimedia => Graphics => Topic started by: Arctic_Eddie on August 07, 2022, 07:51:09 pm

Title: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 07, 2022, 07:51:09 pm
I've been using the viewer package from the OPM for a ham radio propagation project. The purpose is to display the path from a sending station (TX) using WSPR (Weak Signal Propagation Report) and all those hearing the signal (RX) and reporting the spot to the WSPR website. There is one problem trying to draw lines from the TX station to all RX stations. The only thing that has worked so far is the below code.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.DisplayTrack( trpt1, trpt2 :TRealPoint );
  2. var
  3.      rxpt, txpt         :TPoint;
  4. begin
  5.      // Display a line between the TX and Rx stations
  6.      WSPRMap.DrawingEngine.PenWidth:=1;
  7.      WSPRMap.DrawingEngine.PenColor:=clRed;
  8.      txpt := WSPRMap.LonLatToScreen( trpt1 );      // TX screen point
  9.      rxpt := WSPRMap.LonLatToScreen( trpt2 );      // RX screen point
  10.      WSPRMap.DrawingEngine.Line(txpt.x,txpt.y,rxpt.x,rxpt.y);
  11. end;
  12.  

The problem is that when the map is zoomed or panned then the drawing engine deletes the tracks and they have to be displayed again. So my question is: what method should be used to draw these lines whereby the engine is aware of the change and redraws them?

Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 07, 2022, 11:04:19 pm
Don't paint outside the paint cycle - that's a general rule, not related to the MapViewer. Because each control must be able to repaint itself at any time if the operating system requires that.

The "official" way to add a line to the mapview is to add a TGpsTrack to the GpsItems list of the MapViewer. The MapViewer "knows" what a track is and how to draw it because a track consists of discrete points connected by straight lines.

If the endpoints of your line are close to each other it is sufficient to simply add the endpoints to the track. When the line covers a large distance, however, you must divide the line into several segements and add these to the track as well; this way it is guaranteed that the line is curved due to the spherical projection of the grand circle between start and end point.

In the attachment you find a simple example for adding such a segmented "line" to the mapviewer.
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 07, 2022, 11:27:11 pm
Thank you so much. I'll add that to my project tomorrow.

I have other questions but will put them in a separate post.
Title: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 08, 2022, 02:01:57 pm
Unfortunately, the compile failed in the same way as your ADrawer example. The error list is shown below. I'm missing something common in both situations.
Code: Pascal  [Select][+][-]
  1. Compile Project, Target: bin\x86_64-win64\mapviewer_line_demo.exe: Exit code 1, Errors: 4, Hints: 2
  2. Hint: Start of reading config file C:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc.cfg
  3. Hint: End of reading config file C:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc.cfg
  4. main.pas(55,12) Error: identifier idents no member "LineColor"
  5. main.pas(56,12) Error: identifier idents no member "LineWidth"
  6. main.pas(63,46) Error: Identifier not found "TRealPoint"
  7. main.pas(82,23) Error: Identifier not found "RealPoint"
  8.  
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 08, 2022, 05:57:18 pm
Ah, I see - you seem to be using the OPM version which is not in sync with the development version. Please install the version from ccr; either by using svn, or get the snapshot from https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/lazmapviewer/
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 08, 2022, 07:03:43 pm
What do I need to remove of the OPM version?
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 08, 2022, 07:18:13 pm
Not absolutely necessary since the IDE always used the version that was installed last. But if you want to do it: Check LazMapViewer in OPM, then click "Uninstall".

In order to install the new ccr version unzip the snapshot to some folder, then, in the IDE, go to "Package" > "Open package file (.lpk)" > navigate to the folder with the ccr version > open "lazmapviewerpkg.lpk" > "Use" > "Install". If you use the add-on packages in your project you must also install the other lpk files in the same way.
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 08, 2022, 07:28:15 pm
It was the other three lpk files that concerned me. I do not use them knowingly but will find out. I'll uninstall the old LazMapViewer and install the new one as you suggested.
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 08, 2022, 08:39:01 pm
The BGA object was causing a problem so I uninstalled it and now your line demo works. However, when trying to use your example below, I get several failures.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.MapView1DrawGpsPoint(Sender: TObject;
  2.   ADrawer: TMvCustomDrawingEngine; APoint: TGpsPoint);
  3. const
  4.   R = 8;
  5. var
  6.   p: TPoint;
  7. begin
  8.   // Screen coordinates of the GPS point
  9.   p := MapView1.LonLatToScreen(APoint.RealPoint);
  10.  
  11.   // Draw a blue circle
  12.   ADrawer.PenColor := clBlack;
  13.   ADrawer.BrushColor := clBlue;
  14.   ADrawer.BrushStyle := bsSolid;
  15.   ADrawer.Ellipse(p.X-R, p.Y-R, P.X+R, p.Y+R);
  16.  
  17.   // Draw the point label
  18.   ADrawer.BrushStyle := bsClear;
  19.   ADrawer.FontName := 'SegoeUI';
  20.   ADrawer.FontSize := 16;
  21.   ADrawer.FontStyle := [fsBold];
  22.   ADrawer.TextOut(
  23.     p.X - ADrawer.TextWidth(APoint.Name) div 2,
  24.     p.Y + R + 4,
  25.     APoint.Name
  26.   );
  27. end;
The ellipse function is unknown and causes a SIGSEGV fault. If I skip over that the blue circle does not draw anything as the TextWidth function returns a zero. If I substituted a real value, 20, it still does not draw. As soon as I click anything in my program, I get another SIGSEGV fault. Is this example not compatible with the dev version?
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 08, 2022, 11:50:34 pm
I am aware of crashes on Linux due to the GPS points and tracks painting, but not on Windows (which you seem to have).

That the drawer's Ellipse method is unknown could indicate that your new version is not correctly installed. Try this: Open "Tools" > "Configure Build Lazarus" and check the boxes "Clean all" and "Switch after building to automatically". Then click "Build".

Or: Open "Package" > "Install/Uninstall packages", and select the "lazmapviewerpkg.lpk" in the left listbox. When you scroll down the "Package Info" box you should see the path from where the package is used. Is this the path into which you unzipped the download? If not repeat the installation as described in the previous message.
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 12:30:59 am
I'm using an Acer desktop running Win10/21H2, 12GB of RAM and a 512GB SSD drive. I did both of your suggestions and it used my downloaded snapshot from the link you gave. However, both faults are still present in that example but everything else run fine. I also discovered that LineWidth appears to be in millimeters. I noticed the type was Double so tried 0.5 and settled on 0.3. It also affected the size of the lines in the + mark.

Would like to be able to use multiple colors for the tracks as a hundred spot reports all in red is a little overwhelming. One method that comes to mind is to have maybe 16 versions of _LINE_ and sprinkle the spots randomly into these groups with each having a different color. Would that be feasible?

PS
ADrawer.TextWidth(APoint.Name); does not work either. It always returns zero. I tried 20 but it did not help. Is ADrawer.BrushStyle := bsClear; feasible. Maybe I can't see it because it's invisible.
 
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 09, 2022, 01:21:48 am
The attached modified demo of the previous post contains your OnDrawGpsPoint handler (right-click somewhere to add a gps point) - it is working correctly for me (Win 11, 64bit, Laz main/fpc 3.2.2/64bit and 32 bit). Setting a breakpoint after the line w := ADrawer.TextWidth(APoint.Name) allows to read a non-zero TextWidth.

I am rather clueless now...

[EDIT]
Adding the forgotten project...
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 01:38:49 am
I don't see the attachment.

After attempting to run the earlier example, and fail, I get a crash even closing my form.

PS
I'm also using Laz 2.0.12. Perhaps that's the problem.
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 07:07:17 pm
I set a breakpoint at the Ellipse procedure then "Step-Into" to see where it was going. Strangely, it goes to intfbasewinapi.inc to this point.
Code: Pascal  [Select][+][-]
  1. function TWidgetSet.CreateFontIndirectEx(const LogFont: TLogFont;
  2.   const LongFontName: string): HFONT;
  3. begin
  4.   // this functions is needed, because the fontname in TLogFont is limited to
  5.   // 32 characters. If the interface does not support long font names, it can
  6.   // simple omit this function
  7.   Result := CreateFontIndirect(LogFont);
  8. end;
  9.  
Nothing makes any sense at that point and I wonder what fonts have to do with drawing an ellipse.
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 09, 2022, 07:21:15 pm
I don't see the attachment.
Sorry...  Added it to the previous post now.

I'm also using Laz 2.0.12. Perhaps that's the problem.
No. Installed the ccr-mapviewer version in Laz 2.0.12., and that mapviewer-line sample project is working correctly here, too (well... there is another issue because when the gps point title is painted over the map tile boundary it is overpainted by the neighbouring tile - but this is a different story.)
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 07:24:59 pm
I tried the same thing with the call to ADrawer.TextOut() and ended up in win32winapi.inc  at this function.
Code: Pascal  [Select][+][-]
  1. function TWin32WidgetSet.CreateRoundRectRgn(X1, Y1, X2, Y2, nWidthEllipse,
  2.   nHeightEllipse: Integer): HRGN;
  3. begin
  4.   Result := Windows.CreateRoundRectRgn(X1, Y1, X2, Y2, nWidthEllipse,
  5.     nHeightEllipse);
  6. end;
  7.  
This one is talking about drawing an ellipse when it should be dealing with text. The X1 and Y1 values are reasonable but the next two are huge. It looks like each procedure is aimed at what the other should be doing. This is getting a lot deeper than I want to go just to print ham radio call signs on a world map.
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 07:44:11 pm
Your second demo runs fine. I don't see any difference between what you have and mine. There must be a system setting in my PC that is causing the problem. I compared my Form.Activate with yours and nothing obvious. Would you like me to post my Form.Activate and Form.Create procedures? Maybe you can spot something there.
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 09, 2022, 07:52:01 pm
Yes post them, but reading the sources usually is not very efficient without support by the compiler. If the project is not too big it would be better to provide the full project, i.e. all pas, lfm, the lpi and lpr files so that I can compile and test myself. Of course you should remove everything not needed from the project
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 08:04:03 pm
The project is about 1700 lines. Here's the two procedures.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);
  2. var
  3.    P: TRealPoint;
  4. begin
  5.      // Set up initial map
  6.  
  7.      P.Lon := 0;                 // Just north of the equator
  8.      P.Lat := 10;
  9.      WSPRMap.Center := P;
  10.      WSPRMap.Zoom := DEF_ZOOM;   // Nice starting view
  11.      WSPRMap.DoubleBuffered := true;
  12.      WSPRMap.Active := true;
  13. end;
  14.  

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. var
  3.      sw, sh, ft, fl  :Integer;
  4. begin
  5.      // 1366x768 but account for title bar height
  6.      PageControl1.ActivePage := MapTab;      // Put on first tab
  7.  
  8.      Form1.Caption := 'WSPR Propagation Mapping - V'
  9.                       + VERSION + ' --- ' + OpenFileName;
  10.  
  11.      // Set form to 1366x768 for laptop and centered on any larger screen
  12.      PixPerInch := Screen.PixelsPerInch;             // Pitch for this PC
  13.      sh := Screen.Height;                            // Screen height
  14.      sw := Screen.Width;                             // Screen width
  15.      ft := ( sh - MINSCRH - TITLEHEIGHT) div 2;      // Centered vertically
  16.      if ft < 0 then ft := 0;                         // Don't let it go neg
  17.      fl := ( sw - MINSCRW ) div 2;                   // Centered horizontally
  18.      if fl < 0 then fl := 0;                         // Don't let it go neg
  19.      Form1.Top    := ft;                             // Set top
  20.      Form1.Left   := fl;                             // Set left side
  21.      Form1.Height := MINSCRH - TITLEHEIGHT;          // Set minimum height
  22.      Form1.Width  := MINSCRW;                        // Set minimum width
  23.      Application.ProcessMessages;                    // Now do this
  24.  
  25.     {// Start full screen on any PC
  26.      Form1.Top    := 0;                              // Set top
  27.      Form1.Left   := 0;                              // Set left side
  28.      Form1.Height := Screen.Height - TITLEHEIGHT;    // Set to screen height
  29.      Form1.Width  := Screen.Width; }                 // Set to screen width
  30.  
  31.      // Intialize the time scale under map
  32.      InitWidth := TimeScaleImage.Width;              // Initial width of image
  33.      TimeScaleImageInit();
  34.      TimeStart := 0;
  35.      TimeEnd   := 24;
  36.  
  37.      // Load CallGrid names in config tab and set sizes
  38.      CallGridStringGrid.Cells[0,0] := 'Call';
  39.      CallGridStringGrid.Cells[0,1] := 'Grid';
  40.      CallGridStringGrid.Cells[1,0] := TxCall;        //MY_CALL;
  41.      CallGridStringGrid.Cells[1,1] := TxGrid;        //MY_GRID;
  42.      CallGridStringGrid.Height     := CallGridStringGrid.DefaultRowHeight
  43.                                        * CallGridStringGrid.RowCount
  44.                                        + 4;
  45.      CallGridStringGrid.Width      := CallGridStringGrid.ColCount
  46.                                        * CallGridStringGrid.DefaultColWidth
  47.                                        + 4;
  48.  
  49.      // Open users data, call, grid, TZ
  50.      ConfigOpen();
  51.  
  52.      // Initialize the station data window
  53.      StationImageInit();
  54.      StationDataDraw();
  55.      TimeScaleDraw( 0, 24 );
  56.  
  57.  
  58. end;
  59.  
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 08:13:32 pm
The whole project zipped is about 100MB as it contains a lot of cached maps and is in debug mode. I can put it on my friends one-drive page and you can get it from there. It will be the one with the highest suffix number.
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 09, 2022, 09:44:40 pm
Remove the cached maps and I don't the exe, ppu etc either
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 09, 2022, 10:41:15 pm
I stripped out the items you mentioned. The program is still complete and there is one spot file that can be opened. The problem routine is near the end of the source file and activated directly using the Test Button at the bottom-left. There are two breakpoints at the problem statements. The third is commented out, TextWidth. The link to my friends public page is below. Select the file on the left with the word "test" in it's name. It's quite small now. There are no cached maps.

I did the same F7 with your demo file and it goes to an entirely different place and looks appropriate. There are two folders in the project folder involving MvEngine. I'm not sure how they got there, or are necessary, and may be the problem.


https://onedrive.live.com/?authkey=%21AlDtDyEVpMSIPeQ&id=2C53252267529651%21123&cid=2C53252267529651
 (https://onedrive.live.com/?authkey=%21AlDtDyEVpMSIPeQ&id=2C53252267529651%21123&cid=2C53252267529651)
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 09, 2022, 11:11:57 pm
I could not load the map from VirtualEarth which is used by your MapView component, selected "OpenStreetMap Mapnik" instead.

After this fix (and the installation of BGRAControls) the project compiled, but the button click made it crash at the line "APoint.Name := 'Test'". APoint is a local variable of type TGpsPoint - this is a class and must be created! Adding "APoint.Name := TGpsPoint.CreateFrom(rpt)" before "Apoint.Name := 'Test'" solved this issue.

The next crash is at line "ADrawer.BrushStyle := ...". Again: ADrawer is a local variable and type TMvCustomDrawingEngine. This is another local variable which has no value. In fact it is the DrawingEngine of the MapViewer (something like a "generalized canvas") needed for drawing on the screen. Assigning "ADrawer := WSPRMap.DrawingEngine" solves the issue, and there is no more crash. The commented TextWidth now is correct too.

No text appears on the map, but I already told you that you cannot draw in a button's click event and will not repeat this again.

Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 10, 2022, 12:05:24 am
Still having a problem. When I insert "APoint.Name := TGpsPoint.CreateFrom(rpt)", the error says "expected Ansi string". If I change the argument to 'test' then it says "expected TRealPoint". Could you post the corrected version of the routine so I see what you did?

Found it, the inserted line should be "APoint := TGpsPoint.CreateFrom(rpt)" without the ".name" part.
Title: Re: LazMapViewer - Lines between realpoints
Post by: wp on August 10, 2022, 12:44:44 am
Sorry, this happens when I edit the text already written...
Title: Re: LazMapViewer - Lines between realpoints
Post by: Arctic_Eddie on August 10, 2022, 01:02:04 am
I'm going to implement the ideas in your two demos. That will solve my immediate problems.

Thanks again for all your help. I could not have sorted this out by myself.
TinyPortal © 2005-2018