rig_picker/core/shape.py

180 lines
4.7 KiB
Python

import bpy
import bmesh
from mathutils import Vector, Matrix
from bpy_extras import mesh_utils
from .geometry_utils import bound_box_center
from .addon_utils import get_object_color
def border_over_shape(border,verts,loops):
for loop in loops:
for i,p in enumerate(loop):
a = Vector(verts[loop[i-1]])
b = Vector(verts[p])
for j in range(0,4):
c = border[j-1]
d = border[j]
if intersect_line_line_2d(a,b,c,d):
return True
for point in verts:
if point_inside_rect(point,border):
return True
for point in border:
if point_over_shape(point,verts,loops):
return True
def border_loop(vert, loop):
border_edge =[e for e in vert.link_edges if e.is_rectary]
if border_edge:
for edge in border_edge:
other_vert = edge.other_vert(vert)
if not other_vert in loop:
loop.append(other_vert)
border_loop(other_vert, loop)
return loop
else:
return [vert]
def contour_loops(bm, vert_index=0, loops=None, vert_indices=None):
loops = loops or []
vert_indices = vert_indices or [v.index for v in bm.verts]
bm.verts.ensure_lookup_table()
loop = border_loop(bm.verts[vert_index], [bm.verts[vert_index]])
if len(loop) >1:
loops.append(loop)
for v in loop:
vert_indices.remove(v.index)
if len(vert_indices):
contour_loops(bm, vert_indices[0], loops, vert_indices)
return loops
def get_shape_data(ob, matrix=None, depsgraph=None):
if not matrix:
matrix = Matrix()
if not depsgraph:
depsgraph = bpy.context.evaluated_depsgraph_get()
gamma = 1 / 2.2
eval_ob = ob.evaluated_get(depsgraph)
mesh = eval_ob.to_mesh()
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.002)
bmesh.ops.dissolve_limit(bm, angle_limit=0.001745, verts=bm.verts, edges=bm.edges)
bmesh.ops.connect_verts_concave(bm, faces=bm.faces)
bmesh.ops.triangulate(bm, faces=bm.faces)
edges = [[v.index for v in e.verts] for e in bm.edges if len(e.link_faces)<=1]
bm.to_mesh(mesh)
mesh.update()
bm.clear()
points = []
polygons = []
depths = []
for vert in mesh.vertices:
co = matrix @ (ob.matrix_world @ Vector(vert.co))
points.append([round(co[0], 1), round(co[1], 1)])
depths += [co[2]]
if depths:
depth = max(depths)
else:
print(f'{ob.name} has no vertices')
depth = 0
for face in mesh.polygons:
polygons.append([v for v in face.vertices])
color = get_object_color(ob)
if color:
color = [round(pow(c, gamma), 4) for c in color]
else:
color = [0.5, 0.5, 0.5]
shape = {
'source_name': ob.name,
'tooltip': ob.rig_picker.name,
'depth': depth,
'points': points,
'polygons': polygons,
'edges': edges,
'color': color,
'type': ob.rig_picker.shape_type
}
if shape['type'] =='OPERATOR':
shape['operator'] = ob.rig_picker.operator
shape['shortcut'] = ob.rig_picker.shortcut
elif shape['type'] =='BONE':
shape['bone'] = ob.rig_picker.name
eval_ob.to_mesh_clear()
return shape
def get_picker_data(collection):
picker_data = []
depsgraph = bpy.context.evaluated_depsgraph_get()
canvas = collection.rig_picker.canvas
if canvas.type == 'CURVE':
canvas_points = canvas.data.splines[0].points
else:
canvas_points = canvas.data.vertices
canvas_coords = [canvas.matrix_world@Vector((p.co)) for p in canvas_points]
height = abs(max(canvas_coords).y - min(canvas_coords).y)
width = abs(max(canvas_coords).x - min(canvas_coords).x)
center = sum(canvas_coords, Vector()) / len(canvas_coords)
scale = 2048 / max(height, width)# Reference height for the canvas
matrix = Matrix.Translation(-center)
matrix = Matrix.Scale(scale, 4) @ matrix
#sorted by their z axes
for ob in collection.all_objects:
if ob.instance_collection:
for shape in ob.instance_collection.all_objects:
picker_data.append(get_shape_data(shape, matrix=matrix@ob.matrix_world, depsgraph=depsgraph))
elif ob.type in ('MESH', 'CURVE', 'FONT'):
picker_data.append(get_shape_data(ob, matrix=matrix, depsgraph=depsgraph))
else:
#print(f'{ob.name} of type {ob.type} not supported')
continue
picker_data.sort(key=lambda x : x['depth'])
#print(picker_datas)
return picker_data
#rig.data.rig_picker['shapes'] = picker_datas