Untitled

mail@pastecode.io avatar
unknown
plain_text
8 days ago
4.3 kB
2
Indexable
Never
import bpy
import math
import csv
import os
from mathutils import Vector
from mathutils.bvhtree import BVHTree

def main():
    # 1. Access the Active Mesh Object
    obj = bpy.context.active_object
    
    if obj is None:
        print("Error: No active object selected.")
        return
    
    if obj.type != 'MESH':
        print(f"Error: Active object '{obj.name}' is not a mesh.")
        return
    
    mesh = obj.data
    
    # Ensure the mesh is up to date
    mesh.calc_loop_triangles()
    
    # 2. Define the Logical 250x250 Grid
    GRID_SIZE = 250  # 250x250 grid
    Z_SCALE = 250    # Z-axis scaling factor
    
    # 3. Prepare for Ray Casting
    # Build BVH Tree for efficient ray casting
    try:
        bvhtree = BVHTree.FromObject(obj, bpy.context.view_layer.depsgraph)
    except Exception as e:
        print(f"Error: Failed to create BVH Tree for object '{obj.name}'. Exception: {e}")
        return
    
    # 4. Determine Mesh Bounds in World Space
    world_verts = [obj.matrix_world @ vertex.co for vertex in mesh.vertices]
    min_x = min(vertex.x for vertex in world_verts)
    max_x = max(vertex.x for vertex in world_verts)
    min_y = min(vertex.y for vertex in world_verts)
    max_y = max(vertex.y for vertex in world_verts)
    min_z = min(vertex.z for vertex in world_verts)
    max_z = max(vertex.z for vertex in world_verts)
    
    range_x = max_x - min_x if max_x - min_x != 0 else 1
    range_y = max_y - min_y if max_y - min_y != 0 else 1
    range_z = max_z - min_z if max_z - min_z != 0 else 1
    
    # 4.2 Define Grid Spacing
    step_x = range_x / (GRID_SIZE - 1)
    step_y = range_y / (GRID_SIZE - 1)
    
    # 5. Initialize a 250x250 Two-Dimensional Array with default Z-value 0
    terrain_array = [[0 for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)]
    
    # 6. Perform Ray Casting for Each Grid Cell
    print("Starting ray casting...")
    for i in range(GRID_SIZE):
        for j in range(GRID_SIZE):
            # Calculate the (X, Y) position for this grid cell
            x = min_x + j * step_x
            y = min_y + i * step_y
            origin = Vector((x, y, min_z - 10))  # Start well below the mesh
            direction = Vector((0, 0, 1))        # Cast upwards along Z-axis
            
            # Perform the ray cast
            location, normal, index, distance = bvhtree.ray_cast(origin, direction)
            
            if location:
                # Calculate the Z-value from the intersection point
                z = location.z
                # Scale Z to fit within 0 to Z_SCALE
                scaled_z = (z - min_z) / range_z * Z_SCALE
                # Clamp to 0-Z_SCALE
                scaled_z = max(0, min(Z_SCALE, scaled_z))
                terrain_array[i][j] = scaled_z
            else:
                # If no intersection, assign default value (e.g., 0)
                terrain_array[i][j] = 0
                
        # Optional: Print progress every 25 rows
        if (i+1) % 25 == 0:
            print(f"Progress: {i+1}/{GRID_SIZE} rows processed.")
    
    print("Ray casting completed.")
    
    # 7. Output the 2D Array
    # Option 1: Print to Console (Warning: Large Output)
    # Uncomment the following lines if you want to print the array
    # for row in terrain_array:
    #     print(row)
    
    # Option 2: Export to CSV
    # Define the output file path
    output_dir = bpy.path.abspath("//")  # Current Blender file directory
    output_file = os.path.join(output_dir, "terrain_elevation.csv")
    
    try:
        with open(output_file, mode='w', newline='') as csv_file:
            writer = csv.writer(csv_file)
            for row in terrain_array:
                writer.writerow(row)
        print(f"Elevation data successfully exported to '{output_file}'.")
    except Exception as e:
        print(f"Error: Failed to write CSV file. {e}")
    
    # Option 3: Return the Array for Further Processing
    # Here, we'll store it in a custom scene property
    bpy.context.scene["TerrainElevation"] = terrain_array
    print("Elevation data stored in scene property 'TerrainElevation'.")

# Run the main function
if __name__ == "__main__":
    main()
Leave a Comment