I want to compute the center of each spline from object.data.splines.
To do that I try something like:
for obj in curves:
for index in range(len(obj.data.splines)):
temp_obj = obj.evaluated_get(depsgraph).copy()
temp_obj.data = temp_obj.to_curve(depsgraph).copy()
# Remove all splines but the current one based on the `index` taken from `obj.data.splines`
for temp_spline in chain(temp_obj.data.splines[:index], temp_obj.data.splines[index + 1:]):
temp_obj.data.splines.remove(temp_spline)
temp_mesh = temp_obj.to_mesh()
# Compute mean of `temp_mesh.vertices`
temp_obj.to_mesh_clear()
temp_obj.to_curve_clear()
bpy.data.curves.remove(temp_obj.data)
This doesn’t work though because temp_obj.to_mesh() seems to rely on some cached or something based on the splines I remove.
This results in WARN (bke.anim): source/blender/blenkernel/intern/anim_path.c:68 BKE_anim_path_calc_data: No bev list data! after which the spline data gets removed so to_mesh() fails and results in a mesh with no vertices for any index > 0.
In the worst case scenario I have to reconstruct a curve object with a new spline and copy all the individual points taking into account the curve type poly - nurbs, bezier which I’d rather avoid if possible.
Any other ideas on how to get the center of splines or if there’s something I’m missing that would make my implementation work?
import bpy
def calculate_centers_of_splines():
for curve in bpy.data.curves:
for spline in curve.splines:
if spline.type != 'BEZIER':
print('only bezier splines allowed')
continue
sum_points = [0,0,0]
for p in spline.bezier_points:
for i in range(3):
sum_points[i] += p.co[0]
total_points = len(spline.bezier_points)
if total_points == 0:
continue
result = [0,0,0]
for i in range(3):
result[i] = sum_points[i] / total_points
print('spline:', spline, "center:", result)
calculate_centers_of_splines()
Chances that you have to access an enormous amount of curves is slim, from what I see if you have more than a few thousand splines with hundreds of thousands of points then you would have to seek better ways to optimize the code (better to write internal C code within Blender and eject the data as binary file ).
Your solution doesn’t take into account the shape of the spline based on bezier handles (if they’re used), that’s why I wanted to convert to mesh with temp_obj.to_mesh() because it takes in account all parameters, including resolution, handles etc.
I figured out a solution that works, I don’t really like it cause it’s definitely a hack due to caching, but it does work for my need:
for obj in source:
obj_data = obj.data
for index in range(len(obj.data.splines)):
temp_obj = obj.evaluated_get(depsgraph).copy()
temp_obj.data = temp_obj.data.copy()
for temp_spline in chain(temp_obj.data.splines[:index], temp_obj.data.splines[index + 1:]):
temp_obj.data.splines.remove(temp_spline)
obj.data = temp_obj.data
temp_mesh = obj.to_mesh()
obj.data = obj_data
if len(temp_mesh.vertices) > 0:
vector_mean = temp_obj.matrix_world @ sum((v.co for v in temp_mesh.vertices), Vector()) / len(temp_mesh.vertices)
# Do something with vector_mean
obj.to_mesh_clear()
temp_obj.to_mesh_clear()
bpy.data.curves.remove(temp_obj.data)
No because it has to do with how the points on average are calculated. I got it wrong at first myself and then understood the problem better.
A: Curve: any object by default can have it’s origin location anywhere so you can’t be sure about which is which (unless you do set origin to cursor etc...)
B: Curve: If you select all points and do set cursor to selection this is where you get the center point. But is only based on three points as the curve has.
C: Mesh: In this converted curve to mesh, now you get all of the vertices in all positions and the result is the real deal.
This algorithm can be used on any type of curve object type: POLY, BEZER & NURBS. I mean to be more specific, on any spline type. Cause in a curve object you can have at the very least POLY & BEZIER at the same time.
The source variable is just an iterator of objects (list, tuple, generator etc.) as long as they’re of bpy.types.Object type so for example source = [bpy.data.objects['Cube']] # assuming the Cube object exists.
How is it defined specifically in my script? It’s based on a drop-down property that the user uses to pic objects or collections of objects and I convert those to a list of objects like I mentioned.
Only tried with 3.4.
I don’t understand the question. It works with any object that Blender has in the database. I use depsgraph because I want the “evaluated” object - so objects with modifiers, shape keys etc. applied. I’m pretty sure that the evaluated objects and what we see in the 3D viewport is basically the same thing, cause what we see is the state of the evaluated objects if they have modifiers etc.