- Reads CSV files containing `x, y, z, label` - Converts coordinates from feet to the current Blender scene units - Offsets large world coordinates near the origin for precision - Corrects axis orientation (Y flip + proper Z alignment) - Creates labeled empties for each survey point - Optionally filters out unwanted point types (e.g. buildings or utilities) - Generates a Delaunay-triangulated 3D mesh surface from the remaining points The result is a clean, unit-accurate terrain mesh built directly from raw survey data inside Blender.
56 lines
No EOL
1.5 KiB
Python
56 lines
No EOL
1.5 KiB
Python
import bpy
|
|
from mathutils import Vector
|
|
from scipy.spatial import Delaunay
|
|
|
|
# Name of the collection containing the empties
|
|
collection_name = "CSV_Points"
|
|
|
|
# Names to exclude (case-insensitive)
|
|
EXCLUDE_KEYWORDS = ["HSE", "FOO", "BAR"]
|
|
|
|
# Get the collection
|
|
col = bpy.data.collections.get(collection_name)
|
|
if not col:
|
|
raise ValueError(f"Collection '{collection_name}' not found")
|
|
|
|
# Filter empties
|
|
valid_objects = []
|
|
for obj in col.objects:
|
|
if obj.type != 'EMPTY':
|
|
continue
|
|
|
|
name_upper = obj.name.upper()
|
|
if any(keyword in name_upper for keyword in EXCLUDE_KEYWORDS):
|
|
continue
|
|
|
|
valid_objects.append(obj)
|
|
|
|
if len(valid_objects) < 3:
|
|
raise ValueError("Not enough valid points to triangulate.")
|
|
|
|
print(f"Using {len(valid_objects)} empties after filtering.")
|
|
print(f"Skipped {len(col.objects) - len(valid_objects)} objects.")
|
|
|
|
# Extract XY and Z
|
|
points = []
|
|
z_values = []
|
|
|
|
for obj in valid_objects:
|
|
points.append([obj.location.x, obj.location.y])
|
|
z_values.append(obj.location.z)
|
|
|
|
# Perform Delaunay triangulation
|
|
tri = Delaunay(points)
|
|
faces = tri.simplices.tolist()
|
|
|
|
# Create new mesh
|
|
mesh = bpy.data.meshes.new("TriangulatedMesh")
|
|
mesh_obj = bpy.data.objects.new("TriangulatedMesh", mesh)
|
|
bpy.context.collection.objects.link(mesh_obj)
|
|
|
|
# Create mesh
|
|
verts = [Vector((p[0], p[1], z_values[i])) for i, p in enumerate(points)]
|
|
mesh.from_pydata(verts, [], faces)
|
|
mesh.update()
|
|
|
|
print(f"Created mesh with {len(mesh.vertices)} vertices and {len(mesh.polygons)} faces.") |