Skip to content

Instantly share code, notes, and snippets.

@pgtwitter
Created June 5, 2024 09:12
Show Gist options
  • Save pgtwitter/b4781a5d3516ba889c108ee780092392 to your computer and use it in GitHub Desktop.
Save pgtwitter/b4781a5d3516ba889c108ee780092392 to your computer and use it in GitHub Desktop.
Convex hull division using Fiedler vectors
# %%
import bpy
import networkx as nx # /path/to/blender's/python -m pip install scipy networkx
import numpy as np
from scipy.spatial import ConvexHull
def obj2GraphAndXyzAndNormFiedler(obj):
edges = [(e.vertices[0], e.vertices[1]) for e in obj.data.edges]
G = nx.Graph(edges)
xyz = dict(zip(G.nodes, [obj.data.vertices[i].co for i in G.nodes]))
S = [G.subgraph(c).copy() for c in nx.connected_components(G)]
G = S[0]
fiedler_vector = nx.fiedler_vector(G)
minV, maxV = min(fiedler_vector), max(fiedler_vector)
width = maxV-minV
norm_fiedler = [(v-minV)/width for v in fiedler_vector]
return G, xyz, norm_fiedler
def GraphAndXyzAndCategory2MeshLys(G, xyz, category):
subnodeLys = [[n for n, target in zip(G.nodes, category) if target == c] for c in range(k)]
subgraphLys = [[G.subgraph(c).copy() for c in nx.connected_components(G.subgraph(subnodes))]
for subnodes in subnodeLys]
hullLys = [[ConvexHull([xyz[n] for n in H.nodes]) for H in subgraphLy]for subgraphLy in subgraphLys]
meshLys = [[{'verts': hull.points, 'faces': hull.simplices} for hull in hullLy] for hullLy in hullLys]
return meshLys
def addObjectWithMesh(name, verts, faces, collection='Collection'):
mesh = bpy.data.meshes.new(name)
obj = bpy.data.objects.new(mesh.name, mesh)
col = bpy.data.collections[collection]
col.objects.link(obj)
bpy.context.view_layer.objects.active = obj
mesh.from_pydata(verts, [], faces)
return obj
# %%
objName = 'bun_zipper'
obj = bpy.data.objects[objName]
G, xyz, norm_fiedler = obj2GraphAndXyzAndNormFiedler(obj)
# %%
k = 24
category = [int(np.floor(v * k)) for v in norm_fiedler]
category = [k-1 if c == k else c for c in category]
meshLys = GraphAndXyzAndCategory2MeshLys(G, xyz, category)
# %%
collection_name = f'{objName}_parts'
if collection_name not in bpy.data.collections:
collection = bpy.data.collections.new(collection_name)
bpy.context.scene.collection.children.link(collection)
for i, meshLy in enumerate(meshLys):
for j, mesh in enumerate(meshLy):
newObj = addObjectWithMesh(
f'{objName}_part_{i}_{j}',
mesh['verts'],
mesh['faces'],
collection=collection_name)
newObj.location = obj.location
newObj.rotation_euler = obj.rotation_euler
newObj.scale = obj.scale
# %%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment