Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import bpy
def dupliOnCurve(curve_length_effect=None, replace=None):
'''
When you want to duplicate an object on object: Simply do "object > make links > object data".
The function is optimised for an object to duplicate on curves, althoubh it can be used to duplicate on objects.
Usage:
1. Multiple selecte curves, and lastly select an object as an object to be duplicated.
2. Paste the code on text editor which can be found in scripting layout.
Arguments:
curve_length_rate:
How intense the length of curve affect the scale of duplicated object. 0 is no effect.
Default is 0.
replace:
If True, the selected curves will be removed, and only the duplicated objects reimans.
If False, the selected curves won't be removed.
'''
# Default value of curve_length_rate is 0.
if curve_length_effect == None:
curve_length_effect = 0
else:
curve_length_effect = curve_length_effect
# Default value of replace is False.
if replace == True:
replace == True
else:
replace = False
# Name of lastly selected active object to be duplicated.
active_object_name = bpy.context.scene.objects.active.name
# Name list of selected curves/objects, except for lastly selected active object.
selected_object_names = [obj.name for obj in bpy.context.selected_objects if obj.name != active_object_name]
# List of edge lengths for curves/objects.
edge_length_list = []
# Convert the selected curves into objects, and add the edge lenght to edge_length_list.
for selected_object_name in selected_object_names:
# Asign each selected object.
selected_object = bpy.data.objects[selected_object_name]
# If replace == False, the original curve/object is duplicated.
# (it's not duplication of selected object on curves, just for keeping original curves).
if replace == False:
_makeDupli(selected_object)
# If it's curve, convert the curve into object.
if selected_object.type == "CURVE":
_curveToMesh(selected_object)
# calculate the lenght of edge, then append it to edge_length_list.
if curve_length_effect != 0:
edge_length = _getLength(selected_object)
edge_length_list.append(edge_length)
# Calculate average edge length.
avarage_edge_length = sum(edge_length_list)/len(edge_length_list)
# Re-select and change their scale relfecting edge length.
bpy.ops.object.select_all(action='DESELECT')
for i, selected_object_name in enumerate(selected_object_names):
selected_object = bpy.data.objects[selected_object_name]
selected_object.select = True
# Effect for scale = curve_length_effect * (its edge length - average edge lenght) - average edge length.
try:
scale_rate = curve_length_effect * (edge_length_list[i] - avarage_edge_length) / avarage_edge_length
# When avarage_edge_length is 0, set scale_rate=0.
except ZeroDivisionError:
scale_rate = 0
# Change scaled of selected object into the same as scale of duplicated object + scale_rate.
selected_object.scale.x = bpy.data.objects[active_object_name].scale.x + scale_rate
selected_object.scale.y = bpy.data.objects[active_object_name].scale.y + scale_rate
selected_object.scale.z = bpy.data.objects[active_object_name].scale.z + scale_rate
# Re-activate the object which was selected as active object at first.
bpy.context.scene.objects.active = bpy.data.objects[active_object_name]
# Duplicate active object on the curves by linking the data to them.
bpy.ops.object.make_links_data(type='OBDATA')
# Duplicate curves to keep original curves.
def _makeDupli(selected_object):
bpy.ops.object.select_all(action='DESELECT')
selected_object.select = True
# Make duplication.
bpy.ops.object.duplicate_move()
bpy.ops.object.select_all(action='DESELECT')
# Convert curve into mesh.
def _curveToMesh(selected_object):
# Select and active only the curve per loop.
bpy.ops.object.select_all(action='DESELECT')
selected_object.select = True
bpy.context.scene.objects.active = selected_object
# Convert curve into mesh.
bpy.ops.object.convert(target='MESH', keep_original=False)
bpy.ops.object.select_all(action='DESELECT')
# Calculate edge length of a curve.
def _getLength(selected_object):
bpy.ops.object.select_all(action='DESELECT')
selected_object.select = True
bpy.context.scene.objects.active = selected_object
# Temporary duplicate it.
bpy.ops.object.duplicate_move()
try:
# Change origin to center to calculate the lenght easily.
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
# Calculate the edge length.
mesh_data = bpy.context.active_object.data
edge_length = 0
for edge in mesh_data.edges:
vert0 = mesh_data.vertices[edge.vertices[0]].co
vert1 = mesh_data.vertices[edge.vertices[1]].co
edge_length += (vert0-vert1).length
# When the length cannot be calculated, set 0.
except:
edge_length = 0
# Delete temporal duplicated object.
bpy.ops.object.delete()
bpy.ops.object.select_all(action='DESELECT')
return edge_length
# Execute.
dupliOnCurve(curve_length_effect=0.5, replace=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment