Modify

Opened 3 months ago

Last modified 3 months ago

#22596 new enhancement

[Patch] Elevation at current map location / Automatic download of SRTM HGT files

Reported by: hhtznr Owned by: team
Priority: normal Milestone:
Component: Plugin elevationprofile Version:
Keywords: elevation, SRTM HGT, current map location, automatic download Cc: OliverW

Description (last modified by hhtznr)

What?
I wrote this patch, which will display the elevation at the current location on the map next to the coordinates in the MapStatus line. Optionally, the necessary SRTM HGT files providing the elevation can automatically be downloaded, if they are missing on disk.

Why?
This is typical functionality in most map applications, but it is missing in JOSM. Elevation at the current map location (mouse pointer) can be useful in determining the proper direction of waterways, the location of summits etc.

How does it work?
It builds on HgtReader from ElevationProfile plugin written by Oliver Wieland. HgtReader checks whether the HGT file covering the current map location is available on disk. If so, it reads it into memory and determines the elevation at the current location.

I extended HgtReader with HgtDownloader, which will download any missing HGT file in a background thread from NASA's Land Processes Distributed Active Archive Center (LP DAAC) at https://e4ftl01.cr.usgs.gov/MEASURES/SRTMGL3.003/2000.02.11/.

I created a preferences tab, where the elevation feature can be enabled and where optional auto-downloading can turned on.

Why not as plugin?
I did not see a way, how to feed the current map location (mouse pointer) into a plugin.

What's the content of the patch?
New files:

  • src/org/openstreetmap/josm/data/elevation/ElevationHelper.java (from Oliver Wieland)
  • src/org/openstreetmap/josm/data/elevation/HgtDownloader.java
  • src/org/openstreetmap/josm/data/elevation/HgtDownloadListener.java
  • src/org/openstreetmap/josm/data/elevation/HgtPreferences.java
  • src/org/openstreetmap/josm/data/elevation/HgtReader.java (builds on Oliver Wieland)
  • src/org/openstreetmap/josm/data/elevation/gpx/GeoidCorrectionKind.java (from Oliver Wieland)
  • src/org/openstreetmap/josm/gui/preferences/elevation/HgtPreference.java
  • src/org/openstreetmap/josm/gui/preferences/elevation/HgtPreferencesPanel.java
  • resources/images/preferences/elevation.svg
  • resources/images/statusline/ele.svg

Updated files:

  • src/org/openstreetmap/josm/gui/MapStatus.java
  • src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java

What next?
I would appreciate it, if the demonstrated functionality could be integrated into mainline JOSM.

Screenshots
Screenshot of elevation information in MapStatus line Screenshot of elevation data preferences tab

Attachments (5)

JOSM_18616_Elevation_git_diff.txt (63.8 KB) - added by hhtznr 3 months ago.
Git diff of elevation patch
JOSM_18616_Elevation_new_updated_src_files.tar.gz (32.5 KB) - added by hhtznr 3 months ago.
Archive with new and updated source files
JOSM_with_elevation_in_MapSatus.png (3.6 MB) - added by hhtznr 3 months ago.
Screenshot of elevation information in MapStatus line
JOSM_Elevation_Data_Preferences.png (145.7 KB) - added by hhtznr 3 months ago.
Screenshot of elevation data preferences tab
JOSM_ElevationProfile_18494.diff (58.5 KB) - added by hhtznr 3 months ago.
Git diff of reworked elevation patch against ElevationProfile

Change History (17)

Changed 3 months ago by hhtznr

Git diff of elevation patch

Changed 3 months ago by hhtznr

Archive with new and updated source files

Changed 3 months ago by hhtznr

Screenshot of elevation information in MapStatus line

Changed 3 months ago by hhtznr

Screenshot of elevation data preferences tab

comment:1 Changed 3 months ago by hhtznr

Description: modified (diff)

comment:2 Changed 3 months ago by hhtznr

Description: modified (diff)

comment:3 Changed 3 months ago by hhtznr

Description: modified (diff)

comment:4 Changed 3 months ago by taylor.smock

Why not as plugin?
I did not see a way, how to feed the current map location (mouse pointer) into a plugin.

It is possible to do so:

        Point mousePosition = MainApplication.getMap().mapView.getMousePosition();
        LatLon latLon = MainApplication.getMap().mapView.getLatLon(mousePosition.getX(), mousePosition.getY());

Also, you should have renamed attachment:JOSM_18616_Elevation_git_diff.txt such that it ended with .diff or .patch.

Anyway, skimming through your patch:

  • Why unzip the HGT file? It takes more space on disk, and there are several methods in Java to get a decompressed input stream. If you profiled it, and it took fewer resources, that would be helpful to know.
  • Please don't set the HttpClient factory. (HttpClient.setFactory(Http1Client::new);). This should only be set by JOSM itself or a plugin which provides its own factory (like the http2 plugin).
  • I'm not a fan of the TODO comments sprinkled throughout the code
  • Is there any documentation for the login process for the government server? Does it use OAuth 2.0? If so, does it allow redirects to localhost/127.0.0.1? I've got a WIP patch for OAuth 2.0 support in JOSM, and it takes advantage of the remote control server to receive initial server redirect.

comment:5 in reply to:  4 ; Changed 3 months ago by hhtznr

Replying to taylor.smock:

Why not as plugin?
I did not see a way, how to feed the current map location (mouse pointer) into a plugin.

It is possible to do so:

        Point mousePosition = MainApplication.getMap().mapView.getMousePosition();
        LatLon latLon = MainApplication.getMap().mapView.getLatLon(mousePosition.getX(), mousePosition.getY());

Thank you for pointing this out. It helped me to figure out how to do it outside the scope of MapStatus. I think, your proposal would not work to get the position as a result of mouse motion. But being pointed to mapView, I came across that it could be done like this, copying the listener code from MapStatus into an own plugin class and putting it in Plugin.mapFrameInitialized:

@Override
public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
    super.mapFrameInitialized(oldFrame, newFrame);

    if (newFrame != null) {
        newFrame.mapView.addMouseMotionListener(new MouseMotionListener() {
            @Override
            public void mouseDragged(MouseEvent e) {
                mouseMoved(e);
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                if (newFrame.mapView.getCenter() == null)
                    return;
                // Do not update the view if ctrl or right button is pressed.
                if ((e.getModifiersEx() & (MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) == 0)
                    updateEleText(newFrame.mapView.getLatLon(e.getX(), e.getY()));
            }
        });

        }
    }
}

Also, you should have renamed attachment:JOSM_18616_Elevation_git_diff.txt such that it ended with .diff or .patch.

Anyway, skimming through your patch:

  • Why unzip the HGT file? It takes more space on disk, and there are several methods in Java to get a decompressed input stream. If you profiled it, and it took fewer resources, that would be helpful to know.

Modern file systems use compression so it does not take more space when the original file is decompressed. Should I create a config option so the user can decide whether to decompress the downloaded files or to leave them as-is?

  • Please don't set the HttpClient factory. (HttpClient.setFactory(Http1Client::new);). This should only be set by JOSM itself or a plugin which provides its own factory (like the http2 plugin).

Is this better?

Http1Client httpClient = new Http1Client(url, "GET");
  • I'm not a fan of the TODO comments sprinkled throughout the code

NP, can be deleted.

  • Is there any documentation for the login process for the government server? Does it use OAuth 2.0? If so, does it allow redirects to localhost/127.0.0.1? I've got a WIP patch for OAuth 2.0 support in JOSM, and it takes advantage of the remote control server to receive initial server redirect.

They have documentation here: https://urs.earthdata.nasa.gov/documentation

It's not really explained in depth, but it seems they use OAuth2: https://urs.earthdata.nasa.gov/documentation/for_users/oauth2

They also have a Java code example, which uses java.net.HttpURLConnection: https://urs.earthdata.nasa.gov/documentation/for_users/data_access/java

However, it uses basic authorization with username + password instead of the authorization bearer. Would this be preferred? I thought otherwise.

Sorry, I'm absolutely no expert on this web stuff. So some support on this would be appreciated.

comment:6 in reply to:  5 Changed 3 months ago by taylor.smock

Replying to hhtznr:

Modern file systems use compression so it does not take more space when the original file is decompressed. Should I create a config option so the user can decide whether to decompress the downloaded files or to leave them as-is?

Many of the common linux filesystems do not enable transparent compression by default. BTRFS requires the user to pick a compression type, ext4 doesn't support transparent compression, and so on.

  • Please don't set the HttpClient factory. (HttpClient.setFactory(Http1Client::new);). This should only be set by JOSM itself or a plugin which provides its own factory (like the http2 plugin).

Is this better?

Http1Client httpClient = new Http1Client(url, "GET");

Not really. You should be using the factory (HttpClient.create), and the variable type should just be the base HttpClient type instead of a specific subclass. All of the methods you called on Http1Client and Http1Response are available in the super class/interface (HttpClient and HttpResponse respectively).

  • Is there any documentation for the login process for the government server? Does it use OAuth 2.0? If so, does it allow redirects to localhost/127.0.0.1? I've got a WIP patch for OAuth 2.0 support in JOSM, and it takes advantage of the remote control server to receive initial server redirect.

They have documentation here: https://urs.earthdata.nasa.gov/documentation

It's not really explained in depth, but it seems they use OAuth2: https://urs.earthdata.nasa.gov/documentation/for_users/oauth2

They also have a Java code example, which uses java.net.HttpURLConnection: https://urs.earthdata.nasa.gov/documentation/for_users/data_access/java

However, it uses basic authorization with username + password instead of the authorization bearer. Would this be preferred? I thought otherwise.

Sorry, I'm absolutely no expert on this web stuff. So some support on this would be appreciated.

It does look like they do use OAuth 2, and that would be greatly preferred over username + password. See #20768 for the WIP patch for JOSM OAuth 2 support.

comment:7 Changed 3 months ago by hhtznr

Is a "display local elevation" feature of interest for integration into the main application or should I rather convert my proposal into a plugin?

comment:8 in reply to:  7 ; Changed 3 months ago by taylor.smock

Replying to hhtznr:

Is a "display local elevation" feature of interest for integration into the main application or should I rather convert my proposal into a plugin?

I'd probably just apply the patch to the ElevationProfile plugin.

comment:9 in reply to:  8 Changed 3 months ago by hhtznr

Replying to taylor.smock:

Replying to hhtznr:

Is a "display local elevation" feature of interest for integration into the main application or should I rather convert my proposal into a plugin?

I'd probably just apply the patch to the ElevationProfile plugin.

OK, I'll consider your valued feedback on HttpClient and decompression, incorporate my code into ElevationProfile and send a new diff/patch.

Changed 3 months ago by hhtznr

Git diff of reworked elevation patch against ElevationProfile

comment:10 Changed 3 months ago by hhtznr

I integrated my code into ElevationProfile plugin and created this diff: https://josm.openstreetmap.de/attachment/ticket/22596/JOSM_ElevationProfile_18494.diff

An incompatible change is the directory, where the HGT files are saved.

The original code used:

for (String location : Preferences.getAllPossiblePreferenceDirs()) {
    String fullPath = new File(location + File.separator + "elevation", file).getPath();
    [...]
}

I use ...

public static final File DEFAULT_HGT_DIRECTORY =
    Paths.get(Preferences.main().getDirs().getCacheDirectory(true).toString(), "elevation", "SRTM3").toFile();

... to make sure, I have a directory that is writable when downloading and to ensure that SRTM3 HGT files can be distinguished from other elevation data in case that this should be necessary in the future.

What is your opinion on this patch?

comment:11 Changed 3 months ago by skyper

Component: CorePlugin elevationprofile
Owner: changed from team to OliverW
Version: latest

comment:12 Changed 3 months ago by skyper

Cc: OliverW added
Owner: changed from OliverW to team

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The owner will remain team.
as The resolution will be set.
to The owner will be changed from team to the specified user.
The owner will change to hhtznr
as duplicate The resolution will be set to duplicate.The specified ticket will be cross-referenced with this ticket
The owner will be changed from team to anonymous.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.