☰
第77篇:三维地层-钻孔建模——把稀疏钻孔插值成一整块能剖开的地层
2026/10/25 1:53:26 网站建设 项目流程

上一篇我们把数值画进了地球表面——八个城市变成八个大小不一的圆(#76)。这次往地下走。

先看一个真实的工程困境。你在某块场地上打了十几个钻孔,每根孔给你一份柱状图:地下多少米到多少米是砂土,再往下到多少米是粉质粘土……这是一维的信息,一根孔一条竖线。可甲方要看的是三维的东西:这块地下面,砂土层整体是怎么起伏的?基岩面在哪儿最深?

孔与孔之间,是空的。

钻孔建模要做的,就是用这十几条竖线,推断出一整块连续的地层体,还能把它剖开、分层抽出来看。本篇拆的就是这件事——从 19 根钻孔的分层数据,到一块能展开、能高亮、能报深度的三维地层。

💡 本文涉及的全部代码均已开源,完整的仓库地址见文末,可自行取用、随意魔改。


整条链路可以拆成四步,每一步都对应一个具体的工程决策:

  1. 造数据 / 洗数据——每根孔给一串层底深度,还得保证层序不倒挂;
  2. 插值——用反距离加权(IDW)把离散的层底深变成一张连续的界面;
  3. 体素化——把"哪一层在哪"写进一个三维网格,交给VoxelPrimitive渲染;
  4. 钉到地球上——用 ENU 变换把这块 400 米见方的地层体摆到指定经纬度,并处理"高出地表"的那一段。

前三步是数学,第四步是坐标。本篇的坑主要出在第四步。


一、先说清楚:钻孔建模到底在补什么

先看 demo 里的数据长什么样。19 根钻孔(编号 ZK01~ZK19),每根给 5 个层底深度(单位米),对应 5 个地层:

constLAYERS=[{name:'砂土层',color:'#D2B48C'},{name:'粉质粘土层',color:'#B8860B'},{name:'粉砂层',color:'#D3D3A4'},{name:'中砂层',color:'#CD853F'},{name:'密实砾石与基岩',color:'#7A6B5A'}]asconst

19 这个数有个小来历:demo 按 5 列 × 4 行铺了 20 个位置,然后故意跳过中间一个(if (r === 1 && c === 2) continue)——真实场地里钻孔位置从来不是完美网格,缺一个才像真的。

探针把这 19 根孔跑出来,五个层底深的分布是这样的:

层位岩性层底深 minmax均值
第 1 层砂土层4.25 m13.14 m9.76 m
第 2 层粉质粘土层15.38 m23.72 m20.43 m
第 3 层粉砂层30.63 m41.46 m36.48 m
第 4 层中砂层46.32 m56.92 m51.29 m
第 5 层密实砾石与基岩64.48 m73.72 m68.78 m

注意这些数字是起伏的:第一层底深在 4.25 到 13.14 米之间摆动,差了近 9 米。这正是地层建模的意义所在——如果各孔都一样深,画个水平层就完事了,根本不用插值。

生成这批数据时有一条容易被忽略的约束,在makeBoreholes()里:

constwave=Math.sin(u*9+k*1.7)*Math.cos(v*7+k*0.9)*3letd=base[k]+wave+(rand()-0.5)*6if(d<prev+4)d=prev+4// ← 保证每层至少 4 米厚depths.push(d)prev=d

那句if (d < prev + 4) d = prev + 4是在强制层序单调。真实钻孔数据里,第 k 层的底深必须大于第 k−1 层的底深(否则地层就"倒挂"了,物理上不可能);但实测数据常有录入错误或小夹层,直接用会画出翻转的地层。接外部数据时这一步一定要自己做——别指望插值算法帮你兜。


二、IDW 反距离加权:19 根孔怎么变成一张连续的界面

有了 19 根孔,接下来的问题是:任意一点 (u, v) 处的第 k 层界面有多深?

demo 用的是最经典的IDW(Inverse Distance Weighting,反距离加权),也叫 Shepard 插值:

functionidwDepth(u:number,v:number,layerIdx:number):number{constp=3letwsum=0letdsum=0for(leti=0;i<boreholes.length;i++){constb=boreholes[i]constdx=u-b.uconstdy=v-b.vconstd2=dx*dx

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询