framework/cg/blender/utils/mesh_tools.py
2023-10-16 12:21:34 +00:00

103 lines
3.2 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (C) 2023 Ilia Kurochkin <brothermechanic@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
'''
DESCRIPTION.
Various mesh tools for Edit Mode.
'''
__version__ = '0.1'
import bpy
import bmesh
from math import radians
def select_peaks(me, peak_limit_angle=60, peak_accuracy_angle=10):
''' Select sharp vertices that stand alone. '''
bm = bmesh.from_edit_mesh(me)
def is_sharp(vert, eps=radians(peak_limit_angle)):
sharps = []
face_before = None
for face in vert.link_faces:
if face_before:
face_angle = face.normal.angle(face_before.normal)
if face_angle > radians(peak_accuracy_angle):
angle = vert.normal.angle(face.normal)
if angle > eps:
sharps.append(angle)
face_before = face
return (
(len(sharps) + 1) == len(vert.link_faces)
or (len(sharps) + 2) == len(vert.link_faces)
)
def non_single(vert):
for edge in vert.link_edges:
if edge.other_vert(vert).select:
return False
return True
for v in bm.verts:
v.select_set(
is_sharp(v)
)
for v in bm.verts:
if v.select:
v.select_set(
non_single(v)
)
bmesh.update_edit_mesh(me)
return me
def select_zero_faces(me):
''' Select very small faces. '''
bm = bmesh.from_edit_mesh(me)
[f.select_set(True) for f in bm.faces if f.calc_area() < 1e-7]
bmesh.update_edit_mesh(me)
return me
def select_stratched_edges(me, edge_length_limit=0.002):
''' Select very stratched edges of small faces. '''
bm = bmesh.from_edit_mesh(me)
faces_stratched = [f for f in bm.faces if f.calc_area() < 1e-6]
for face in faces_stratched:
edges_lengths = {e: e.calc_length() for e in face.edges}
edge_max_length = max(edges_lengths.values())
if edge_max_length > edge_length_limit:
edge_max = [k for k, v in edges_lengths.items() if v == edge_max_length][0]
edge_max.select_set(True)
bmesh.update_edit_mesh(me)
return me
def collect_less_volume_objs(objs: list, min_volume):
''' Separate selection for less volume objects. '''
less_volume_objs = []
for obj in objs:
bpy.ops.object.select_all(action='DESELECT')
if obj.type != 'MESH':
continue
# requed for bmesh
obj.hide_set(False)
obj.select_set(state=True)
if obj.type == 'MESH':
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(obj.data)
if bm.calc_volume() < min_volume:
less_volume_objs.append(obj)
bpy.ops.object.mode_set(mode='OBJECT')
return less_volume_objs