2

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.

Geordie
  • 1,920
  • 2
  • 24
  • 34

2 Answers2

1

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.

Geordie
  • 1,920
  • 2
  • 24
  • 34
  • One thing to note is that while MapPolylines correctly handle altitudes, MapPolygons do not. The will always draw to the terrain surface. – Duncan Lawler Jun 01 '20 at 16:14
1

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?

Duncan Lawler
  • 1,772
  • 8
  • 13
  • I tried with all the different reference systems and all gave similar results. I'm now using TryGetLocationFromOffset. Yeah there's a slight discrepancy with expected altitude between getting a map location with GetLocationFromOffset which returns an altitude from the given ref system and drawing markers etc which you just supply an altitude which is an offset of the altitude at a given point – Geordie May 30 '20 at 06:07
  • ohhhh can pass AltitudeReferenceSystem to the Geopath constructor. That works as expected, but I still see a jump of a couple of meters from the ink to the geopath – Geordie May 30 '20 at 06:27
  • Annnd that offset is because I have a CommandBar above my map control. Remove that so the map control uses the whole app window and the coords returned from TryGetLocationFromOffset / Surface are 1:1 with Geopath /Surface. So either a bug or my xaml is screwy, but it's a pretty simple xaml file. – Geordie May 30 '20 at 06:35
  • Sounds like it's a XAML layout issue. The offset passed to the API is relative to the map control window so it appears your command bar is overlaying the map control causing the offset to not be relative to the full control. – Duncan Lawler Jun 01 '20 at 16:13
  • I agree it could be a XAML issue but as a test I removed the command bar and just manually made the map control smaller and got the same results. – Geordie Jun 01 '20 at 17:21