0 引言
在做岩石的时候,粗糙一点就认为岩石是一个均匀的整体,对整体参数进行标定,达到一个单元层次的宏观特性对应。精细点做的话就需要考虑矿物,这样我们会认为矿物内部是一个均匀的整体,这样的话就需要对岩石内部的区域进行划分,规定每种矿物成分的区域,然后用颗粒进行填充模拟。
本文主要目的是将区域进行随机多边形划分,并且往其中填充颗粒。使用到的技术主要是rblock中的merge命令。
1 区域划分
我们主要使用rblock的建模特性作为过渡,得到随机的多边形区域。
model new
model domain extent -10 10
geometry set "box"
geometry generate box -5 5
def par
origin_rad_min=0.2
origin_rad_max=origin_rad_min*1.5
scale=3
block_radius_max=origin_rad_max*scale
block_radius_min=origin_rad_min*scale
end
@par
rblock construct from-geometry "box" minimum-edge @origin_rad_min ...
maximum-edge @origin_rad_max group "origin" slot "1"
第一步是利用rblock construct命令可以对区域进行三角划分,如果可以直接对区域进行多边形划分肯定是更好的。但就我目前对rblock的理解来说,还做不到这种程度,目前只能做到对区域进行三角划分,这里可以指定三角形的边长范围。
我们生成了一堆三角形的rblock,如下图:
第二步就是用所得到的三角形进行随机的合并,这里我们用的是长方形区域进行合并。
def inbox(pos,pointer)
groupName=rblock.group(pointer)
if groupName#"1=origin" then
inbox=false
exit
endif
vl=vector(x_pos_random-sousuo_rad_x,y_pos_random-sousuo_rad_y)
vh=vector(x_pos_random sousuo_rad_x,y_pos_random sousuo_rad_y)
rbpos=rblock.pos(pointer)
if comp.x(rbpos)>comp.x(vl) & comp.x(rbpos)<comp.x(vh) &comp.y(rbpos)>comp.y(vl) & comp.y(rbpos)<comp.y(vh) then
inbox=true
exit
endif
inbox=false
end
def conbine_rblock
stop_flag=true
name_count=1
loop while stop_flag
x_pos_random=math.random.uniform*10-5
y_pos_random=math.random.uniform*10-5
sousuo_rad_x=math.random.uniform*(block_radius_max-block_radius_min) block_radius_min
sousuo_rad_y=math.random.uniform*(block_radius_max-block_radius_min) block_radius_min
ishaveRb=false
loop foreach rb rblock.list
vl=vector(x_pos_random-sousuo_rad_x,y_pos_random-sousuo_rad_y)
vh=vector(x_pos_random sousuo_rad_x,y_pos_random sousuo_rad_y)
if inbox(vl,rb) then
ishaveRb=true
exit loop
endif
endloop
group_name=string.build("zu_%1",name_count)
name_count =1
if ishaveRb=true then
command
rblock merge group "new" slot "1" group @group_name slot "10" ...
range fish @inbox
model clean
endcommand
endif
orgin_count=0
loop foreach rb rblock.groupmap("origin",1)
orgin_count =1
endloop
if orgin_count==0 then
stop_flag=false
endif
endloop
end
@conbine_rblock
我们每次随机获得一个长宽的长方形,将长方形中的“origin”组的rblock合并成一个新的rblock。
这里有个逻辑需要注意是,merge的概念不一定需要rblock紧贴在一起,就算rblock分开一段距离,他们之间的范围也会合并到新的rblock中,所以合并得到的rblock实际上是有重叠的。
我们看一下新的rblock。
可以发现的是,大部分的rblock都被合并了,但是有少部分rblock是被“剩余合并”的,所谓“剩余合并”的概念就是某个rblock或者某几个会被单独剩余下来,最终形成一个rblock,而这个rblock是不满足长宽要求的。
所以我们还需要进行第三步,也就是把这些小的rblock合并到它周围的大rblock中。
def findMinRb
VLimit=origin_rad_min*origin_rad_min*10
loop foreach rb rblock.groupmap("new",1)
if rblock.vol(rb)<VLimit*4 then
rblock.group(rb,1)="minRB"
endif
endloop
end
@findMinRb
def findNearestRb(pos)
minPos=1e100
minId=0
loop foreach rbfind rblock.groupmap("new",1)
vecLenghth=rblock.pos(rbfind)-pos
if math.mag(vecLenghth)<minPos then
minPos=math.mag(vecLenghth)
minId=rblock.id(rbfind)
endif
endloop
findNearestRb=minId
end
def solveMinRb
loop foreach rb rblock.groupmap("minRB",1)
rbNearest=rblock.find(findNearestRb(rblock.pos(rb)))
rblock.group(rb,20)="dai"
rblock.group(rbNearest,20)="dai"
group_name=string.build("zu_%1",name_count)
name_count =1
command
rblock merge group "new" slot "1" group @group_name ...
slot "10" range group "20=dai"
endcommand
loop foreach rbdai rblock.groupmap("dai",20)
rblock.group(rbdai,20)="none"
endloop
endloop
end
@solveMinRb
通过以上的命令,我们可以找到小的颗粒,当然我们也可以调整“小的颗粒”的范围,从而调整模型中区域的精细度。
运行完的效果如图:
这个就是我们区域的范围。
2 颗粒填充
由于没有指定随机数,导致本文出现的图和我既有算例的分布有区别,这里给出我算完的一个sav。如下图:
可以看到区域大小基本一致,只是形状不同,这里也体现随机性的概念。
颗粒填充前我们需要把rblock的边界都导出为geometry,方便后面根据区域进行颗粒生成。
可以看一下区域图:
由于rblock有重叠,导致geometry也是有重叠的,所以颗粒的生成规则我们需要进行优化。
首先定一个考虑区域重叠的规则。
区域交集优先被id小的geometry使用。
也就是说id为3区域需要减去其与id 1和id 2区域的交集,作为对应颗粒的生成范围。
榆树我们可以得到某个区域的颗粒投放逻辑,如下:
第二个逻辑是颗粒的平衡边界,每个区域的颗粒投放后都需要平衡,其边界应当考虑id小于当前geo id的区域,所以需要控制墙体的生成和删除。
最后便是函数的调用,每次生成新的区域的时候,旧的区域颗粒需要进行固定。
效果如下:
每次投放都保存了save文件,可以进行查看。