Issue with applying projection to graticule in D3 and Three.js: unable to execute projection on graticule

My current project involves creating 3D graticules using three.js. The process starts by constructing a mollweide projection graticule in SVG with D3, followed by extracting the graticule path points and converting them to three.js vectors.

However, the resulting three.js graticule turns out to be just a sphere graticule and does not align with the desired projection (mollweide) points. Any suggestions on how to resolve this issue?

You can see the example file below. The problematic function is vertex(point)

 <!DOCTYPE HTML>

<html>

<head>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/r86/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/r86/examples/js/controls/OrbitControls.js"></script>

  <title>3D Mollweide Projection</title>
  <style type="text/css">
  <!--
 .background {
  fill: #a4bac7;
}

.foreground {
  fill: none;
  stroke: #333;
  stroke-width: 1.5px;
}

.graticule {
  fill: none;
  stroke: #fff;
  stroke-width: .5px;
}


  -->
  </style>
</head>

<body style=font-family:arial>

<center>SVG Drawing (mollweide projection):</center>
<svg id=projectionSVG width=600 height=440 overflow=visible />
Three.js Drawing (rotate and mousewheel zoom):<br>
<div  id=container></div>

<script>
var projection
var gratPathPointArray=[]
var radius = 230


//----build svg graticule----
    projection = d3.geo.mollweide()
    .scale(120);

    var path = d3.geo.path()
    .projection(projection);

    var graticule = d3.geo.graticule();

    var svg= d3.select("#projectionSVG")
    svg.append("path")
    .datum(graticule.outline)
    .attr("class", "background")
    .attr("d", path);

    var graticuleG=svg.append("g")
    .attr("class", "graticule")
    .selectAll("path")
    .data(graticule.lines)
    .enter().append("path")
    .attr("d", path);


    var graticulePathG=projectionSVG.lastChild

    var graticulePaths=graticulePathG.childNodes
    for(p=0;p<graticulePaths.length;p++)
    {
        var holdArray=[]
        var graticulePath=graticulePaths[p]
        var d=graticulePath.getAttribute("d")
        var d=d.replace(/M/,"").replace(/L/g,",")
        var dSplit=d.split(",")
        for(var k=0;k<dSplit.length;k++)
        {
        var x=dSplit[k]
        var y=dSplit[k+1]
        holdArray.push([x,y])
        k++
        }
        gratPathPointArray.push(holdArray)
    }

    threeJSVectors()

function threeJSVectors()
{
    initThree()

    var geometry = new THREE.Geometry();
    var material= new THREE.LineBasicMaterial({color: 0xaaaaaa})


    var splineVectors=[]
    //=========graticule lines==============
    gratPathPointArray.forEach(function(line)
    {
        d3.pairs(line.map(vertex), function(a, b)
        {
            geometry.vertices.push(a, b);
        });
    });

    scene.add( new THREE.LineSegments(geometry, material))

    animate()
    render()
}

//----build three.js graticule---
var renderer,camera,controls,scene
function initThree()
{
    var width = 600,
    height = 600

    scene = new THREE.Scene;
    camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000);
    renderer = new THREE.WebGLRenderer({alpha: true});

    camera.position.x = -7;
    camera position.y = -245;
    camera position.z = 315;
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(width, height);
    container.appendChild(renderer.domElement);
    controls = new THREE.OrbitControls( camera,renderer.domElement );
    controls.addEventListener( 'change', render );
}
//---does not apply projection???---
//--convert path point to vector---
function vertex(point)
{
    //---get lng/lat degrees of each projection point--
     var invertLL=projection.invert(point)
       //---to radians--
    var lambda = invertLL[0] * Math.PI / 180,
    phi = invertLLi[1] * Math.PI / 180,
    cosPhi = Math.cos(phi);
    return new THREE.Vector3(
        radius * cosPhi * Math.cos(lambda),
        radius * cosPhi * Math.sin(lambda),
        radiusd * Math.sin(phi)
    );
}

function animate()
{
requestAnimationFrame(animate);
controls.update();
}

function render()
{
camera lookAt( scene.position );
    renderer.render(scene, camera);

}
</script>

</body>
</html>

Answer №1

I can't quite figure out what you're attempting to accomplish there :) Your vertex (point) function accurately determines the 3D location of a 2D point, which helps with reconstructing the globe. However, if you're looking for a flat shape instead, consider this:

 <!DOCTYPE HTML>

<html>

<head>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/r86/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/r86/examples/js/controls/OrbitControls.js"></script>

  <title>3D Mollweide Projection</title>
  <style type="text/css">
  <!--
 .background {
  fill: #a4bac7;
}

.foreground {
  fill: none;
  stroke: #333;
  stroke-width: 1.5px;
}

.graticule {
  fill: none;
  stroke: #fff;
  stroke-width: .5px;
}


  -->
  </style>
</head>

<body style=font-family:arial>

<center>SVG Drawing (mollweide projection):</center>
<svg id=projectionSVG width=600 height=440 overflow=visible />
Three.js Drawing (rotate and mousewheel zoom):<br>
<div  id=container></div>

<script>
var projection
var gratPathPointArray=[]
var radius = 230


//----build svg graticule----
    projection = d3.geo.mollweide()
    .scale(120);

    var path = d3.geo.path()
    .projection(projection);

    var graticule = d3.geo.graticule();

    var svg= d3.select("#projectionSVG")
    svg.append("path")
    .datum(graticule.outline)
    .attr("class", "background")
    .attr("d", path);

    var graticuleG=svg.append("g")
    .attr("class", "graticule")
    .selectAll("path")
    .data(graticule.lines)
    .enter().append("path")
    .attr("d", path);


    var graticulePathG=projectionSVG.lastChild

    var graticulePaths=graticulePathG.childNodes
    for(p=0;p<graticulePaths.length;p++)
    {
        var holdArray=[]
        var graticulePath=graticulePaths[p]
        var d=graticulePath.getAttribute("d")
        var d=d.replace(/M/,"").replace(/L/g,",")
        var dSplit=d.split(",")
        for(var k=0;k<dSplit.length;k++)
        {
        var x=dSplit[k]
        var y=dSplit[k+1]
        holdArray.push([x,y])
        k++
        }
        gratPathPointArray.push(holdArray)
    }

    threeJSVectors()

function threeJSVectors()
{
    initThree()

    var geometry = new THREE.Geometry();
    var material= new THREE.LineBasicMaterial({color: 0xaaaaaa})


    var splineVectors=[]
    //=========graticule lines==============
    gratPathPointArray.forEach(function(line)
    {
        d3.pairs(line.map(vertex), function(a, b)
        {
            geometry.vertices.push(a, b);
        });
    });

    scene.add( new THREE.LineSegments(geometry, material))

    animate()
    render()
}

//----build three.js graticule---
var renderer,camera,controls,scene
function initThree()
{
    var width = 600,
    height = 600

    scene = new THREE.Scene;
    camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000);
    renderer = new THREE.WebGLRenderer({alpha: true});

    camera.position.x = -7;
    camera.position.y = -245;
    camera.position.z = 315;
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(width, height);
    container.appendChild(renderer.domElement);
    controls = new THREE.OrbitControls( camera,renderer.domElement );
    controls.addEventListener( 'change', render );
}
//---does not apply projection????---
//--convert path point to vector---
function vertex(point)
{
    return new THREE.Vector3(
        point[0] - 500,
        point[1] - 150,
        0
    );
}

function animate()
{
requestAnimationFrame(animate);
controls.update();
}

function render()
{
camera.lookAt( scene.position );
    renderer.render(scene, camera);

}
</script>

</body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Loading a gallery dynamically using AJAX in a CakePHP application

I am currently working with Cakephp 2.8.0 and I am facing an issue with implementing ajax in my application. I have a list of categories displayed as li links, and upon clicking on a category, I need to remove certain html code, locate the necessary catego ...

What is the best way to adjust the transparency of the document.body?

Is it possible to set the body of a website to have a low opacity while keeping a popup at full opacity to make it stand out? I attempted to specify the popup with opacity: 1 !important; but it didn't work as expected. Can you help me figure out how ...

The Ajax script is failing to retrieve search results

I am encountering an issue with my normal AJAX search functionality in which I need to retrieve data from a database when the form is submitted. The problem arises when trying to filter data between two specific dates using separate pages, it works fine bu ...

Surprising Interactions Between Ajax and PHP

I am encountering an issue with my ajax request to a php page. The PHP script successfully sets a cookie, but the message sent back using the echo function is not appearing in the response. I have confirmed this by logging the XMLHTTPRequest Object in the ...

Encountering a white screen while loading StaticQuery on Gatsby website

I encountered an error that has been reported in this GitHub issue: https://github.com/gatsbyjs/gatsby/issues/25920. It seems like the Gatsby team is currently occupied and unable to provide a solution, so I'm reaching out here for help. Just to clar ...

Is the "json_encode" function dropping the '+' character when using "json.parse"?

Seeking Assistance I have a question regarding the functionality of php function json_encode and js JSON.parse. I seem to be encountering an issue where the '+' character is being dropped somewhere in the process, particularly when dealing with ...

The JQuery datepicker fails to display the current date

I am experiencing an issue with the datepicker on my webpage. While it is working correctly, the default date being displayed is '01/01/2001' instead of '11/23/2012', as I intended. Here is the jquery code I am using: $(":inpu ...

What is the purpose of using $ symbols within NodeJS?

Lately, I've been attempting to grasp the ins and outs of using/installing NodeJS. Unfortunately, I'm feeling a bit lost due to tutorials like the one found here and their utilization of the mysterious $ symbol. Take for instance where it suggest ...

Adding textures to the interior of a 3D cube using three.js

I'm currently experimenting with applying unique images to each face of a cube, specifically on the interior. Check out my demonstration here: http://codepen.io/anon/pen/mymOKe This is how I am loading the images: var material = [ n ...

Adjust the cell text overflow based on the width of the table

I am working with a table that has multiple columns. I want the first 3 columns to have a larger width than the others, specifically taking up 15% each for a total of 45% of the table's width. Currently, I am using this code in a sandbox environment: ...

Invisible Thinglink image revealed upon resizing browser

I am currently repurposing a pre-existing theme that has a drop-down menu showcasing an image. I am attempting to integrate a Thinglink into the content section of this drop-down, but unfortunately, the image does not appear until I adjust the size of the ...

What is the best way to halt the ticking of this clock in JavaScript?

I can't seem to figure out how to stop this clock using JavaScript Even though I press the stop button, the clock keeps running <!DOCTYPE html> <html> <head> <h1> Welcome to the clock. Press the stop button to halt the clo ...

I am looking to download a file from a server and showcase it in a browser using React.js. The file will be received as a response from the

**I am looking to retrieve a file from the server by sending the file name through the body and then receiving the requested file from the server.** I have successfully received the file in response from the server, which I tested using Postman. What I a ...

Changing images dynamically using Three.js

I have a 3D object with a texture applied as a jpg. I am looking for a way to change this image when a button is clicked. Is this possible and how can it be done? var loader = new THREE.ImageLoader(manager); loader.load('models/obj/dla/dla.jpg', ...

Integrating a footer into the enhanced search tab slider

I'm struggling to create a sticky footer like the one on w3schools. Even though I used the same code in my material UI demo, it's not functioning properly. I tried debugging by changing the position from fixed to absolute, but it still isn&apos ...

jQuery animation that smoothly fades out from the left and fades in from the right

This survey is designed to assist individuals in determining where they should go with a specific type of ticket. Currently, everything is functioning smoothly, but I would like to add a sleek animation to each ul transition. Whenever a button is clicked ...

Refreshing the page triggers the callback function that retrieves the checkboxes selected in a Kendo treeview component

How can I retain the selected checkboxes after refreshing the page? Is there a way to achieve this using AJAX when submitting data to a database and then reloading the page? AJAX //AJAX call for button $("#primaryTextButton").kendoButton(); va ...

Determine the shared elements within a single array by utilizing Javascript

I have the following array of mergeUniqueItems: var mergeUniqueItems = ["-JsDEcxz_ZSGFLKwd1QM", "-JsJ2NXGDYKI6QRsuXVK", "-JsJ2RK-kOG2eGcG04xF", "-JsJ2RK-kOG2eGcG04xF", "-JsJ2YLPiP6751zh8geS"] After using this code snippet, I encountered an issue: ...

AngularJS: The blend of bo-bind, bindonce, and the translate filter

I am currently working with angular 1.2.25, angular-translate 2.0.1, angular-translate-loader-static-files 2.0.0, and angular-bindonce 0.3.1. My goal is to translate a static key using bindonce. Here is the code snippet I have: <div bindonce> < ...

Have developers created an event trigger for when google maps controls finish loading?

While I am aware of the tilesloaded event, it appears that the controls load after this event. My goal is to use jQuery to retrieve the controls, but I am struggling to identify the appropriate event to listen for. ...