你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-07 15:10:13 +08:00
Added a pre-commit config file and reformatted all the files accordingly by using it.
这个提交包含在:
@@ -9,7 +9,7 @@ Information
|
||||
|
||||
**Author/Contact**: Kartik Bansal (kartikbn21000@gmail.com)
|
||||
|
||||
This package provides the ability to directly model real objects without having to build their geometries manually using geometry primitives such as the ``#edge``, ``#plate``, ``#box`` etc.. commands. It specifically provides a tool to convert a `STL file <https://en.wikipedia.org/wiki/STL_(file_format)>`_, which can be produced by many CAD software packages, to a voxelised mesh (FDTD Yee cells) which is saved as a geometry file in HDF5 format suitable for directly importing into gprMax.
|
||||
This package provides the ability to directly model real objects without having to build their geometries manually using geometry primitives such as the ``#edge``, ``#plate``, ``#box`` etc.. commands. It specifically provides a tool to convert a `STL file <https://en.wikipedia.org/wiki/STL_(file_format)>`_, which can be produced by many CAD software packages, to a voxelised mesh (FDTD Yee cells) which is saved as a geometry file in HDF5 format suitable for directly importing into gprMax.
|
||||
|
||||
This package was created as part of the `Google Summer of Code <https://summerofcode.withgoogle.com/>`_ programme 2021 which gprMax participated. The package uses the `stl-to-voxel <https://github.com/cpederkoff/stl-to-voxel>`_ Python library by Christian Pederkoff.
|
||||
|
||||
@@ -67,4 +67,4 @@ The following Python script (using our Python API) can be used to import the gen
|
||||
.. figure:: ../../images_shared/stanford_bunny.png
|
||||
:width: 600 px
|
||||
|
||||
FDTD geometry mesh showing the Stanford bunny
|
||||
FDTD geometry mesh showing the Stanford bunny
|
||||
|
@@ -7,12 +7,12 @@ from . import slice
|
||||
def convert_meshes(meshes, discretization, parallel=True):
|
||||
scale, shift, shape = slice.calculate_scale_shift(meshes, discretization)
|
||||
vol = np.zeros(shape[::-1], dtype=np.int32)
|
||||
|
||||
|
||||
for mesh_ind, org_mesh in enumerate(meshes):
|
||||
slice.scale_and_shift_mesh(org_mesh, scale, shift)
|
||||
cur_vol = slice.mesh_to_plane(org_mesh, shape, parallel)
|
||||
vol[cur_vol] = mesh_ind + 1
|
||||
|
||||
|
||||
return vol, scale, shift
|
||||
|
||||
|
||||
@@ -22,12 +22,12 @@ def convert_file(input_file_path, discretization, pad=1, parallel=False):
|
||||
|
||||
def convert_files(input_file_paths, discretization, colors=[(0, 0, 0)], pad=1, parallel=False):
|
||||
meshes = []
|
||||
|
||||
|
||||
for input_file_path in input_file_paths:
|
||||
mesh_obj = mesh.Mesh.from_file(input_file_path)
|
||||
org_mesh = np.hstack((mesh_obj.v0[:, np.newaxis], mesh_obj.v1[:, np.newaxis], mesh_obj.v2[:, np.newaxis]))
|
||||
meshes.append(org_mesh)
|
||||
vol, scale, shift = convert_meshes(meshes, discretization, parallel)
|
||||
vol = np.transpose(vol)
|
||||
|
||||
|
||||
return vol
|
||||
|
@@ -15,7 +15,7 @@ z = 0.148
|
||||
|
||||
scene = gprMax.Scene()
|
||||
|
||||
title = gprMax.Title(name=fn.with_suffix('').name)
|
||||
title = gprMax.Title(name=fn.with_suffix("").name)
|
||||
domain = gprMax.Domain(p1=(x, y, z))
|
||||
dxdydz = gprMax.Discretisation(p1=(dl, dl, dl))
|
||||
time_window = gprMax.TimeWindow(time=10e-9)
|
||||
@@ -25,13 +25,13 @@ scene.add(domain)
|
||||
scene.add(dxdydz)
|
||||
scene.add(time_window)
|
||||
|
||||
go = gprMax.GeometryObjectsRead(p1=(0.020, 0.020, 0.020), geofile='stl/Stanford_Bunny.h5', matfile= 'materials.txt')
|
||||
go = gprMax.GeometryObjectsRead(p1=(0.020, 0.020, 0.020), geofile="stl/Stanford_Bunny.h5", matfile="materials.txt")
|
||||
|
||||
gv = gprMax.GeometryView(
|
||||
p1=(0, 0, 0), p2=domain.props.p1, dl=(dl, dl, dl), filename=fn.with_suffix("").name, output_type="n"
|
||||
)
|
||||
|
||||
gv = gprMax.GeometryView(p1=(0, 0, 0), p2=domain.props.p1,
|
||||
dl=(dl, dl, dl), filename=fn.with_suffix('').name,
|
||||
output_type='n')
|
||||
|
||||
scene.add(go)
|
||||
scene.add(gv)
|
||||
|
||||
gprMax.run(scenes=[scene], geometry_only=True, outputfile=fn)
|
||||
gprMax.run(scenes=[scene], geometry_only=True, outputfile=fn)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#material: 3 0 1 0 sand
|
||||
#material: 5 0.001 1 0 concrete
|
||||
#material: 2.35 0 1 0 hdpe
|
||||
#material: 3 0 1 0 pcb
|
||||
#material: 3 0 1 0 pcb
|
||||
|
@@ -4,16 +4,16 @@ from functools import reduce
|
||||
def lines_to_voxels(line_list, pixels):
|
||||
current_line_indices = set()
|
||||
x = 0
|
||||
for (event_x, status, line_ind) in generate_line_events(line_list):
|
||||
for event_x, status, line_ind in generate_line_events(line_list):
|
||||
while event_x - x >= 0:
|
||||
lines = reduce(lambda acc, cur: acc + [line_list[cur]], current_line_indices, [])
|
||||
paint_y_axis(lines, pixels, x)
|
||||
x += 1
|
||||
|
||||
if status == 'start':
|
||||
if status == "start":
|
||||
assert line_ind not in current_line_indices
|
||||
current_line_indices.add(line_ind)
|
||||
elif status == 'end':
|
||||
elif status == "end":
|
||||
assert line_ind in current_line_indices
|
||||
current_line_indices.remove(line_ind)
|
||||
|
||||
@@ -23,14 +23,14 @@ def slope_intercept(p1, p2):
|
||||
x2, y2 = p2[:2]
|
||||
slope = (y2 - y1) / (x2 - x1)
|
||||
intercept = y1 - slope * x1
|
||||
|
||||
|
||||
return slope, intercept
|
||||
|
||||
|
||||
def generate_y(p1, p2, x):
|
||||
slope, intercept = slope_intercept(p1, p2)
|
||||
y = slope * x + intercept
|
||||
|
||||
|
||||
return y
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ def paint_y_axis(lines, pixels, x):
|
||||
if len(target_ys) % 2:
|
||||
distances = []
|
||||
for i in range(len(target_ys) - 1):
|
||||
distances.append(target_ys[i+1] - target_ys[i])
|
||||
distances.append(target_ys[i + 1] - target_ys[i])
|
||||
# https://stackoverflow.com/a/17952763
|
||||
min_idx = -min((x, -i) for i, x in enumerate(distances))[1]
|
||||
del target_ys[min_idx]
|
||||
@@ -54,15 +54,15 @@ def paint_y_axis(lines, pixels, x):
|
||||
pixels[target_y][x] = True
|
||||
is_black = not is_black
|
||||
yi = target_y
|
||||
assert is_black is False, 'an error has occured at x%s' % x
|
||||
assert is_black is False, "an error has occured at x%s" % x
|
||||
|
||||
|
||||
def generate_line_events(line_list):
|
||||
events = []
|
||||
|
||||
|
||||
for i, line in enumerate(line_list):
|
||||
first, second = sorted(line, key=lambda pt: pt[0])
|
||||
events.append((first[0], 'start', i))
|
||||
events.append((second[0], 'end', i))
|
||||
|
||||
events.append((first[0], "start", i))
|
||||
events.append((second[0], "end", i))
|
||||
|
||||
return sorted(events, key=lambda tup: tup[0])
|
||||
|
@@ -27,13 +27,13 @@ def mesh_to_plane(mesh, bounding_box, parallel):
|
||||
else:
|
||||
pbar.update(1)
|
||||
_, pixels = paint_z_plane(mesh_subset, z, bounding_box[1::-1])
|
||||
vol[z]=pixels
|
||||
vol[z] = pixels
|
||||
z += 1
|
||||
|
||||
if status == 'start':
|
||||
if status == "start":
|
||||
assert tri_ind not in current_mesh_indices
|
||||
current_mesh_indices.add(tri_ind)
|
||||
elif status == 'end':
|
||||
elif status == "end":
|
||||
assert tri_ind in current_mesh_indices
|
||||
current_mesh_indices.remove(tri_ind)
|
||||
|
||||
@@ -61,17 +61,17 @@ def paint_z_plane(mesh, height, plane_shape):
|
||||
|
||||
|
||||
def linear_interpolation(p1, p2, distance):
|
||||
'''
|
||||
"""
|
||||
:param p1: Point 1
|
||||
:param p2: Point 2
|
||||
:param distance: Between 0 and 1, Lower numbers return points closer to p1.
|
||||
:return: A point on the line between p1 and p2
|
||||
'''
|
||||
return p1 * (1-distance) + p2 * distance
|
||||
"""
|
||||
return p1 * (1 - distance) + p2 * distance
|
||||
|
||||
|
||||
def triangle_to_intersecting_lines(triangle, height, pixels, lines):
|
||||
assert (len(triangle) == 3)
|
||||
assert len(triangle) == 3
|
||||
above = list(filter(lambda pt: pt[2] > height, triangle))
|
||||
below = list(filter(lambda pt: pt[2] < height, triangle))
|
||||
same = list(filter(lambda pt: pt[2] == height, triangle))
|
||||
@@ -100,36 +100,36 @@ def triangle_to_intersecting_lines(triangle, height, pixels, lines):
|
||||
|
||||
|
||||
def where_line_crosses_z(p1, p2, z):
|
||||
if (p1[2] > p2[2]):
|
||||
if p1[2] > p2[2]:
|
||||
p1, p2 = p2, p1
|
||||
# now p1 is below p2 in z
|
||||
if p2[2] == p1[2]:
|
||||
distance = 0
|
||||
else:
|
||||
distance = (z - p1[2]) / (p2[2] - p1[2])
|
||||
|
||||
|
||||
return linear_interpolation(p1, p2, distance)
|
||||
|
||||
|
||||
def calculate_scale_shift(meshes, discretization):
|
||||
mesh_min = meshes[0].min(axis=(0, 1))
|
||||
mesh_max = meshes[0].max(axis=(0, 1))
|
||||
|
||||
|
||||
for mesh in meshes[1:]:
|
||||
mesh_min = np.minimum(mesh_min, mesh.min(axis=(0, 1)))
|
||||
mesh_max = np.maximum(mesh_max, mesh.max(axis=(0, 1)))
|
||||
amplitude = mesh_max - mesh_min
|
||||
#Standard Unit of STL is mm
|
||||
vx=discretization[0]*1000
|
||||
vy=discretization[1]*1000
|
||||
vz=discretization[2]*1000
|
||||
|
||||
bx=int(amplitude[0]/vx)
|
||||
by=int(amplitude[1]/vy)
|
||||
bz=int(amplitude[2]/vz)
|
||||
bounding_box = [bx+1, by+1, bz+1]
|
||||
|
||||
return max(1/vx,1/vy,1/vz), mesh_min, bounding_box
|
||||
amplitude = mesh_max - mesh_min
|
||||
# Standard Unit of STL is mm
|
||||
vx = discretization[0] * 1000
|
||||
vy = discretization[1] * 1000
|
||||
vz = discretization[2] * 1000
|
||||
|
||||
bx = int(amplitude[0] / vx)
|
||||
by = int(amplitude[1] / vy)
|
||||
bz = int(amplitude[2] / vz)
|
||||
bounding_box = [bx + 1, by + 1, bz + 1]
|
||||
|
||||
return max(1 / vx, 1 / vy, 1 / vz), mesh_min, bounding_box
|
||||
|
||||
|
||||
def scale_and_shift_mesh(mesh, scale, shift):
|
||||
@@ -142,7 +142,7 @@ def generate_tri_events(mesh):
|
||||
events = []
|
||||
for i, tri in enumerate(mesh):
|
||||
bottom, middle, top = sorted(tri, key=lambda pt: pt[2])
|
||||
events.append((bottom[2], 'start', i))
|
||||
events.append((top[2], 'end', i))
|
||||
|
||||
events.append((bottom[2], "start", i))
|
||||
events.append((top[2], "end", i))
|
||||
|
||||
return sorted(events, key=lambda tup: tup[0])
|
||||
|
@@ -7,33 +7,35 @@ import h5py
|
||||
from .convert import convert_file
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(format='%(message)s', level=logging.INFO)
|
||||
logging.basicConfig(format="%(message)s", level=logging.INFO)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Parse command line arguments
|
||||
parser = argparse.ArgumentParser(description='Allows the user to convert a STL files to voxelized mesh.', usage='cd gprMax; python -m user_libs.STLtoVoxel.stltovoxel stlfilename matindex dx_dy_dz')
|
||||
parser.add_argument('stlfilename', help='name of STL file to convert including path')
|
||||
parser.add_argument('-matindex', type=int, required=True,
|
||||
help='index of material to extract from STL file')
|
||||
parser.add_argument('-dxdydz', nargs='+', type=float, required=True,
|
||||
help='discretisation to use in voxelisation process')
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Allows the user to convert a STL files to voxelized mesh.",
|
||||
usage="cd gprMax; python -m user_libs.STLtoVoxel.stltovoxel stlfilename matindex dx_dy_dz",
|
||||
)
|
||||
parser.add_argument("stlfilename", help="name of STL file to convert including path")
|
||||
parser.add_argument("-matindex", type=int, required=True, help="index of material to extract from STL file")
|
||||
parser.add_argument(
|
||||
"-dxdydz", nargs="+", type=float, required=True, help="discretisation to use in voxelisation process"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
filename_stl = Path(args.stlfilename)
|
||||
dxdydz = tuple(args.dxdydz)
|
||||
|
||||
logger.info(f'\nConverting STL file: {filename_stl.name}')
|
||||
logger.info(f"\nConverting STL file: {filename_stl.name}")
|
||||
model_array = convert_file(filename_stl, dxdydz)
|
||||
model_array[model_array==0] = -1
|
||||
model_array[model_array==1] = args.matindex
|
||||
logger.info(f'Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}')
|
||||
logger.info(f'Spatial discretisation: {dxdydz[0]} x {dxdydz[1]} x {dxdydz[2]}m')
|
||||
|
||||
# Write HDF5 file for gprMax using voxels
|
||||
filename_hdf5 = filename_stl.with_suffix('.h5')
|
||||
with h5py.File(filename_hdf5, 'w') as f:
|
||||
f.create_dataset('data', data=model_array)
|
||||
f.attrs['dx_dy_dz'] = (dxdydz[0], dxdydz[1], dxdydz[2])
|
||||
model_array[model_array == 0] = -1
|
||||
model_array[model_array == 1] = args.matindex
|
||||
logger.info(f"Number of voxels: {model_array.shape[0]} x {model_array.shape[1]} x {model_array.shape[2]}")
|
||||
logger.info(f"Spatial discretisation: {dxdydz[0]} x {dxdydz[1]} x {dxdydz[2]}m")
|
||||
|
||||
logger.info(f'Written geometry object file: {filename_hdf5.name}')
|
||||
# Write HDF5 file for gprMax using voxels
|
||||
filename_hdf5 = filename_stl.with_suffix(".h5")
|
||||
with h5py.File(filename_hdf5, "w") as f:
|
||||
f.create_dataset("data", data=model_array)
|
||||
f.attrs["dx_dy_dz"] = (dxdydz[0], dxdydz[1], dxdydz[2])
|
||||
|
||||
logger.info(f"Written geometry object file: {filename_hdf5.name}")
|
||||
|
在新工单中引用
屏蔽一个用户