样条弧在三个js球体上不工作

splines arc on three js globe not working

本文关键字:js 工作 三个 样条      更新时间:2023-09-26

我一直在遵循关于在three.js球体周围映射弧的几个示例。我几乎把这个工作,虽然我有困难得到正确的数学和最终的投影是不正确的。我很感激任何人看看代码,告诉我我做错了什么。由于

import oHoverable from 'o-hoverable';
import d3 from 'd3';
import oHeader from 'o-header';
import THREE from 'three.js';

// var OrbitControls = require('three-orbit-controls')(THREE);
// console.log("orbitControls=",OrbitControls);

oHoverable.init(); // makes hover effects work on touch devices
document.addEventListener('DOMContentLoaded', function () {
  oHoverable.init(); // makes hover effects work on touch devices
  var dataset=spreadsheet.data
  console.log(dataset)
    // This let's you inspect the resulting image in the console.
    //console.log(canvas.node().toDataURL()); //F

  var startLon=45
  var startLat=75
  var endLon=0
  var endLat=0
  var posX = 200;
  var posY = 600;
  var posZ = 1800;
  var width = document.getElementById('main').getBoundingClientRect().width;
  var height = 600;
  var FOV = 45;
  var NEAR = 2;
  var FAR = 4000;
  var controls;
  // some global variables and initialization code 
  // simple basic renderer
  var renderer = new THREE.WebGLRenderer();
  renderer.setSize(width,height);
  renderer.setClearColor( 0x000000, 1);
  // add it to the target element
  var globeDiv = document.getElementById("globeDiv");
  globeDiv.appendChild(renderer.domElement);
  // setup a camera that points to the center
  var camera = new THREE.PerspectiveCamera(FOV,width/height,NEAR,FAR);
  camera.position.set(posX,posY, posZ);
  camera.lookAt(new THREE.Vector3(0,0,0));
  // create a basic scene and add the camera
  var scene = new THREE.Scene();
  scene.add(camera);
  //spotlight set up in the same location as the camera
  var light = new THREE.DirectionalLight(0xffffff, 1.0, 200 );
  light.position.set(posX,posY,posZ);
  scene.add(light);
  //Add Earth
  var radious=650
  var line
  // var earthGeo=new THREE.SphereGeometry(radious,100,100);
  // var earthMat=new THREE.MeshPhongMaterial();
  // earthMat.map=THREE.ImageUtils.loadTexture("images/world.jpg");
  // earthMat.bumpMap=THREE.ImageUtils.loadTexture("images/bumpmap.jpg");
  // earthMat.bumpScale=8;
  // earthMat.shininess=10;
  // var earthObject = new THREE.Mesh(earthGeo,earthMat);
  // scene.add(earthObject);
  // //Add clouds
  // var cloudGeo=new THREE.SphereGeometry(radious,60,60);
  // var cloudsMat=new THREE.MeshPhongMaterial({
  //     opacity: 0.5,
  //     transparent: true,
  //     color: 0xffffff
  // });
  // cloudsMat.map=THREE.ImageUtils.loadTexture("images/clouds.png");
  //  var meshClouds = new THREE.Mesh( cloudGeo, cloudsMat );
  // meshClouds.scale.set(1.015, 1.015, 1.015 );
  // scene.add(meshClouds);
  //Add lines
  var root = new THREE.Object3D();
  for (var i = 0; i < dataset.length; i++) {
    endLon=dataset[i].lng;
    endLat=dataset[i].lat;
    makeCurve(startLat,startLon,endLat,endLon);
    root.add(line);
  };
  scene.add(root)

  function makeCurve(startLon,startLat,endLon,endLat){
    console.log("makeCurve",startLon,startLat,endLon,endLat);
    var phiFrom = startLon * Math.PI / 180;
    var thetaFrom = (startLat+90) * Math.PI / 180;
    //calculates "from" point
    var xF = radious * Math.cos(phiFrom) * Math.sin(thetaFrom);
    var yF = radious * Math.sin(phiFrom);
    var zF = radious * Math.cos(phiFrom) * Math.cos(thetaFrom);
    phiFrom = endLon * Math.PI / 180;
    thetaFrom = (endLat+90) * Math.PI / 180;
    //calculates "from" point
    var xT = radious * Math.cos(phiFrom) * Math.sin(thetaFrom);
    var yT = radious * Math.sin(phiFrom);
    var zT = radious * Math.cos(phiFrom) * Math.cos(thetaFrom);
    //Sets up vectors
    var vF = new THREE.Vector3(xF, yF, zF);
    var vT = new THREE.Vector3(xT, yT, zT);
    var dist = vF.distanceTo(vT);
    // here we are creating the control points for the first ones.
    // the 'c' in front stands for control.
    var cvT = vT.clone();
    var cvF = vF.clone();
    // get the half point of the vectors points.
    var xC = ( 0.5 * (vF.x + vT.x) );
    var yC = ( 0.5 * (vF.y + vT.y) );
    var zC = ( 0.5 * (vF.z + vT.z) );
    // then we create a vector for the midpoints.
    var subdivisions = 100;
    var geometry = new THREE.Geometry();
    var curve = new THREE.QuadraticBezierCurve3();
    curve.v0 = new THREE.Vector3(xF, yF, zF);
    curve.v1 = new THREE.Vector3(xT, yT, zT);
    curve.v2 = new THREE.Vector3(xC, yC, zC);
    for (var i = 0; i < subdivisions; i++) {
      geometry.vertices.push( curve.getPoint(i / subdivisions) )
    }
    var material = new THREE.LineBasicMaterial( { color: 0xf2c0a4, linewidth: 2 } );
    line = new THREE.Line(geometry, material);
  }

  // controls = new THREE.OrbitControls( camera );
  render();
  function render() {
      var timer = Date.now() * 0.0001;
      // camera.position.x=(Math.cos(timer)*1800);
      // camera.position.z=(Math.sin(timer)*1800);
      camera.lookAt( scene.position );
      // light.position.x = (Math.cos(timer)*2000);
      // light.position.z = (Math.sin(timer)*2000);
      light.lookAt(scene.position);
      //earthObject.rotation.y += 0.0014;
      root.rotation.y += 0.0014;
      //meshClouds.rotation.y += 0.001;
      renderer.render(scene,camera);
      requestAnimationFrame(render );
  }
});

数据样本如下所示,在其他地方加载ftlabel imfcode, lat,液化天然气33岁的阿富汗,512年66年914年阿尔巴尼亚,41岁,20阿尔及利亚,612年,28岁的3安哥拉、614、-12.5、18.5阿根廷,213,-34,-64911年亚美尼亚,40岁,45岁阿鲁巴岛,314年,12.5,-69.97澳大利亚,193年、-25135年奥地利,122年,47.33,13.33阿塞拜疆,912,40.5,47.5巴哈马群岛,313,-76巴林、419年,26岁的50.5孟加拉国,513,90巴巴多斯、316、13.17、-59.53现年53岁的白俄罗斯,913年28比利时,124年50.83,4伯利兹城,339,17.25,-88.75贝宁、638、9.5、2.25百慕大,319,32.33,-64.75玻利维亚、218、-17、-65波斯尼亚和黑塞哥维那,963,44.25,17.83巴西、223、-10、-55文莱、516、4.5,114.67918年保加利亚,43岁,25岁布基纳法索、748、13日2布隆迪、618、-3.5,30岁柬埔寨,522年,13105年喀麦隆、622、6、12加拿大,156,-96佛得角、624、-24中非共和国,626、7、21乍得、628、15、19智利,228,-30,-71中国,924年、35105年哥伦比亚,233,-72科摩罗、632、-12.17、44.25哥斯达黎加,238,-84科特迪瓦、662、8、5克罗地亚,960,45.17,15.5古巴,928年,22岁的-79.5

清理了一些数学,但基本上我是将lon和lat传递给接收它们的错误方式的函数。代码现在可以工作了,看起来像这样

import oHoverable from 'o-hoverable';
import d3 from 'd3';
import oHeader from 'o-header';
import THREE from 'three.js';

oHoverable.init(); // makes hover effects work on touch devices
document.addEventListener('DOMContentLoaded', function () {
  oHoverable.init(); // makes hover effects work on touch devices
  var dataset=spreadsheet.data
  //console.log(dataset)
  var startLat=38
  var startLon=-100
  var endLon=0
  var endLat=0
  var posX = 200;
  var posY = 600;
  var posZ = 1800;
  var width = document.getElementById('main').getBoundingClientRect().width;
  var height = 600;
  var FOV = 45;
  var NEAR = 2;
  var FAR = 4000;
  var controls;
  // some global variables and initialization code 
  // simple basic renderer
  var renderer = new THREE.WebGLRenderer();
  renderer.setSize(width,height);
  renderer.setClearColor( 0x000000, 1);
  // add it to the target element
  var globeDiv = document.getElementById("globeDiv");
  globeDiv.appendChild(renderer.domElement);
  // setup a camera that points to the center
  var camera = new THREE.PerspectiveCamera(FOV,width/height,NEAR,FAR);
  camera.position.set(posX,posY, posZ);
  camera.lookAt(new THREE.Vector3(0,0,0));
  // create a basic scene and add the camera
  var scene = new THREE.Scene();
  scene.add(camera);
  //spotlight set up in the same location as the camera
  var light = new THREE.DirectionalLight(0xffffff, 1.0, 200 );
  light.position.set(posX,posY,posZ);
  scene.add(light);
  //Add Earth
  var radius=600
  var curveObject
  var earthGeo=new THREE.SphereGeometry(radius,100,100);
  var earthMat=new THREE.MeshPhongMaterial();
  earthMat.map=THREE.ImageUtils.loadTexture("images/world.jpg");
  earthMat.bumpMap=THREE.ImageUtils.loadTexture("images/bumpmap.jpg");
  earthMat.bumpScale=8;
  earthMat.shininess=10;
  var earthObject = new THREE.Mesh(earthGeo,earthMat);
  scene.add(earthObject);
  //Add clouds
  var cloudGeo=new THREE.SphereGeometry(radius,60,60);
  var cloudsMat=new THREE.MeshPhongMaterial({
      opacity: 0.5,
      transparent: true,
      color: 0xffffff
  });
  cloudsMat.map=THREE.ImageUtils.loadTexture("images/clouds.png");
   var meshClouds = new THREE.Mesh( cloudGeo, cloudsMat );
  meshClouds.scale.set(1.015, 1.015, 1.015 );
  scene.add(meshClouds);
  //Add lines
  var lineObject = new THREE.Object3D();
  for (var i = 0; i < dataset.length; i++) {
    endLon=dataset[i].lng;
    endLat=dataset[i].lat;
    makeCurve(startLon,startLat,endLon,endLat,i);
    lineObject.add(curveObject);
  };
  scene.add(lineObject)

  // takes lon lat and a radius and turns that into vector
  function to3DVector(lon, lat, radius) {
    var phi = lat * Math.PI / 180;
    var theta = (lon + 90) * Math.PI / 180;
    var xF = radius * Math.cos(phi) * Math.sin(theta);
    var yF = radius * Math.sin(phi);
    var zF = radius * Math.cos(phi) * Math.cos(theta);
    return new THREE.Vector3(xF, yF, zF);
  }
  function makeCurve(startLon,startLat,endLon,endLat,i){
    var widthScale = d3.scale.linear()
                .domain([0, d3.max(dataset, function(d) { return d.imfcode; })])
                .range([1, 12]);
    var vF = to3DVector(startLon, startLat, radius);
    var vT = to3DVector(endLon, endLat, radius);
    // then you get the half point of the vectors points.
    var xC = ( 0.5 * (vF.x + vT.x) );
    var yC = ( 0.5 * (vF.y + vT.y) );
    var zC = ( 0.5 * (vF.z + vT.z) );
    // then we create a vector for the midpoints.
    var mid = new THREE.Vector3(xC, yC, zC);
    var dist = vF.distanceTo(vT);
    // here we are creating the control points for the first ones.
    // the 'c' in front stands for control.
    var cvT = vT.clone();
    var cvF = vF.clone();
    var smoothDist = map(dist, 0, 10, 0, 15/dist );
    console.log(smoothDist);
    mid.setLength( radius * smoothDist );
    cvT.add(mid);
    cvF.add(mid);
    cvT.setLength( radius * smoothDist );
    cvF.setLength( radius * smoothDist );
    var curve = new THREE.CubicBezierCurve3( vF, cvF, cvT, vT );
    var geometry2 = new THREE.Geometry();
    geometry2.vertices = curve.getPoints( 50 );
    var material2 = new THREE.LineBasicMaterial( { transparent: true,opacity :0.6, color : 0xff0000,linewidth:widthScale(dataset[i].imfcode)} );

    // Create the final Object3d to add to the scene
    curveObject = new THREE.Line( geometry2, material2 );
    function map(value, low1, high1, low2, high2) {
      return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
    }
  }
  render();
  function render() {
    var timer = Date.now() * 0.0001;
    // camera.position.x=(Math.cos(timer)*1800);
    // camera.position.z=(Math.sin(timer)*1800);
    camera.lookAt( scene.position );
    // light.position.x = (Math.cos(timer)*2000);
    // light.position.z = (Math.sin(timer)*2000);
    light.lookAt(scene.position);
    earthObject.rotation.y += 0.0005;
    lineObject.rotation.y += 0.0005;
    meshClouds.rotation.y += 0.0012;
    renderer.render(scene,camera);
    requestAnimationFrame(render );
  }

});