资讯详情

资讯详情

d3-geo 球面几何引擎:从墨卡托点到地理经线的投影管线,以及 D3 地图的裁剪与绕序约定

d3-geo 球面几何引擎从墨卡托点到地理经线的投影管线以及 D3 地图的裁剪与绕序约定【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3本文以 d3 官方文档 docs/d3-geo.md 为主体系统讲解 d3-geo 的核心设计为什么地图投影不能只做“点变换”、球面几何大圆线、自适应采样如何进入投影管线、日界线切割与小圆裁剪、多边形绕序约定以及 D3 使用的球面 GeoJSON 数据表示。读完后你能理解 d3 投影 APIprojection/stream/shape/math/path的分工并能在 d3 v7当前仓库 package.json 声明d3-geo: ^3.1.1整体版本 7.9.0中正确构建、裁剪、旋转一幅 SVG/Canvas 地图。点变换地图投影的最直观形式地图投影常被实现为点变换一个接收经度 λ 与纬度 φ、返回平面上对应 x/y 位置的函数。以球面墨卡托投影单位弧度为例function mercator(lambda, phi) { const x lambda; const y Math.log(Math.tan(Math.PI / 4 phi / 2)); return [x, y]; }如果几何体只由点构成这种方法是可行的。但对多边形、折线这类离散几何从球面投影到平面会引入新的难题。大圆线与自适应采样球面多边形的边不是直线而是大圆线great circle 的线段即测地线。除了正射方位角投影gnomonic见 docs/d3-geo/azimuthal.md之外大圆线在几乎所有投影下都会变成曲线因此精确投影要求沿每条弧线插值。d3 采用自适应采样adaptive sampling来平衡精度与性能其思想借鉴自 Visvalingam 折线简化算法当投影后的曲线偏离原始大圆超过阈值时才在中间补充采样点。这个阈值由投影的precision方法控制从 docs/d3-geo/projection.md 可以看到projection.precision(p)设置自适应重采样的阈值单位是像素对应 Douglas–Peucker 距离默认值为Math.sqrt(0.5) ≅ 0.70710…。也就是说你几乎不需要手动沿大圆插值——把 LineString 传给d3.geoPath(projection)时投影内部会按上述规则自动沿大圆弧密集采样docs/d3-geo/shape.md 中的提示也印证了这一点大圆的中间点由投影的测地线插值完成。球面与平面的拓扑差异裁剪与日界线切割多边形和折线的投影还必须处理球面与平面之间的拓扑差异。从文档脉络看d3 把裁剪分成两级均定义在 docs/d3-geo/projection.mdpreclip球面裁剪在投影之前、以球面坐标进行。两类典型用途clipAngle(angle)按投影中心的小圆裁剪。angle为度数设为null时切换为日界线切割antimeridian cutting模式。默认值为null。geoClipAntimeridian把跨越日界线的线/多边形切成左右两半常用于世界地图避免“绕地球一圈”的伪影。geoClipCircle(angle)生成以小圆为界的裁剪流。postclip平面裁剪在投影之后的平面上进行用于把有界的投影约束到视口矩形内clipExtent([[x0, y0], [x1, y1]])像素单位的视口裁剪范围null表示不裁剪默认nullgeoClipRectangle(x0, y0, x1, y1)生成矩形裁剪流。文档同时提醒小圆裁剪clipAngle与视口裁剪clipExtent相互独立可以叠加使用。以正射投影geoOrthographic为例文档中的示例惯用fitExtent加precision(0.2)来控制球体轮廓的采样精度可参考 docs/d3-geo/shape.md 顶部的示例参数。绕序约定多边形的“内侧”是哪一边球面多边形还需要绕序约定winding order来确定多边形的哪一侧是内部小于半球的多边形其外环必须是顺时针大于半球的多边形例如海洋占超过半个地球其外环必须是逆时针表示孔洞的内环绕序与外环相反。::: warning 注意 D3 的绕序约定被 TopoJSON 与 ESRI shapefile 沿用但它与 GeoJSON RFC 7946 的约定正好相反标准 GeoJSON 要求外环逆时针。另外标准 GeoJSON WGS84 使用的是平面等距圆柱坐标而非球面坐标因此直接投影 WGS84 数据可能出现日界线切割残留需要额外“缝合”stitching处理。这是从 docs/d3-geo.md 的官方警告继承的关键工程细节处理全球级数据海洋、大陆轮廓时必须特别注意。 :::球面 GeoJSONd3-geo 的数据表示D3 使用球面 GeoJSON表示 JavaScript 中的地理要素配合三类几何能力投影docs/d3-geo/projection.md把球面几何投影到平面内置方位角、圆锥、圆柱三大类标准投影路径docs/d3-geo/path.mdd3.geoPath(projection)把 GeoJSON 生成 SVG path data 或渲染到 Canvas流docs/d3-geo/stream.md不物化中间表示通过函数调用直接变换球面或平面几何。数据准备方面文档给出的工具链是Shapefile 转 GeoJSON使用 shapefile 工具包的shp2json命令TopoJSONGeoJSON 的更紧凑扩展编码拓扑信息。当前仓库的文档组件 docs/components/WorldMap.vue 正是这样加载世界轮廓的import * as topojson from topojson-client; // 从 world-atlas 的 TopoJSON 中提取 GeoJSON Feature d3.json(.../land-110m.json) .then((world) topojson.feature(world, world.objects.land));这解释了 d3-geo 文档为何反复以 TopoJSON 作为数据入口geoPath消费的是topojson.feature转换后的标准 GeoJSON。投影 API 精要一次投影发生了什么projection.stream(stream)见 docs/d3-geo/projection.md揭示了一次完整投影的管线顺序输入几何先转换为弧度 → 三轴旋转 → 小圆裁剪或日界线切割 → 以自适应重采样投影到平面 → 缩放与平移。据此常用的投影方法可归为四组变换组方法说明默认值scale(k)比例因子与投影点间距线性相关但不同投影间绝对值不可比因投影而异translate([tx, ty])平移偏移决定中心点的像素坐标[480, 250]960×500 画布中心center([λ, φ])投影中心度[0, 0]rotate([λ, φ, γ])三轴球面旋转偏航、俯仰、翻滚度γ缺省为 0[0, 0, 0]angle(θ)/reflectX/reflectY投影后平面旋转与轴向反射0° / false / falseprecision(p)自适应重采样阈值像素√0.5裁剪组clipAngle、clipExtent、preclip、postclip见上文“拓扑差异”一节。适配组fitExtent(extent, object)设置 scale 与 translate使给定 GeoJSON 对象居中适配指定矩形计算包围盒时使用有效 scale 为 150 的 precision忽略 clipExtentfitSize(size, object)等价于fitExtent([[0, 0], [width, height]], object)fitWidth/fitHeight按对象宽高比自动推算另一维度。文档中的实例新泽西州 State Plane 投影var projection d3.geoTransverseMercator() .rotate([74 30 / 60, -38 - 50 / 60]) .fitExtent([[20, 20], [940, 480]], nj);点/逆投影projection(point)接受度数输入的[经度, 纬度]返回像素[x, y]或null被裁掉时可逆投影另有invert(point)。流Stream几何变换的同步接口docs/d3-geo/stream.md 定义了流的接口流不构造中间几何对象仅靠方法调用传递几何从而最小化开销。流天然是有状态的——point的含义取决于它是否处于lineStart之内线又靠polygonStart与环区分虽然叫“流”这些调用目前是同步的。必需方法point(x, y, z)、lineStart()、lineEnd()、polygonStart()、polygonEnd()、sphere()。入口是d3.geoStream(object, stream)注意流接口只描述几何Feature 的properties对流不可见。一个细节与绕序直接相关lineEnd()在环内不重复发出闭合坐标。输入{ type: Polygon, coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]] }实际触发的调用序列是stream.polygonStart(); stream.lineStart(); stream.point(0, 0); stream.point(0, 1); stream.point(1, 1); stream.point(1, 0); stream.lineEnd(); stream.polygonEnd();球面数学与形状生成docs/d3-geo/math.md 提供底层球面工具与投影后的平面测量path.area、path.bounds等一一对应geoArea(object)球面面积单位球面度steradiangeoBounds(object)球面包围盒[[left, bottom], [right, top]]单位度geoCentroid(object)球面质心geoDistance(a, b)/geoLength(object)两点大圆弧距 / 几何体大圆弧长单位弧度多边形为外环加内环周长geoInterpolate(a, b)返回沿过 a、b 大圆弧的插值器t ∈ [0, 1]对跖点时取任意大圆弧geoContains(object, point)球面点包含测试geoRotation(angles)与projection.rotate同参数的旋转函数支持invert。docs/d3-geo/shape.md 则返回球面 GeoJSON 供geoPath消费geoGraticule()经纬网格默认 ±80° 纬度内每 10° 一条线、极地 90° 经线精度默认 2.5°、geoGraticule10()、geoCircle()等。仓库的 WorldMap.vue 里const graticule d3.geoGraticule10();就是最小用法。实战仓库中的世界地图组件docs/components/WorldMap.vue 是一个可直接借鉴的完整示例加载 TopoJSON 陆地轮廓用d3.geoPath(projection)依次绘制球体轮廓{type: Sphere}、经纬网格、要素本体并通过指针拖动实时修改projection.rotate()的第一轴重绘直观演示了“因为 D3 使用球面几何表示数据所以任何投影都可以通过旋转得到任意视角”这一文档论断。核心绘制逻辑const path d3.geoPath(projection); function update() { svg.selectAll([nameoutline]).attr(d, path({type: Sphere})); svg.selectAll([namegraticule]).attr(d, path(graticule)); svg.selectAll([namefeature]).attr(d, path(feature)); }自定义投影raw projection 与 geoProjectiondocs/d3-geo/projection.md 的“Raw projections”一节定义了扩展机制raw projection 是接收弧度[λ, φ]、返回单位坐标[x, y]的点变换函数无需自己处理缩放、平移与旋转这些由scale/translate/rotate自动完成。d3.geoProjection(project)由 raw projection 构造标准投影若project暴露invert生成的投影也可逆。var mercator d3.geoProjection(function(x, y) { return [x, Math.log(Math.tan(Math.PI / 4 y / 2))]; });d3.geoProjectionMutator(factory)为带参数的投影族如双标准纬线的圆锥投影构造可变投影通过mutate(phi0, phi1)替换内部 raw projectionfunction conicCustom() { var phi0 29.5, phi1 45.5, mutate d3.geoProjectionMutator(conicFactory), projection mutate(phi0, phi1); projection.parallels function(_) { return arguments.length ? mutate(phi0 _[0], phi1 _[1]) : [phi0, phi1]; }; return projection; }d3.geoTransform(methods)用任意方法集合定义几何变换未定义的方法透传是“广义投影”可传给path.projection但只实现投影方法的一个子集d3.geoIdentity()恒等变换用于对平面几何做缩放、平移与裁剪实现了 scale/translate/fit*/clipExtent/angle/reflectX/reflectY。小结从文档骨架到工程结论回看 docs/d3-geo.md 的主线可以提炼为四条工程结论投影 ≠ 点变换大圆线必须沿弧插值d3 用自适应采样默认阈值√0.5像素自动完成precision是你的精度/性能旋钮裁剪分两级球面级clipAngle/日界线切割preclip与平面级clipExtentpostclip相互独立按需组合绕序有约定小于半球外环顺时针、大于半球逆时针、内环相反——与 GeoJSON RFC 7946 相反全球级数据海洋、跨日界线边界尤其要核对数据用球面 GeoJSON/TopoJSON 表示配合geoPath、geoStream与三轴rotate即可在任意投影上自由切换视角如 WorldMap.vue 所示。配套阅读Paths、Projections、Streams、Shapes、Spherical math以及三大投影类别文档 azimuthal、conic、cylindrical。【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →