Source code for snnib.blender.utils.random

"""functions for random generation

Exceptions

Classes

Functions
    - `random_points_bbox()` -- generates random points inside a bounding box
    - `random_points_raycast()` -- BROKEN; generates random points based on raycasting

Other Objects
"""

#%%imports
import bpy
from mathutils import Vector
from mathutils.bvhtree import BVHTree

import numpy as np

import logging

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

#%%definitions
[docs] def random_points_bbox( obj:bpy.types.Object, Rng:np.random.Generator, n:int=1, ) -> np.ndarray: """generates `n` random points inside the bounding box of `obj` Parameters - `obj` - `bpy.types.Object` - object to use the bounding box of - `Rng` - `np.random.Generator` - random number generator - `n` - `int`, optional - number of points to generate - the default is `1` Raises Returns - `coords` - `np.ndarray` - has shape `(n,3)` - randomly generated coordinates Dependencies - `bpy` - `mathutils` - `numpy` - `logging` - `typing` """ #generate neurons at random locations min = np.array([v.co for v in obj.data.vertices]).min(axis=0) max = np.array([v.co for v in obj.data.vertices]).max(axis=0) coords = Rng.random((n,3)) * (max - min) + min return coords
[docs] def random_points_raycast( obj:bpy.types.Object, Rng:np.random.Generator, n:int=1, ) -> np.ndarray: """BROKEN; generates a random points inside `obj` Parameters - `obj` - `bpy.types.Object` - object to use as host - `Rng` - `np.random.Generator` - random number generator - `n` - `int`, optional - number of points to generate - the default is `1` Raises Returns - `coords` - `np.ndarray` - has shape `(n,3)` - randomly generated coordinates Dependencies - `bpy` - `mathutils` - `numpy` - `logging` - `typing` """ def is_point_inside( point:Vector, bvh:BVHTree, ) -> bool: """determine if a point is inside some geometry - cast a ray in +X direction. - if surface hit an odd number of times => point is inside. """ direction = Vector([1, 0, 0]) #raycast direction hit_count = 0 #init hit-count origin = point #ray-origin while True: hit = bvh.ray_cast(origin, direction) #cast a ray if not hit[0]: #case: no intersection at all break #increase hit-count hit_count += 1 #move origin slightly forward => avoids hitting same face again origin = hit[0] + direction * 1e-6 print(origin) return (hit_count % 2) == 1 #get evaluated mesh (modifiers applied) depsgraph = bpy.context.evaluated_depsgraph_get() eval_obj = obj.evaluated_get(depsgraph) #build BVH for fast ray tests bvh = BVHTree.FromObject(eval_obj, depsgraph) #generate points coords = np.empty((n, 3)) for i in range(n): while True: point = Vector(random_points_bbox(obj, Rng, 1).flatten()) if is_point_inside(point, bvh): coords[i] = np.array(point) break return coords
#%%registration def register(): pass def unregister(): pass