blender-mapping-tools/create_mesh_from_geotiff.py

116 lines
4.3 KiB
Python

import bpy
from bpy.props import StringProperty
from bpy_extras.io_utils import ImportHelper
import rasterio
class GridVertexGenerator():
def __init__(self, grid_size_x, grid_size_y, cell_size_x, cell_size_y, dem_array):
self.cell_size_x = cell_size_x
if cell_size_y is not None:
self.cell_size_y = cell_size_y
else:
self.cell_size_y = cell_size_x
self.grid_size_x = grid_size_x
self.grid_size_y = grid_size_y
self.dem_array = dem_array
def __len__(self):
return self.grid_size_x * self.grid_size_y
def __iter__(self):
return self._generator()
def _generator(self):
for j in range(self.grid_size_y):
for i in range(self.grid_size_x):
yield (i * self.cell_size_x,
j * self.cell_size_y,
self.dem_array[j][i])
class GridTriangleGenerator():
def __init__(self, grid_size_x, grid_size_y, cell_size_x, cell_size_y=None):
self.cell_size_x = cell_size_x
if cell_size_y is not None:
self.cell_size_y = cell_size_y
else:
self.cell_size_y = cell_size_x
self.grid_size_x = grid_size_x
self.grid_size_y = grid_size_y
def __len__(self):
#return (self.grid_size_x - 1) * (self.grid_size_y - 1) * 2
return (self.grid_size_x - 1) * (self.grid_size_y - 1)
def __iter__(self):
return self._generator()
def _generator(self):
for i in range(self.grid_size_x - 1):
for j in range(self.grid_size_y - 1):
v00 = j * self.grid_size_x + i
v01 = (j + 1) * self.grid_size_x + i
v10 = j * self.grid_size_x + i + 1
v11 = (j + 1) * self.grid_size_x + i + 1
yield (v00, v10, v11, v01)
#yield (v00, v10, v01)
#yield (v01, v10, v11)
class CreateMeshFromGeotiffOperator(bpy.types.Operator, ImportHelper):
"""Create a new object from a GeoTIFF"""
bl_idname = "object.create_mesh_from_geotiff"
bl_label = "Mesh from GeoTIFF"
filter_glob = StringProperty(default="*.tif;*.tiff", options={"HIDDEN"})
def execute(self, context):
with rasterio.open(self.properties.filepath) as geotiff:
grid_size_x = geotiff.width
grid_size_y = geotiff.height
print(f"GeoTIFF is {grid_size_x}x{grid_size_y}")
bounds = geotiff.bounds
print(f"GeoTIFF bounds: {bounds}")
cell_size_x = (bounds.right - bounds.left) / geotiff.width
cell_size_y = (bounds.bottom - bounds.top) / geotiff.height
print(f"Calculated cell size: {cell_size_x} x {cell_size_y}")
print("Reading GeoTIFF...")
dem_array = geotiff.read(1)
print("Processing values...")
print("Done.")
mesh = bpy.data.meshes.new("mesh")
dem_obj = bpy.data.objects.new("DEM", mesh)
collection = bpy.data.collections["Collection"]
collection.objects.link(dem_obj)
context.view_layer.objects.active = dem_obj
print("Creating mesh data...")
(vertices, edges, faces) = self.construct_mesh(grid_size_x, grid_size_y, cell_size_x, cell_size_y, dem_array)
print("Constructing mesh...")
mesh.from_pydata(vertices, edges, faces, shade_flat=False)
print("Done.")
mesh.validate(verbose=True)
return {'FINISHED'}
def construct_mesh(self, grid_size_x, grid_size_y, cell_size_x, cell_size_y, dem_array):
#grid_size_x = 10
#grid_size_y = 15
#cell_size_x = 0.75
#cell_size_y = 0.5
return (GridVertexGenerator(grid_size_x, grid_size_y, cell_size_x, cell_size_y, dem_array),
[],
GridTriangleGenerator(grid_size_x, grid_size_y, cell_size_x, cell_size_y))
def menu_func(self, context):
self.layout.operator(CreateMeshFromGeotiffOperator.bl_idname,
text=CreateMeshFromGeotiffOperator.bl_label)
def register():
bpy.utils.register_class(CreateMeshFromGeotiffOperator)
bpy.types.VIEW3D_MT_add.append(menu_func)
def unregister():
bpy.utils.unregister_class(CreateMeshFromGeotiffOperator)
bpy.types.VIEW3D_MT_add.remove(menu_func)
if __name__ == "__main__":
register()