
一句话介绍: 这套程序在一个三维长方体区域内不断随机生成球形骨料,通过边界检查和球—球碰撞检查自动拒绝不合格候选,直到尽量达到指定骨料数量,最后把所有已接受骨料绘制成三维模型。
建立混凝土细观模型时,一个很基础的问题是:
怎样把大量骨料随机放进试件内部,同时保证骨料不 穿出边界,也不互相重叠?
如果只是随机生成一批球心和半径,很容易出现:
骨料穿出试件表面;两个甚至多个骨料互相穿透;
骨料位置过于集中;三维模型无法直接用于后续细观分析。
这套程序采用非常直接的顺序随机投放思路:
随机生成球心和半径 → 检查是否完全位于试件内部 → 检查是否与已有骨料重叠 → 合格则保存 → 不合格则重新生成 → 绘制全部球形骨料
所以它真正实现的是:三维随机球形骨料的“生成—碰撞检测—接受/拒绝”投放过程。
1. 这个工程真正包含什么?
核心程序:ConcreteBone.m
它完成了整个流程:
设置三维边界;设置目标骨料数量;
设置随机半径范围;随机生成候选骨料;
检查边界;检查与已有骨料之间的距离;保存合格骨料;最后绘制三维球形骨料。
程序没有读取外部数据文件,也没有复杂的函数依赖。
其中每一行表示一个球:
Sph(i,:) = [xᵢ, yᵢ, zᵢ, rᵢ]
也就是:球心 X + 球心 Y + 球心 Z + 半径
2. 当前程序设定了怎样的三维区域?
源码给出的边界为:
x:1~5、y:2~6、z:3~7
因此从参数定义本身看,目标试件是一个三个方向跨度都为 4 的长方体:
目标骨料数量为:Num = 1000
源码设置的半径参数为:、rmin = 0.05、rmax = 0.5
因此程序设计意图是随机生成尺寸不同的球形骨料,而不是全部使用相同半径。
3. 一个候选骨料是怎样产生的?
程序每次循环都会随机产生:
球心 (x, y, z) + 半径 r
然后判断这个候选球能不能真正加入当前骨料集 合。
整个算法最多尝试:1,000,000 次
当成功接受的骨料数量达到:1000 个
就提前结束随机搜索。
这类方法可以理解为一种非常直观的:
Sequential Random Placement,顺序随机投放 / 随机拒绝采样。
已经接受的骨料不会再移动,新的骨料只能寻找剩余可用空间。
4. 第一道检查:骨料不能穿出试件边界
一个半径为 r、球心为 (x,y,z) 的球要完全位于长方体内部,不能只要求球心在盒子内。
还必须保证球面也没有越界。
程序检查:
x - r > xmin,x + r < xmax
y - r > ymin,y + r < ymax
z - r > zmin,z + r < zmax
可以理解为:
球心与每一个边界面的距离都必须至少大于自己的半径。
例如球心虽然在 x = 1.1,但如果半径为 0.3,那么球左侧已经越过 xmin = 1,这个骨料就会被拒绝。
因此程序做的是:完整球体边界检查,而不是只检查球心。
5. 第二道检查:骨料之间不能互相重叠
如果候选球已经通过边界检查,程序会依次计算它与所有已有球之间的球心距离:
Dᵢⱼ = √[(xᵢ-xⱼ)² + (yᵢ-yⱼ)² + (zᵢ-zⱼ)²]
两个球不发生几何重叠需要满足:
Dᵢⱼ ≥ rᵢ + rⱼ
如果:
Dᵢⱼ < rᵢ + rⱼ
说明两个球已经相互穿透,当前候选骨料立即被拒绝。
只有当它与已经存在的所有骨料都满足非重叠条件时,程序才把它加入 Sph。
因此整个投放规则可以概括成:
不 穿边界 + 不碰已有骨料 = 接受
6. 为什么必须逐个检查所有已有骨料?
假设当前已经成功放入 300 个球。
第 301 个候选球即使没有和前 299 个发生碰撞,只要它与第 300 个球重叠,也不能接受。
所以程序使用循环依次计算新球与:
第 1 个、第 2 个、……、第 cum 个
已有骨料的距离。
只有全部检查通过,才让:
cum = cum + 1
并把新的 [x,y,z,r] 保存下来。
这种方法逻辑非常清楚,也能严格保证当前保存的球之间不存在几何穿透。
7. 为什么越到后面越难投放?
刚开始时,三维空间几乎是空的。
第一个球只需要满足边界条件,很容易接受。
随着骨料越来越多:可用空隙越来越少;
新球更容易碰到已有球;半径较大的球越来越难找到位置;大量随机候选会被拒绝。
所以顺序随机投放天然具有:前期接受率高,后期接受率逐渐下降的特点。
这也是源码为什么设置高达:
1,000,000 次最大尝试次数,而不是只循环 1000 次。
8. 为什么这种方法比“直接生成 1000 个随机球”更合理?
最简单的方法可以一次性随机生成:
1000 个球心 + 1000 个半径
但这样完全没有几何约束。
最终很可能出现大量:
球—球重叠;球穿出边界。
当前程序虽然仍然依赖随机数,但每一个候选都必须通过两层判断。
因此它从:无约束随机生成
变成了:带几何约束的随机投放
这才使生成结果能够形成一个基本可用的三维骨料几何模型。
9. 程序最终怎样把骨料画出来?
MATLAB 的:sphere(20)会产生一个离散单位球面。
程序对单位球做:
半径缩放 + 球心平移
对于第 i 个骨料:
X = rᵢ·X_unit + xᵢ
Y = rᵢ·Y_unit + yᵢ
Z = rᵢ·Z_unit + zᵢ
这样就把同一个单位球模板变成不同:大小;位置;的实际骨料。
所有球依次使用 surf 绘制并保留在同一个三维坐标系中。
因此运行后可以直接观察:
随机球形骨料在三维空间中的分布状态。
10. 这种随机投放方法理论上为什么适合做基础骨料模型?
一个球是否允许放入,只取决于两件事:
是否越界以及是否和已有球重叠
判断关系都可以直接用球心距离表达,因此实现简单、容易验证。
最终 Sph 中每一个对象都有:
x、y、z、r
所以这些数据不仅能用于绘图,也可以继续用于:
生成有限元几何;判断点是否位于骨料内部;计算骨料体积;建立界面过渡区;
进一步生成混凝土细观模型。
程序使用 rand 随机产生骨料。
重复运行时,骨料:
位置会变化;半径会变化;最终空间分布也会变化。
因此可以生成多个不同随机样本,而不是每次都得到完全相同的规则排列。
11. 当前程序更准确地属于哪类骨料模型?
虽然工程名称是“混凝土三维骨料投放”,但从源码实现看,它采用的是:
随机球形骨料模型
也就是说,所有骨料几何形状都是球。
它控制的主要目标是:骨料个数 Num
而不是预先指定某个骨料体积分数。
因此这份程序最适合看作:三维混凝土细观骨料生成的基础几何 Demo。
12. 一个非常重要的源码范围问题
当前源码写法使用:
rand × range([下限, 上限])
而 MATLAB 的 range([a,b]) 返回的是:b - a不会自动把下限 a 加回去。
因此源码实际产生的初始随机值是:
x:0~4、y:0~4、z:0~4、r:0~0.45
而不是参数名称看起来想表达的:
x:1~5、y:2~6、z:3~7、r:0.05~0.5
由于后面还有边界筛选,真正被接受的球仍会满足部分边界条件,但随机中心不会均匀覆盖原先定义的整个 4×4×4 区域。
如果设计意图确实是“在 xmin~xmax 内均匀随机”,对应关系应为:
x = xmin + rand·(xmax-xmin)
y、z 和 r 同理。
这是复现和继续扩展这个工程时最需要先确认的一点。
13. 程序最终能得到什么?
成功投放后,主要得到两类结果。
Sph每一行:[x, y, z, r]
可以直接知道所有骨料的球心和半径。
程序把所有球形骨料绘制到同一个三维坐标系中,可以观察:
大小随机性;空间随机性;骨料之间没有几何重叠;骨料不会穿过通过检查的边界面。
由于整个生成过程使用随机数,所以每次运行的具体骨料位置和半径都可能不同,并不存在唯一固定的三维结果。
14. 它适合用在哪里?
非常适合理解“骨料不是连续材料,而是一个个独立几何颗粒”时如何建立最基础的三维模型。
随机候选 → 边界检测 → 碰撞检测 → 接受 / 拒绝
这一经典随机填充流程。
除了混凝土骨料,相同思路也可以作为球形颗粒、夹杂物、孔洞中心等三维随机几何生成的基础。
15. 怎么运行?
主程序就是:ConcreteBone.m直接运行即可。
程序会自动尝试投放骨料,并把接受的球心和半径保存在 Sph 中,最后绘制三维球形分布。
运行前建议先确认第 12 节提到的随机范围写法。如果希望严格按照源码参数中的 xmin~xmax、ymin~ymax、zmin~zmax 和 rmin~rmax 进行均匀抽样,需要给随机数补上下限偏移。
最值得调整的只有 目标数量 Num、骨料半径范围和试件边界尺寸,它们分别决定颗粒数量、尺寸尺度和可用投放空间。
16. 一句话看懂这个项目
这是一个 MATLAB 三维随机球形骨料投放程序:它为每个候选骨料随机生成球心和半径,通过 x±r、y±r、z±r 判断球体是否位于试件内部,再利用 Dᵢⱼ≥rᵢ+rⱼ 检查它与所有已有骨料是否重叠,只有全部条件满足才把 [x,y,z,r] 保存到 Sph;目标数量为 1000,最多尝试 1,000,000 次,最后利用 sphere(20) 和 surf 绘制整个三维随机骨料模型。