2017-03-09 83 views
1

我想使用反投影將JPG底圖投影到正投影上。我已經能夠在D3的v3中使用它,但是我在D3的v4中遇到了問題。出於某種原因,v4將源圖像的邊緣作爲背景(而不是我指定的黑色背景)。是否有任何已知的v4逆向投影問題或針對此問題的任何修復?D3 v4反轉功能

  • D3 v4 JSBin Link

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

回答

2

的問題是,反轉功能不是一一對應的。我知道有兩種方法可以解決問題。一,計算組成投影的光盤區域,並跳過該半徑之外的像素。或兩個(其中下面我使用),計算你的座標的前方突出,並查看它們是否匹配的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()只會返回您想要的值。

在上面的代碼塊中有一個容差因子用於舍入誤差,只要前向投影在原始x,y座標的半個像素內,它將被繪製(這似乎工作得很好) :

enter image description here

我有一個更新斌here(點擊運行,我未選中自動運行)。當然,與計算投影光盤的半徑(但該方法僅限於投影到光盤的投影)相比,這是計算上涉及的計算過程。

question的兩個答案可能能夠進一步解釋 - 他們涵蓋了兩種方法。

+0

非常感謝!我必須更清楚地閱讀你的答案,以及你提供的其他SO問題。 – Lprox5

+0

自從您的幫助以來,我已經能夠將一個拖曳功能(使用versor)應用於畫布圖像的正投影。我也可以疊加一個SVG點(代表過去任務的「着陸點」)。但是,我無法使用SVG拖動功能來處理這些問題。我有一個新的JSBin設置[在這裏](https://jsbin.com/moconod/edit?html,output)。任何想法爲什麼這可能是這種情況?我能夠用畫布繪製點,但是我發現爲點創建工具提示太困難了。 – Lprox5

+0

你可以不理會!我只是通過更新每個拖動功能中的地圖路徑來實現它的工作:) – Lprox5