# -*- coding: utf-8 -*- """Opens OrePatches.blend read-only and checks how the clusters sit: does every cluster reach into the rock all round its foot, and do two clusters of one patch run into each other. blender -b ../OrePatches.blend --python check_fit.py """ import bpy, bmesh, os, json, math import numpy as np from mathutils import Vector from mathutils.bvhtree import BVHTree HERE = os.path.dirname(os.path.abspath(__file__)) dg = bpy.context.evaluated_depsgraph_get() out = {} def tree(ob): bm = bmesh.new() bm.from_mesh(ob.data) bm.transform(ob.matrix_world) t = BVHTree.FromBMesh(bm) V = np.array([v.co[:] for v in bm.verts]) bm.free() return t, V for root in [o for o in bpy.data.objects if o.type == 'EMPTY' and o.name.startswith('OrePatch_')]: rock = next(c for c in root.children if c.name.startswith('SM_OreRock_')) insts = sorted([c for c in root.children if '_Ore_' in c.name], key=lambda o: o.name) rt, _ = tree(rock) trees = [tree(o) for o in insts] floating, crossing = [], [] for ob, (t, V) in zip(insts, trees): mw = ob.matrix_world z = (mw.to_3x3() @ Vector((0, 0, 1))).normalized() s = mw.to_scale()[0] # 12 points round the foot, at 70 % of the footprint: the rock must reach the cluster's base plane there worst = 1e9 for k in range(12): a = k * math.pi / 6 p = mw @ Vector((0.175 * math.cos(a), 0.175 * math.sin(a), 0.0)) hit = rt.ray_cast(p + z * (0.5 + 0.25 * s), -z) if hit[0] is None: worst = min(worst, -9.0) continue worst = min(worst, ((hit[0] - p).dot(z)) / s) if worst < -0.002: floating.append((ob.name, round(worst * s, 3))) for i in range(len(insts)): for j in range(i + 1, len(insts)): n = len(trees[i][0].overlap(trees[j][0])) if n: crossing.append((insts[i].name.split('_Ore_')[1], insts[j].name.split('_Ore_')[1], n)) out[root.name] = dict(clusters=len(insts), foot_above_rock=floating, crossing_pairs=crossing) print('[fit]', root.name, 'clusters', len(insts), '| foot not buried:', floating or 'none', '| crossing pairs:', crossing or 'none') json.dump(out, open(os.path.join(HERE, 'fit_report.json'), 'w'), indent=1)