【问题标题】:Mercator longitude and latitude calculations to x and y on a cropped map (of the UK)(英国)裁剪地图上 x 和 y 的墨卡托经度和纬度计算
【发布时间】:2011-01-07 10:00:20
【问题描述】:

我有这张图片。这是英国的地图(不包括南爱尔兰):

我已经成功地获得了一个纬度和经度,并将其绘制到这张地图上,方法是获取英国最左边的经度和最右边的经度,并使用它们来计算在地图上放置点的位置。

这是代码(用于Processing.js,但可以用作js或任何东西):

// Size of the map
int width = 538;
int height = 811;
// X and Y boundaries
float westLong = -8.166667;
float eastLong = 1.762833;
float northLat = 58.666667;
float southLat = 49.95;

void drawPoint(float latitude, float longitude){

 fill(#000000);

 x = width * ((westLong-longitude)/(westLong-eastLong));
 y = (height * ((northLat-latitude)/(northLat-southLat)));

 console.log(x + ", " + y);
 ellipseMode(RADIUS);
 ellipse(x, y, 2, 2);    

}

但是,我无法在这些值上实现墨卡托投影。这些图相当准确,但还不够好,这个投影可以解决它。

我不知道该怎么做。我找到的所有例子都在解释如何为全世界做这件事。 This 是一个很好的示例资源,解释了如何实现投影,但我无法让它工作。

另一个资源是Extreme points of the United Kingdom,我在其中获得了英国周围边界框的纬度和经度值。他们也在这里:

northLat = 58.666667; 
northLong = -3.366667; 
eastLat = 52.481167; 
eastLong = 1.762833; 
southLat = 49.95;
southLong = -5.2; 
westLat = 54.45;
westLong = -8.166667;

如果有人能帮我解决这个问题,我将不胜感激!

谢谢

【问题讨论】:

    标签: javascript geolocation projection processing.js proj4js


    【解决方案1】:

    我写了一个函数,它完全符合您的要求。我知道有点晚了,但也许还有其他人感兴趣。

    您需要一张墨卡托投影地图,并且您需要知道地图的纬度/经度位置。 您可以从TileMill 获得具有完美匹配纬度/经度位置的自定义墨卡托地图,MapBox 是免费软件!

    我正在使用这个脚本并用一些谷歌地球位置对其进行了测试。它在像素级别上完美运行。实际上,我没有在不同或更大的地图上对此进行测试。希望对你有帮助!

    拉斐尔 ;)

    <?php
    
    $mapWidth = 1500;
    $mapHeight = 1577;
    
    $mapLonLeft = 9.8;
    $mapLonRight = 10.2;
    $mapLonDelta = $mapLonRight - $mapLonLeft;
    
    $mapLatBottom = 53.45;
    $mapLatBottomDegree = $mapLatBottom * M_PI / 180;
    
    function convertGeoToPixel($lat, $lon)
    {
        global $mapWidth, $mapHeight, $mapLonLeft, $mapLonDelta, $mapLatBottom, $mapLatBottomDegree;
    
        $x = ($lon - $mapLonLeft) * ($mapWidth / $mapLonDelta);
    
        $lat = $lat * M_PI / 180;
        $worldMapWidth = (($mapWidth / $mapLonDelta) * 360) / (2 * M_PI);
        $mapOffsetY = ($worldMapWidth / 2 * log((1 + sin($mapLatBottomDegree)) / (1 - sin($mapLatBottomDegree))));
        $y = $mapHeight - (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);
    
        return array($x, $y);
    }
    
    $position = convertGeoToPixel(53.7, 9.95);
    echo "x: ".$position[0]." / ".$position[1];
    
    ?>
    

    这是我用 TileMill 创建的图像,我在这个例子中使用了它:

    【讨论】:

    • 感谢分享,很高兴有一些代码可以参考。这看起来像我最终的结果,但我最终是在 Javascript 中完成的。
    • 您是否愿意发布您使用这段代码的图像?谢谢!
    • 刚刚添加了图片。干杯,拉夫 ;)
    • @RaphaelWichmann 你有相反的吗?转换像素到地理()?我尝试将 xarinko 的答案转换为 Javascript,但没有得到相同的纬度/经度。我希望能够来回转换。
    • 非常感谢,这对我来说非常有用!在javascript中使用它就像一个魅力
    【解决方案2】:

    除了 Raphael Wichmann 发布的内容(顺便说一句,谢谢!), 这是在 actionscript 中的反向函数:

    function convertPixelToGeo(tx:Number, ty:Number):Point
    {   
        /* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI  */   
        var worldMapRadius:Number = mapWidth / mapLonDelta * 360/(2 * Math.PI);     
        var mapOffsetY:Number = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian))  ));
        var equatorY:Number = mapHeight + mapOffsetY;   
        var a:Number = (equatorY-ty)/worldMapRadius;
    
        var lat:Number = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
        var long:Number = mapLonLeft+tx/mapWidth*mapLonDelta;
        return new Point(lat,long);
    }
    

    【讨论】:

      【解决方案3】:

      我已将 Raphael 提供的 PHP 代码转换为 JavaScript,并且可以确认它可以正常工作,并且此代码可以自己工作。所有功劳归功于拉斐尔。

      /*
      var mapWidth = 1500;
      var mapHeight = 1577;
      
      var mapLonLeft = 9.8;
      var mapLonRight = 10.2;
      var mapLonDelta = mapLonRight - mapLonLeft;
      
      var mapLatBottom = 53.45;
      var mapLatBottomDegree = mapLatBottom * Math.PI / 180;
      */
      
      function convertGeoToPixel(latitude, longitude ,
                                 mapWidth , // in pixels
                                 mapHeight , // in pixels
                                 mapLonLeft , // in degrees
                                 mapLonDelta , // in degrees (mapLonRight - mapLonLeft);
                                 mapLatBottom , // in degrees
                                 mapLatBottomDegree) // in Radians
      {
          var x = (longitude - mapLonLeft) * (mapWidth / mapLonDelta);
      
          latitude = latitude * Math.PI / 180;
          var worldMapWidth = ((mapWidth / mapLonDelta) * 360) / (2 * Math.PI);
          var mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomDegree)) / (1 - Math.sin(mapLatBottomDegree))));
          var y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitude)) / (1 - Math.sin(latitude)))) - mapOffsetY);
      
          return { "x": x , "y": y};
      }
      

      【讨论】:

      • 感谢您的这种转换,它对我的​​需要非常有用,我已尝试为您和 Raphael 投票。
      【解决方案4】:

      这是另一个 Javascript 实现。这是上面@Rob Willet 解决方案的简化。它不需要计算值作为函数的参数,它只需要基本值并从中计算所有内容:

      function convertGeoToPixel(latitude, longitude,
                        mapWidth, // in pixels
                        mapHeight, // in pixels
                        mapLngLeft, // in degrees. the longitude of the left side of the map (i.e. the longitude of whatever is depicted on the left-most part of the map image)
                        mapLngRight, // in degrees. the longitude of the right side of the map
                        mapLatBottom) // in degrees.  the latitude of the bottom of the map
      {
          const mapLatBottomRad = mapLatBottom * Math.PI / 180
          const latitudeRad = latitude * Math.PI / 180
          const mapLngDelta = (mapLngRight - mapLngLeft)
      
          const worldMapWidth = ((mapWidth / mapLngDelta) * 360) / (2 * Math.PI)
          const mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomRad)) / (1 - Math.sin(mapLatBottomRad))))
      
          const x = (longitude - mapLngLeft) * (mapWidth / mapLngDelta)
          const y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitudeRad)) / (1 - Math.sin(latitudeRad)))) - mapOffsetY)
      
          return {x, y} // the pixel x,y value of this point on the map image
      }
      

      【讨论】:

      • 正确。一开始以为不行,后来发现地图底部的纬度不对
      【解决方案5】:

      我认为值得记住的是,并非所有平面地图都是墨卡托投影。如果不特别了解该地图,很难确定。您可能会发现世界上一小部分区域的大多数地图更可能是 圆锥形 类型的投影,其中地图上的感兴趣区域比全球墨卡托投影上的“更平坦” .离赤道越远,这一点尤其重要(而英国离它也足够远)。

      您可能能够使用您正在尝试的计算获得“足够接近”,但为了获得最佳准确性,您可能希望使用具有明确投影的地图,或者创建自己的地图。

      【讨论】:

      • 我相当肯定它是 - 在这个页面上:en.wikipedia.org/wiki/Mercator_projection#Uses 它提到谷歌地图使用投影。我将帖子中包含的地图(也可以在此处找到:en.wikipedia.org/wiki/File:Uk-map.svg)叠加到 Google 地图版本上,它们完全吻合,让我觉得确实如此。是否仍然可以使用墨卡托投影?如果不只是看看这是否能解决问题.. 还是我应该重新考虑我的地图?
      • @betamax:嗯,看起来那张地图可能确实是墨卡托。当然可以将纬度/经度投影到现有地图上,实际上您的线性插值方法应该适用于经度。但是,对于纬度,您需要使用该维基百科页面上提供的投影方程,并计算出实际纬度与地图坐标之间的关系。它应该是墨卡托y 和您的地图坐标y' 之间的线性关系(仅表示乘法和加法)。也就是说,对于某些 A 和 B,y' = Ay + B。
      【解决方案6】:

      我知道这个问题是不久前提出的,但 Proj4JS 库非常适合在 JavaScript 中的不同地图投影之间进行转换。

      英国地图倾向于使用基于横向墨卡托投影的 OSGB 国家网格。 IE。像传统的墨卡托,但旋转了 90 度,因此“赤道”变成了子午线。

      【讨论】:

        【解决方案7】:

        @Xarinko Actionscript sn-p in Javascript(带有一些测试值)

        var mapWidth = 1500;
        var mapHeight = 1577;
        
        var mapLonLeft = 9.8;
        var mapLonRight = 10.2;
        var mapLonDelta = mapLonRight - mapLonLeft;
        
        var mapLatBottom = 53.45;
        var mapLatBottomRadian = mapLatBottom * Math.PI / 180;
        
        
        
        function convertPixelToGeo(tx, ty)
        {   
            /* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI  */   
            var worldMapRadius = mapWidth / mapLonDelta * 360/(2 * Math.PI);     
            var mapOffsetY = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian))  ));
            var equatorY = mapHeight + mapOffsetY;   
            var a = (equatorY-ty)/worldMapRadius;
        
            var lat = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
            var long = mapLonLeft+tx/mapWidth*mapLonDelta;
            return [lat,long];
        }
        
        convertPixelToGeo(241,444)
        

        【讨论】:

          【解决方案8】:

          C#实现:

          private Point ConvertGeoToPixel(
              double latitude, double longitude, // The coordinate to translate
              int imageWidth, int imageHeight, // The dimensions of the target space (in pixels)
              double mapLonLeft, double mapLonRight, double mapLatBottom // The bounds of the target space (in geo coordinates)
          ) {
              double mapLatBottomRad = mapLatBottom * Math.PI / 180;
              double latitudeRad = latitude * Math.PI / 180;
          
              double mapLonDelta = mapLonRight - mapLonLeft;
              double worldMapWidth = (imageWidth / mapLonDelta * 360) / (2 * Math.PI);
              double mapOffsetY = worldMapWidth / 2 * Math.Log((1 + Math.Sin(mapLatBottomRad)) / (1 - Math.Sin(mapLatBottomRad)));
          
              double x = (longitude - mapLonLeft) * (imageWidth / mapLonDelta);
              double y = imageHeight - ((worldMapWidth / 2 * Math.Log((1 + Math.Sin(latitudeRad)) / (1 - Math.Sin(latitudeRad)))) - mapOffsetY);
          
              return new Point()
              {
                  X = Convert.ToInt32(x),
                  Y = Convert.ToInt32(y)
              };
          }
          

          【讨论】:

            【解决方案9】:

            如果您想避免 Proj4JS 固有的 lat/lng 投影的一些复杂方面,您可以使用 D3,它提供了许多内置投影并呈现精美。这是几种方位角投影的interactive example。对于美国地图,我更喜欢 Albers。

            如果 D3 不是最终用户选项——比如说,你需要支持 IE 7/8——你可以在 D3 中渲染,然后从 D3 生成的 SVG 文件中获取 xy 坐标。然后,您可以在 Raphael 中渲染这些 xy 坐标。

            【讨论】:

              【解决方案10】:

              这个函数对我很有用,因为我想根据我想要绘制的地图定义 mapHeight。我正在生成 PDF 地图。我需要做的就是传入地图的 max Lat , min Lon ,然后它将地图的像素大小返回为 [height,width]。

              convertGeoToPixel(最大纬度,最大经度)

              在设置 $y 的最后一步中注意,如果您的坐标系“xy”从底部/左侧开始,请不要从 mapHeight 中减去计算,就像 PDF 一样,这将反转地图。

              $y =  (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);
              

              【讨论】:

                猜你喜欢
                • 2012-12-29
                • 2011-10-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多