如何用D3.js将椭球面上的3D坐标投影至2D并保持相对位置
解决椭球3D点到2D平面的D3.js自定义投影方案
首先,你需要先把椭球上的笛卡尔坐标转换成球面经纬度,再基于经纬度实现自定义投影来保持相对位置。以下是分步骤的公式和代码示例:
1. 椭球坐标转球面经纬度
假设你的椭球是三轴椭球,三个半轴分别为a(X轴半径)、b(Y轴半径)、c(Z轴半径),先将原始3D坐标归一化到单位球面:
- 归一化坐标:
const xPrime = point.X / a; const yPrime = point.Y / b; const zPrime = parseFloat(point.Z) / c; // 注意你的Z是字符串格式,先转数字 - 计算经纬度(弧度制):
const longitude = Math.atan2(yPrime, xPrime); // 经度,范围[-π, π] const latitude = Math.asin(zPrime); // 纬度,范围[-π/2, π/2]
如果是旋转椭球(X/Y轴半径相同,即a=b),上述公式依然适用,无需调整。
2. 自定义D3投影保持相对位置
要保证点的相对位置关系不混乱,推荐用等距圆柱投影(Equirectangular),它能维持点之间的相对比例与位置逻辑,仅存在均匀的轴向拉伸,公式和实现如下:
投影函数实现
// 定义画布尺寸 const width = 800; const height = 600; // 自定义等距圆柱投影 const customProjection = (lon, lat) => { // 弧度转角度 const lonDeg = lon * 180 / Math.PI; const latDeg = lat * 180 / Math.PI; // 等距圆柱投影核心公式 const x = (lonDeg + 180) * (width / 360); const y = (90 - latDeg) * (height / 180); return [x, y]; };
完整流程示例
// 原始点数据 const points = [{X: 339.34474945068354, Y: 505.363540649415, Z: '187.425979614258'},{X: 333.741912841797, Y: 445.61164855957054, Z: '185.462127685547'}]; // 替换为你实际的椭球半轴参数 const a = 500; // X轴半径 const b = 500; // Y轴半径 const c = 200; // Z轴半径 // 转换所有点到经纬度格式 const geoPoints = points.map(point => { const xPrime = point.X / a; const yPrime = point.Y / b; const zPrime = parseFloat(point.Z) / c; const lon = Math.atan2(yPrime, xPrime); const lat = Math.asin(zPrime); return [lon, lat]; }); // 用自定义投影转换到2D坐标 const projectedPoints = geoPoints.map(([lon, lat]) => customProjection(lon, lat)); // 在D3中绘制点 const svg = d3.select("svg") .attr("width", width) .attr("height", height); svg.selectAll("circle") .data(projectedPoints) .enter() .append("circle") .attr("cx", d => d[0]) .attr("cy", d => d[1]) .attr("r", 3) .attr("fill", "red");
其他可选投影
如果需要不同的视觉效果但仍保持相对位置:
- 正射投影(Orthographic):模拟太空视角看椭球的效果,适合展示局部区域,D3内置
d3.geoOrthographic(),也可自行自定义实现。 - 墨卡托投影:保持角度不变,但高纬度区域会拉伸,D3内置
d3.geoMercator(),适合需要方向准确性的场景。
注意:必须根据你实际椭球的半轴参数a、b、c调整代码,这些参数是坐标转换准确性的关键。
内容的提问来源于stack exchange,提问作者quetional
相关产品推荐
相关产品推荐

