我尝试使用Miller Projection将坐标转换为像素。 我的方法如下:
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 };
}
我将此图片用作地图: https://upload.wikimedia.org/wikipedia/commons/5/5f/Miller_projection_SW.jpg
显然如果我使用0,0坐标则标记正确的位置。 如果我给它任何其他坐标它不起作用。地图可能是问题,还是我使用的逻辑存在问题?
答案 0 :(得分:1)
此:
var x = (lng - mapSet.leftLong) * (mapSet.imageWidth / (mapSet.rightLong - mapSet.leftLong));
var y = (mapSet.topLat - lat) * (mapSet.imageHeight / (mapSet.topLat - mapSet.bottomLat));
假设纬度和经度都有线性x和y变换,但这仅适用于经度。您可以在参考图像中看到纬度之间的不同间距。
让我们回到您评论的投影并使用它,因为它是正确的,但需要缩放和翻译:
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倍。
现在我们可以扩展和翻译。我会先缩放并稍后翻译,但反之亦然。
要缩放,我们需要知道边界框或输出范围的宽度或高度。方面是固定的,所以如果不指定两者,这是最简单的,而是从另一个中确定一个。如果我们不均衡地拉伸输出,我们就不再有米勒了。
考虑到宽度的尺寸,我们可以使用以下内容进行缩放:
var scale = width / Math.PI / 2;
我们希望看到每个弧度需要多少像素。然后我们可以通过比例多次投影输出来获得缩放值。使用上述内容,我们还可以使用d3的地理平台模块库来验证我们的投影:
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]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<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/2
到width/2
,在y轴上的范围为约0.733倍。让我们翻译数据,使其占据左下坐标[0,0]和右上坐标[宽,宽* 0.733]的边界框。这相当容易,在我们缩放数据后,我们将width/2
添加到x值,将width/2*0.733
(或稍微更准确地说,width/2/*0.7331989845
)添加到y值:
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));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<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值会增加,请在进行任何操作之前翻转纬度的符号。