简体   繁体   English

D3 v4反转功能

[英]D3 v4 invert function

I am trying to project a JPG basemap onto an Orthographic projection using the inverse projection. 我正在尝试使用逆投影将JPG底图投影到正交投影上。 I have been able to get it working in v3 of D3, but I am having an issue in v4 of D3. 我已经能够在D3的v3中运行它,但是在D3的v4中存在问题。 For some reason, v4 gives me the edge of the source image as the background (rather than the black background I have specified). 由于某些原因,v4给我源图像的边缘作为背景(而不是我指定的黑色背景)。 Are there any known issues with the inverse projection in v4 or any fixes for this? v4中的逆投影是否存在任何已知问题,或者对此有任何解决方法?

  • D3 v4 JSBin Link D3 v4 JSBin链接

     <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> 

The problem is that the invert function is not one to one. 问题在于反相功能不是一对一的。 There are two ways that I'm aware of that can solve the problem. 我知道有两种方法可以解决问题。 One, calculate the area of the disc that makes up the projection and skip pixels that are outside of that radius. 一种是,计算组成投影的光盘区域,并跳过该半径之外的像素。 Or two (which I use below), calculate the forward projection of your coordinates and see if they match the x,y coordinates that you started with: 或两个(我在下面使用),计算坐标的正向投影,看看它们是否与您开始的x,y坐标匹配:

if ( 
  (Math.abs(x - orthographic(coords)[0]) < 0.5 ) &&
  (Math.abs(y - orthographic(coords)[1]) < 0.5 ) 
 ) 

Essentially this asks is [x,y] equal to projection(projection.invert([x,y])) . 本质上,这要求[x,y]等于projection(projection.invert([x,y])) By ensuring that this statement is equal (or near equal) then the pixel is indeed in the projection disc. 通过确保该陈述相等(或近似相等),则像素确实在投影盘中。 This is needed as multiple svg points can represent a given lat long but projection() returns only the one you want. 这是需要的,因为多个svg点可以表示给定的经度,但是projection()仅返回您想要的一个。

There is a tolerance factor there for rounding errors in the code block above, as long as the forward projection is within half a pixel of the original x,y coordinate it'll be drawn (which appears to work pretty well): 只要向前投影在原始x,y坐标的半个像素之内,就会在上面的代码块中存在一个舍入误差的容限因子(看起来效果很好):

在此处输入图片说明

I've got an updated bin here (click run, I unchecked auto run). 我在这里有一个更新的bin(单击运行,我未选中自动运行)。

Naturally this is the more computationally involved process when compared to calculating the radius of the projection disc (but that method is limited to projections that project to a disc). 与计算投影光盘的半径相比,自然地,这是计算量更大的过程(但是该方法仅限于投影到光盘上的投影)。

This question 's two answers might be able to explain further - they cover both approaches. 这个问题的两个答案可能可以进一步解释-它们涵盖了两种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM