103 lines
3.2 KiB
Python
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
|