D3 v4 反转功能
D3 v4 invert function
我正在尝试使用逆投影将 JPG 底图投影到正交投影上。我已经能够让它在 D3 的 v3 中工作,但我在 D3 的 v4 中遇到了问题。出于某种原因,v4 将源图像的边缘作为背景(而不是我指定的黑色背景)。 v4 中的逆投影是否存在任何已知问题或对此有任何修复?
-
<title>Final Project</title>
<style>
canvas {
background-color: black;
}
</style>
<body>
<div id="canvas-image-orthographic"></div>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
// Canvas element width and height
var width = 960,
height = 500;
// Append the canvas element to the container div
var div = d3.select('#canvas-image-orthographic'),
canvas = div.append('canvas')
.attr('width', width)
.attr('height', height);
// Get the 2D context of the canvas instance
var context = canvas.node().getContext('2d');
// Create and configure the Equirectangular projection
var equirectangular = d3.geoEquirectangular()
.scale(width / (2 * Math.PI))
.translate([width / 2, height / 2]);
// Create and configure the Orthographic projection
var orthographic = d3.geoOrthographic()
.scale(Math.sqrt(2) * height / Math.PI)
.translate([width / 2, height / 2])
.clipAngle(90);
// Create the image element
var image = new Image(width, height);
image.crossOrigin = "Anonymous";
image.onload = onLoad;
image.src = 'https://tatornator12.github.io/classes/final-project/32908689360_24792ca036_k.jpg';
// Copy the image to the canvas context
function onLoad() {
// Copy the image to the canvas area
context.drawImage(image, 0, 0, image.width, image.height);
// Reads the source image data from the canvas context
var sourceData = context.getImageData(0, 0, image.width, image.height).data;
// Creates an empty target image and gets its data
var target = context.createImageData(image.width, image.height),
targetData = target.data;
// Iterate in the target image
for (var x = 0, w = image.width; x < w; x += 1) {
for (var y = 0, h = image.height; y < h; y += 1) {
// Compute the geographic coordinates of the current pixel
var coords = orthographic.invert([x, y]);
// Source and target image indices
var targetIndex,
sourceIndex,
pixels;
// Check if the inverse projection is defined
if ((!isNaN(coords[0])) && (!isNaN(coords[1]))) {
// Compute the source pixel coordinates
pixels = equirectangular(coords);
// Compute the index of the red channel
sourceIndex = 4 * (Math.floor(pixels[0]) + w * Math.floor(pixels[1]));
sourceIndex = sourceIndex - (sourceIndex % 4);
targetIndex = 4 * (x + w * y);
targetIndex = targetIndex - (targetIndex % 4);
// Copy the red, green, blue and alpha channels
targetData[targetIndex] = sourceData[sourceIndex];
targetData[targetIndex + 1] = sourceData[sourceIndex + 1];
targetData[targetIndex + 2] = sourceData[sourceIndex + 2];
targetData[targetIndex + 3] = sourceData[sourceIndex + 3];
}
}
}
// Clear the canvas element and copy the target image
context.clearRect(0, 0, image.width, image.height);
context.putImageData(target, 0, 0);
}
</script>
问题是反转函数不是一对一的。我知道有两种方法可以解决问题。第一,计算构成投影的圆盘面积并跳过该半径之外的像素。或者两个(我在下面使用),计算你的坐标的前向投影,看看它们是否匹配你开始的 x,y 坐标:
if (
(Math.abs(x - orthographic(coords)[0]) < 0.5 ) &&
(Math.abs(y - orthographic(coords)[1]) < 0.5 )
)
基本上这个问题是 [x,y]
等于 projection(projection.invert([x,y]))
。通过确保此语句相等(或接近相等),则像素确实在投影盘中。这是必需的,因为多个 svg 点可以表示给定的经纬度,但 projection()
returns 只是您想要的那个。
上面的代码块中有一个舍入误差的容差因子,只要前向投影在原始 x,y 坐标的半个像素以内,它就会被绘制(这看起来工作得很好):
我有一个更新的垃圾箱 here(点击 运行,我取消选中自动 运行)。
与计算投影圆盘的半径相比,这自然是计算量更大的过程(但该方法仅限于投影到圆盘的投影)。
这个 的两个答案也许可以进一步解释 - 它们涵盖了两种方法。
我正在尝试使用逆投影将 JPG 底图投影到正交投影上。我已经能够让它在 D3 的 v3 中工作,但我在 D3 的 v4 中遇到了问题。出于某种原因,v4 将源图像的边缘作为背景(而不是我指定的黑色背景)。 v4 中的逆投影是否存在任何已知问题或对此有任何修复?
-
<title>Final Project</title> <style> canvas { background-color: black; } </style> <body> <div id="canvas-image-orthographic"></div> <script src="//d3js.org/d3.v4.min.js"></script> <script> // Canvas element width and height var width = 960, height = 500; // Append the canvas element to the container div var div = d3.select('#canvas-image-orthographic'), canvas = div.append('canvas') .attr('width', width) .attr('height', height); // Get the 2D context of the canvas instance var context = canvas.node().getContext('2d'); // Create and configure the Equirectangular projection var equirectangular = d3.geoEquirectangular() .scale(width / (2 * Math.PI)) .translate([width / 2, height / 2]); // Create and configure the Orthographic projection var orthographic = d3.geoOrthographic() .scale(Math.sqrt(2) * height / Math.PI) .translate([width / 2, height / 2]) .clipAngle(90); // Create the image element var image = new Image(width, height); image.crossOrigin = "Anonymous"; image.onload = onLoad; image.src = 'https://tatornator12.github.io/classes/final-project/32908689360_24792ca036_k.jpg'; // Copy the image to the canvas context function onLoad() { // Copy the image to the canvas area context.drawImage(image, 0, 0, image.width, image.height); // Reads the source image data from the canvas context var sourceData = context.getImageData(0, 0, image.width, image.height).data; // Creates an empty target image and gets its data var target = context.createImageData(image.width, image.height), targetData = target.data; // Iterate in the target image for (var x = 0, w = image.width; x < w; x += 1) { for (var y = 0, h = image.height; y < h; y += 1) { // Compute the geographic coordinates of the current pixel var coords = orthographic.invert([x, y]); // Source and target image indices var targetIndex, sourceIndex, pixels; // Check if the inverse projection is defined if ((!isNaN(coords[0])) && (!isNaN(coords[1]))) { // Compute the source pixel coordinates pixels = equirectangular(coords); // Compute the index of the red channel sourceIndex = 4 * (Math.floor(pixels[0]) + w * Math.floor(pixels[1])); sourceIndex = sourceIndex - (sourceIndex % 4); targetIndex = 4 * (x + w * y); targetIndex = targetIndex - (targetIndex % 4); // Copy the red, green, blue and alpha channels targetData[targetIndex] = sourceData[sourceIndex]; targetData[targetIndex + 1] = sourceData[sourceIndex + 1]; targetData[targetIndex + 2] = sourceData[sourceIndex + 2]; targetData[targetIndex + 3] = sourceData[sourceIndex + 3]; } } } // Clear the canvas element and copy the target image context.clearRect(0, 0, image.width, image.height); context.putImageData(target, 0, 0); } </script>
问题是反转函数不是一对一的。我知道有两种方法可以解决问题。第一,计算构成投影的圆盘面积并跳过该半径之外的像素。或者两个(我在下面使用),计算你的坐标的前向投影,看看它们是否匹配你开始的 x,y 坐标:
if (
(Math.abs(x - orthographic(coords)[0]) < 0.5 ) &&
(Math.abs(y - orthographic(coords)[1]) < 0.5 )
)
基本上这个问题是 [x,y]
等于 projection(projection.invert([x,y]))
。通过确保此语句相等(或接近相等),则像素确实在投影盘中。这是必需的,因为多个 svg 点可以表示给定的经纬度,但 projection()
returns 只是您想要的那个。
上面的代码块中有一个舍入误差的容差因子,只要前向投影在原始 x,y 坐标的半个像素以内,它就会被绘制(这看起来工作得很好):
我有一个更新的垃圾箱 here(点击 运行,我取消选中自动 运行)。
与计算投影圆盘的半径相比,这自然是计算量更大的过程(但该方法仅限于投影到圆盘的投影)。
这个