Projecting points onto 3D terrain surface in UWP MapControl

Viewed 211

I'm creating a windows desktop app using the UWP Map control (MapControl) and inking based on this blog post.

I have the basics working. can draw ink on the canvas and convert them to map locations, but I can't get the points to correctly project onto the map 3D surface.

I'm using mapControl.GetLocationFromOffset to transform the control-space offset to map position but no matter what AltitudeReferenceSystem I use the points are offset above or below the 3D mesh. I'm basically trying to emulate how inking works in the built in windows Maps app. But since there's a pause after drawing each stroke I'm thinking it's doing some ray casting onto the 3D mesh. Lat/Long are correct but altitude has an offset.

Geopoint GeopointFromPoint(Point point)
{
   Geopoint geoPoint = null;
   this.map.GetLocationFromOffset(point, AltitudeReferenceSystem.Geoid, out geoPoint); // Tried all alt ref systems here
   return (geoPoint);
}
...
BasicGeoposition curP;
foreach (var segment in firstStroke.GetRenderingSegments())
{
   curP = GeopointFromPoint(segment.Position).Position;
   geoPoints.Add(curP);
}
...

This is my inking around a patch of grass in the Maps App which determines correct altitude:

enter image description here

And the same area using the Map control + GetLocationFromOffset, blue ink is annotation showing altitude offset:

enter image description here

How can I project screen/control space coordinates onto the 3D mesh in the UWP Map control and get the correct altitude?

Edit: And the answer is I'm an idiot, have been thinking in meters from center of earth too long, ie I thought altitude was the altitude above sea level of the map location, but it's not, it's the points altitude above the map. So just setting altitude to zero works.

2 Answers

First problem was I wasn't passing a AltitudeReferenceSystem to the Geopath constructor while translating ink strokes to map polygons. Once you do this you can pass the result of TryGetLocationFromOffset directly to the polygons.

Second is a possible bug with the map control. If the map control does not take up the entire height of the main window you see a pixel offset between what TryGetLocationFromOffset and where the ink stroke was drawn.

Just setting the altitude to zero may still produce unexpected results. The call to GetLocationFromOffset is where your issue is. (you should really use TryGetLocationFromOffset BTW and handle failure cases - it isn't always possible to map a screen offset to a location, for example when you click above the horizon). The AltitudeReference you pass is is telling the control what to intersect with. You can think of it as a ray you're shooting into the 3D scene at that screen pixel. The ray will intersect the Surface first, then the terrain, then the Geoid or Ellipsoid depending on where you are. You were asking for the intersection with the Geoid, which probably wasn't what you really wanted. You probably want the intersection with the surface for an inking case. The docs aren't terribly clear on what this parameter does and should probably be updated.

If you reset all altitudes to 0 with an altitude reference of surface for the line you pass in, it will always put the line on the surface, but that might not match your ink.

There may actually be a bug here - if your code snippet above was passing the Geopoint returned from GetLocationFromOffset to the polyline, it should appear at the same pixel (you should be able to round-trip values). What was the AltitudeReferenceSystem and value returned for these GeoPoints?

Related