首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Miller投影到像素

Miller投影到像素
EN

Stack Overflow用户
提问于 2018-04-20 16:25:55
回答 1查看 413关注 0票数 2

我试图使用Miller投影将坐标转换为像素。我的方法如下所示:

代码语言:javascript
复制
function millerProjection(lat, lng) {

        // Create sec() function //
        function sec(value) {
            return 1/Math.cos(value);
        }

        // Create fucntion to change degree to radian //
        function toRadian(value) {
            return value * Math.PI / 180;
        }

        lng = toRadian(lng);
        lat = toRadian(lat);

        // Miller Projection
        // var x = lng;
        // var y = 1.25 * Math.log(Math.tan(Math.PI / 4 + 0.4 * (lat)));

        // Mercator Projection
        // var x  = lng;
        // var y = Math.log(Math.tan(lat) + sec(lat));

        var mapSet = {
            leftLong: toRadian(-180),
            rightLong: toRadian(180),
            topLat: toRadian(90),
            bottomLat: toRadian(-90),
            imageWidth: 2057,
            imageHeight: 1512,
        }

        var x = (lng - mapSet.leftLong) * (mapSet.imageWidth / (mapSet.rightLong - mapSet.leftLong));
        var y = (mapSet.topLat - lat) * (mapSet.imageHeight / (mapSet.topLat - mapSet.bottomLat));

        console.log(`Miller Projection X: ${x} -- Y: ${y}`);

        return { x: x,  y: y };

    }

我用这张图片作为地图:SW.jpg

显然,如果我使用0,0坐标,它标记正确的位置。如果我给它其他坐标,它就不起作用了。地图是问题吗?还是我使用的逻辑有问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-25 21:54:41

这是:

代码语言:javascript
复制
  var x = (lng - mapSet.leftLong) * (mapSet.imageWidth / (mapSet.rightLong - mapSet.leftLong));
  var y = (mapSet.topLat - lat) * (mapSet.imageHeight / (mapSet.topLat - mapSet.bottomLat));

假设对纬度和经度都进行线性x和y变换,但这只发生在经度上。您可以在所引用的图像中看到纬度之间的不同间距。

让我们回到您注释掉的投影,并使用它是正确的,但需要缩放和翻译:

代码语言:javascript
复制
function millerProjection(lat, lng) {

  // Create sec() function
  function sec(value) {
    return 1/Math.cos(value);
  }

 // Create fucntion to change degree to radians
 function toRadian(value) {
   return value * Math.PI / 180;
 }
 
 lng = toRadian(lng);
 lat = toRadian(lat);

 // Miller Projection
 var x = lng;
 var y = 1.25*Math.log(Math.tan(Math.PI/4+0.4*(lat)));
 
 return [x,y];
 
}

console.log(millerProjection(90,180));
console.log(millerProjection(-90,-180));

X轴的输出范围是-π到+π,y轴的范围大约是该轴的0.733倍。

现在我们可以缩放和翻译了。我会先缩放,然后再翻译,反之亦然。

要进行缩放,我们需要知道边框的宽度或高度或输出范围。方面是固定的,所以这是最简单的,如果没有指定两者,而是确定一个从另一个。如果我们不均匀地拉伸输出,我们就不再有一个磨坊。

给定一个宽度维度,我们可以使用如下内容进行缩放:

代码语言:javascript
复制
var scale = width / Math.PI / 2; 

我们想看看每个弧度需要多少像素。然后,我们可以将投影输出乘以比例,得到缩放值。使用上述方法,我们还可以使用像d3的地理投影模块这样的库来验证我们的投影:

代码语言:javascript
复制
function millerProjection(lat, lng) {

  // Create sec() function
  function sec(value) {
    return 1/Math.cos(value);
  }

 // Create fucntion to change degree to radians
 function toRadian(value) {
   return value * Math.PI / 180;
 }
 
 lng = toRadian(lng);
 lat = toRadian(lat);

 // Miller Projection
 var x = lng;
 var y = -1.25*Math.log(Math.tan(Math.PI/4+0.4*(lat)));
 
 var width = 360;
 var scale = width/Math.PI/2;
 x *= scale;
 y *= scale;
 
 return [x,y];
 
}

//// 
// set up reference scale:
var width = 360;
var height = width / Math.PI / 2.303412543376391; // aspect ratio

// set d3 projection for reference:
var d3Miller = d3.geoMiller()
 .fitSize([360,180*0.7331989845], {"type": "Polygon","coordinates": [[[180, 90], [-180, 90], [-90, -180], [180, 90]]] })
	.translate([0,0]);
  
// compare the two:
console.log("90N,180W:")
console.log("Miller:  ", ...millerProjection(90,-180));
console.log("d3Miller:", ...d3Miller([-180,90]));

console.log("90S,180E:")
console.log("Miller:  ",...millerProjection(-90,180));
console.log("d3Miller:", ...d3Miller([180,-90]));

console.log("90S,180E:")
console.log("Miller:  ",...millerProjection(-57,162));
console.log("d3Miller:", ...d3Miller([162,-57]));
代码语言:javascript
复制
.as-console-wrapper { max-height: 100% !important; top: 0; }
代码语言:javascript
复制
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>

我取了纬度的负值(根据你的例子),因为当投影的地理坐标在底部有y=0时,y值随着移动而增加。相反,类似的事情(大多数?)图像顶部有y=0,y值随着移动而增加。D3预期后一种约定,所以我没有为引用函数这样做。

看起来不错。我们的数据现在在x轴上有一个从-width/2width/2的范围,在y上也是这个值的0.733倍。让我们翻译一下数据,这样它就占据了左下角坐标为0,0和宽度*0.733的右上坐标的边框。这很容易,在我们缩放数据之后,我们将width/2添加到x值,width/2*0.733 (或者更准确地说,是width/2/*0.7331989845)添加到y值中:

代码语言:javascript
复制
function millerProjection(lat, lng) {

  // Create sec() function
  function sec(value) {
    return 1/Math.cos(value);
  }

 // Create fucntion to change degree to radians
 function toRadian(value) {
   return value * Math.PI / 180;
 }
 
 lng = toRadian(lng);
 lat = toRadian(lat);

 // Miller Projection
 var x = lng;
 var y = -1.25*Math.log(Math.tan(Math.PI/4+0.4*(lat)));
 
 var width = 2057;
 var scale = width/Math.PI/2;
 x *= scale;
 y *= scale;
 
 x += width/2;
 y += width/2*0.7331989845
 
 return [x,y];
 
}
  
// compare the two:
console.log("90N,180W:")
console.log("Miller:  ", ...millerProjection(90,-180));

console.log("90S,180E:")
console.log("Miller:  ",...millerProjection(-90,180));

console.log("45N,45E:")
console.log("Miller:  ",...millerProjection(45,45));

console.log("90S,180E:")
console.log("Miller:  ",...millerProjection(-57,162));
代码语言:javascript
复制
.as-console-wrapper { max-height: 100% !important; top: 0; }
代码语言:javascript
复制
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>

当然,如果您正在进行图像处理,其中顶部应该是y=0,而y值在向下移动时会增加,那么在进行任何操作之前,请翻转纬度的符号。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49945993

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档