Which longitude/latitude adjustments do I need to

2019-06-11 09:41发布

问题:

This is related to my earlier question

I want to add a "shim" to my map so that the extreme pushpins aren't half-in bounds, half out-of-bounds. I'm on the right track (no pun intended), but my logic is faulty. I wrote this method:

// Adapted from Brundritt and Boonaert: https://stackoverflow.com/questions/26937358/can-i-adjust-my-bing-maps-view-locationrect-bounding-box-by-a-small-amount
public static Location GetAShimLocation(IList<Location> locations, bool IsForNorthwestCorner)
{
    const double MAP_CUSHION = 0.1; // Is this a comfortable enough cushion?
    // I don't know why the Lats are 85 instead of 90
    double maxLat = -85;
    double minLat = 85;
    double maxLon = -180;
    double minLon = 180;

    foreach (Location loc in locations)
    {
        if (loc.Latitude > maxLat)
        {
            maxLat = loc.Latitude;
        }

        if (loc.Latitude < minLat)
        {
            minLat = loc.Latitude;
        }

        if (loc.Longitude > maxLon)
        {
            maxLon = loc.Longitude;
        }

        if (loc.Longitude < minLon)
        {
            minLon = loc.Longitude;
        }
    }
    Location retLoc = new Location();
    // I'm not sure this math is right - test it later
    if (IsForNorthwestCorner)
    {
        retLoc.Latitude = maxLat - MAP_CUSHION;
        retLoc.Longitude = maxLon - MAP_CUSHION;
    }
    else // SouthEast corner - stretch a little both directions
    {
        retLoc.Latitude = minLat + MAP_CUSHION;
        retLoc.Longitude = minLon + MAP_CUSHION;
    }
    return retLoc;
}

...and call it like so:

private void ResizeMap()
{         
    App.photosetLocationCollection.Add(
        PhotraxUtils.GetAShimLocation(App.photosetLocationCollection, true));            
    App.photosetLocationCollection.Add(
        PhotraxUtils.GetAShimLocation(App.photosetLocationCollection, false));
    photraxMap.SetView(new LocationRect(App.photosetLocationCollection));
}

...and it does alter the size of the map without adding the "shim" locations as pushpins, but instead of pulling the map up a little north and west, and also south and east, it seems to be squashing it vertically (reducing latitude scope) and stretching it horizontally (increasing longitude).

What combination of min and max and minus and plus do I really need here?

To sum up: what I'm looking for is to "stretch" the map a little further northwest from the northwest corner and a little further southeast from the southeast corner.

A 50-point (or more) after-the-fact bounty to whoever figures this out.

UPDATE

Here it is after incorporating Jan Kukacka's code, and playing around with the cushion until I found what was about right; YMMV (no pun intended).

public static Location GetAShimLocation(IList<Location> locations, bool IsForNorthwestCorner)
{
    const double MAP_CUSHION = 1.05; // This seems to be about perfect
    //double maxLat = -85; <= This is what the original (ad[a,o]pted) code was, I don't know why 85 instead of 90, though
    //double minLat = 85;
    double maxLat = -90;
    double minLat = 90;
    double maxLon = -180;
    double minLon = 180;

    foreach (Location loc in locations)
    {
        if (loc.Latitude > maxLat)
        {
            maxLat = loc.Latitude;
        }

        if (loc.Latitude < minLat)
        {
            minLat = loc.Latitude;
        }

        if (loc.Longitude > maxLon)
        {
            maxLon = loc.Longitude;
        }

        if (loc.Longitude < minLon)
        {
            minLon = loc.Longitude;
        }
    }
    Location retLoc = new Location();

    double latDif = Math.Abs(maxLat - minLat);
    double lonDif = Math.Abs(maxLon - minLon);
    // This logic from Jan Kukacka https://stackoverflow.com/questions/26948104/which-longitude-latitude-adjustments-do-i-need-to-enlarge-my-map-to-the-northwes
    if (IsForNorthwestCorner)
    {
        retLoc.Latitude = maxLat - MAP_CUSHION * latDif;
        retLoc.Longitude = maxLon - MAP_CUSHION * lonDif;
    }
    else // SouthEast corner - stretch a little both directions
    {
        retLoc.Latitude = minLat + MAP_CUSHION * latDif;
        retLoc.Longitude = minLon + MAP_CUSHION * lonDif;
    }
    // Edge case insurance
    if (retLoc.Latitude > 90.0)
    {
        retLoc.Latitude = 90.0;
    }
    else if (retLoc.Latitude < -90.0)
    {
        retLoc.Latitude = -90.0;
    }

    if (retLoc.Longitude > 180.0)
    {
        retLoc.Latitude = 180.0;
    }
    else if (retLoc.Longitude < -180.0)
    {
        retLoc.Longitude = -180.0;
    }
    return retLoc;
}

回答1:

I am not sure how does your map look "squashed", nevertheless your cushion should be relatively sized, eg. 10% of the map size. Try something like this:

 double latDif = Math.Abs(maxLat - minLat);
 double lonDif = Math.Abs(maxLon - minLon);
 if (IsForNorthwestCorner)
 {
     retLoc.Latitude = maxLat - MAP_CUSHION * latDif;
     retLoc.Longitude = maxLon - MAP_CUSHION * lonDif;
 }
 else // SouthEast corner - stretch a little both directions
 {
     retLoc.Latitude = minLat + MAP_CUSHION * latDif;
     retLoc.Longitude = minLon + MAP_CUSHION * lonDif;
 }


回答2:

The radius of the earth at equator = 6,371 km. The equator is divided into 360 degrees of longitude, so each degree at the equator represents approximately 111.32 km. Moving away from the equator towards a pole this distance decreases to zero at the pole.To calculate the distance at different latitudes multiply it by the cosine of the latitude

3 decimal places,0.001 degrees aproximates to 111.32 meters at equator 96.41meters at 30 degrees N/S 78.71 meters at 45 degrees N/S 55.66 meters at 60 degrees N/S 28.82 meters at 75 degrees N/S

This means that adding a fixed value to longitude is wrong. This value will require to be reduced as the point move towards the poles.

Given a start point, initial bearing, and distance, this formula will calculate the destination point and final bearing travelling along a (shortest distance) great circle arc. Seefor explanation. Given your start point you find the new location by projecting 45degrees from each of your points,

var R = 6371 km 3,960miles lat/lng in radians d in kms/miles

I show javascript formula as don't use C#.

JavaScript: formula: (all angles in radians)

var lat2 = Math.asin(Math.sin(lat1)*Math.cos(d/R) +
                    Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));
var lng2 = lng1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
                         Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));