Rugged with DEM has problem at ground point lat 90(-90) and lon180(-180)

I am developing an software depend on rugged with DEM.

I found there are problem at point nearby longitude 180(-180). By tracing the code inside, i found the when algorithm goes , a Geodetic Point with longitude value greater than Pi caused the problem,i reset this value by minus 2Pi,the result goes out. I’m not sure this is a bug or not .

After finish the longitude 180 test,I tried lat 90, rugged throw out exception, I tried to fix this, failed .

i post my test here,maybe the team can give some message about this, thanks.

The ±180° longitude is normally handled internally as we use NormalizedGeodeticPoint instances
that take care to center all longitudes considered during one compmutation to remain in the same hemisphere. Consider for example a case where we have a DEM that extends from -100m altitude to +1500m altitude on some tile and want to compute a direct location from some line of sight. Then, we first check when we cross the +1500m altitude surface and look at the longitude of this point. This longitude will be used as a reference longitude throughout this computation and all other points computed will be normalized with respect to it. So if this point is at say +179.99 degrees, then when we continue exploring the line of sight, if this LOS crosses the +180 degrees longitude before traversing DEM, then we will use longitudes like +180.01, +180.02… until we reach the ground, thus avoiding a discontinuity.

As we have already taken care of handling this issue (which is quite common), you may have found a bug because doing remote sensing at the antimeridain shgould be possible.

Could you insert calls to DumpManager.activate(file) and DumpManager.deactivate() files somewhere around the location where the problem occurs, review the generated dump file to make sure it does not contain any sensitive information and post this dump fie here so we try to reproduce the issue? Be aware that if you post this file, it will be publicly available, so double check before doing so.

Concerning the ±90 latitude issue, this is clearly a point we don’t address. This is a highly singular point because of sphere topology and DEM which are defined as tiles in longitude-latitude do not work properly there. The DEM I have seen up to know are generally limited before reaching poles. Do you have a DEM that covers polar regions too?

1 Like

thank you for the answer and all the detail.
i’v understood the rugged’s design, leaving latitude 90(-90)singular point is acceptable for me.

My DEM data is noaa’s 1KM GLOBE, the longitude 180 is an edge between two tiles.

I implied a tileupdater to load the GLOBE DEM and made the “overlap edge”.

rugged works well in all the other places.

i override the tile “cellIntersection” method, add these code below, the “longitude180 problem” fixed, in my software.

@Override
    public NormalizedGeodeticPoint cellIntersection(final GeodeticPoint p_input, final Vector3D los, final int latitudeIndex,
            final int longitudeIndex) {

        GeodeticPoint p_use = null;
        if (p_input.getLongitude() > FastMath.PI) {
            p_use = new GeodeticPoint(p_input.getLatitude(), Math.abs(p_input.getLongitude()) - 2 * FastMath.PI, p_input.getAltitude());
        } else if (p_input.getLongitude() < -FastMath.PI) {
            p_use = new GeodeticPoint(p_input.getLatitude(), 2 * FastMath.PI - Math.abs(p_input.getLongitude()), p_input.getAltitude());
        }else{
            p_use =p_input;
        }

replace following "p" with "p_use"

hope this will improve the rugged and help other people to use it.

Is p_use the value needed when you load the GLOBE DEM?
If I understand correctly, the problem is due to Rugged calling the cellIntersection method in your code with a value that was extended past the antimeridian because Rugged takes care to avoid discontinuities, and then this breaks the assumptions in the tile updater, is that correct?

Also one simpler way to convert p_input into p_use would be to do:

  GeodeticPoint p_use = new GeodeticPoint(p_input.getLatitude(),
                                          MathUtils.normalizeAngle(p_input.getLongitude(), 0.0),
                                          p_input.getAltitude());

Here the normalizeAngle method is used to clip the angle back to [-π ; +π] interval.

On a side note, would you consider contributing your tile updater for GLOBE to the Rugged project?

I agree with your analysis.

the code

            final NormalizedGeodeticPoint entry = ellipsoid.transform(entryP, ellipsoid.getBodyFrame(), null,
                    tile.getMinimumLongitude());
return tile.cellIntersection(entry, ellipsoid.convertLos(entryP, exitP),
                    tile.getFloorLatitudeIndex(closeGuess.getLatitude()),
                    tile.getFloorLongitudeIndex(closeGuess.getLongitude()));

which “entry” point is NormalizedGeodeticPoint, this Class longitude "/** Geodetic point whose longitude can be selected with respect to the 2π boundary.
"
and override the

    public double getLongitude() {
        return normalizedLongitude;
    }

that’s why inside the

public NormalizedGeodeticPoint cellIntersection(final GeodeticPoint p_input, final Vector3D los, final int latitudeIndex,
            final int longitudeIndex)

we can get a longitude greater than PI.

In my opinion, It’s the mismatch between the rugged’s core algorithm and my Tile implement causes the problem.

I think there are two way to fix this

  1. make it clear in the document that the Tile(and the TileUpdate) must support that NormalizedGeodeticPoint as the input in method “cellIntersection”

and maybe consider change the Interface Tile.cellIntersection to specify the param “p”

    /** Find the intersection of a line-of-sight and a Digital Elevation Model cell.
     * @param p point on the line, must be NormalizedGeodeticPoint,which with longitude 0~2PI
     * @param los line-of-sight, in the topocentric frame (East, North, Zenith) of the point,
     * scaled to match radians in the horizontal plane and meters along the vertical axis
     * @param latitudeIndex latitude index of the Digital Elevation Model cell
     * @param longitudeIndex longitude index of the Digital Elevation Model cell
     * @return point corresponding to line-of-sight crossing the Digital Elevation Model surface
     * if it lies within the cell, null otherwise
     */
    NormalizedGeodeticPoint cellIntersection(NormalizedGeodeticPoint p, Vector3D los,
                                              int latitudeIndex, int longitudeIndex);
  1. maybe change API is not a good chose , the other way is change the code before call “tile.cellIntersection”

i think most public DEM data like SRTM and ASTER uses -Pi to Pi to define Tiles, which is the same as GeodeticPoint 's definition.

at last, i would love to share my implement of tileUpdater about Noaa’s GLOBE DEM.

how to do that? I can try to make a fork and make a MR.I’m not sure the quality of my codes can meet the project requirements or not. Or just post my codes here.

anyway,I hope the discussion is useful, it’s my pleasure to help others to make use of rugged more easily.

thanks

I think both documentation and API for tile updater should be made clearer.

I will add something like:

Beware that for continuity reasons, the point argument in `cellIntersection` is normalized
with respect to other points used by the caller. This implies that the longitude may be
outside of the [-π ; +π] interval (or the [0 ; 2π] interval, depending on the DEM). In particular,
when a Line Of Sight crosses the antimeridian at  ±π longitude, the library may call the
`cellIntersection` method with a point having a longitude of -π-ε to ensure this continuity,
and the method must return a point that is in the same area. As DEM are stored with longitude
clipped to a 2π interval (either  [-π ; +π] or [0 ; 2π]), implementations MUST take care to
clip the input point back to the DEM interval using `MathUtils.normalizeAngle(p.getLongitude(), 0)` 
for the [-π ; +π] interval or `MathUtils.normalizeAngle(p.getLongitude(), FastMath.PI)` for the [0 ; 2π]) 
interval, and then MUST take care of normalizing the return back in the vicinity of the input point
using `MathUtils.normalizeAngle(intersection.getLongitude(), p.getLongitude())` before returning it.

Doing a merge request is fine. I don’t remember if you can create a fork on our forge directly or if this
operation requires moderation. Please take care that for contributions, we need either a Software Grant (for one-time contributions) or a Contributor License Agreement (for long term involvement). You can find more about this in the Rugged governance document.

Well, the documentation improvement I suggested above is wrong, the output may be normalized with respect to the tile itself, not the input point.

I’ve already fork the rugged,I am willing to have a try to submit a merge request.