113 lines
4.8 KiB
Python
113 lines
4.8 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, map_scale, vertical_exaggeration):
|
|
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
|
|
self.map_scale = map_scale
|
|
self.vertical_exaggeration = vertical_exaggeration
|
|
|
|
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 * self.map_scale,
|
|
j * self.cell_size_y * self.map_scale,
|
|
self.dem_array[j][i] * self.map_scale * self.vertical_exaggeration)
|
|
|
|
class GridQuadGenerator():
|
|
def __init__(self, grid_size_x, grid_size_y):
|
|
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)
|
|
|
|
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)
|
|
|
|
|
|
class OBJECT_OT_create_mesh_from_geotiff(bpy.types.Operator):
|
|
"""Create a new object from a GeoTIFF"""
|
|
bl_idname = "object.create_mesh_from_geotiff"
|
|
bl_label = "Mesh from GeoTIFF"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.scene.mapping_extension_geotiff_filename
|
|
|
|
def execute(self, context):
|
|
map_origin = context.scene.mapping_extension_map_origin
|
|
map_scale = 1.0 / context.scene.mapping_extension_map_scale
|
|
vertical_exaggeration = context.scene.mapping_extension_vertical_exaggeration
|
|
filename = context.scene.mapping_extension_geotiff_filename
|
|
with rasterio.open(filename) 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_x,
|
|
grid_size_y=grid_size_y,
|
|
cell_size_x=cell_size_x,
|
|
cell_size_y=cell_size_y,
|
|
dem_array=dem_array,
|
|
map_scale=map_scale,
|
|
vertical_exaggeration=vertical_exaggeration)
|
|
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, map_scale, vertical_exaggeration):
|
|
return (GridVertexGenerator(grid_size_x=grid_size_x,
|
|
grid_size_y=grid_size_y,
|
|
cell_size_x=cell_size_x,
|
|
cell_size_y=cell_size_y,
|
|
dem_array=dem_array,
|
|
map_scale=map_scale,
|
|
vertical_exaggeration=vertical_exaggeration),
|
|
[],
|
|
GridQuadGenerator(grid_size_x, grid_size_y))
|
|
|
|
def menu_func(self, context):
|
|
self.layout.operator(CreateMeshFromGeotiffOperator.bl_idname,
|
|
text=CreateMeshFromGeotiffOperator.bl_label)
|