Blender: Python script to change curve’s origin to a tip

The problem:

When you rotate a Bezier curve, the curve spin around the curve’s origin point. The origin point usually stay at geometric center.
The problem comes here. After rotation, a tip of the curve changes its location.

python_change_curve_origin_before

python_change_curve_origin_after

 

It’s fatal fault when you map curves as a location point, such as 3D map with curves like below. The location wrongly is changed, when you stand the curves!
python_change_curve_origin_map

 

You can change origin point to a curve’s tip, so that the location of tip doesn’t change after rotation.
python_change_curve_origin_tip

You can change origin point to its tip manually.
But when you deal with hundreds of curves, you want to change origin points by multiple selection and several clicks, right?

 

Usage of the snippet:

  1. Multiple select curves that you want to change origin point.
  2. Change view from “Default” to “Scripting” by clicking an icon on upper menu.
  3. In the scripting view, press new of the code editor. Then paste the snippet below.
  4. Change option of the function at the very bottom, changeMultipleCurveOrigin(xyz=’x’, maxmin=’max’).
    x/y/z is axis you want to change origin point to the curve’s tip. max/min is criteria of calculating tip.
  5. Right click and click “Run Script”

python_change_curve_origin_runscript

 

 

The code:

'''
changeCurveOrigin can relocate origin of curves at max or min of x/y/z vertex of the curve.
Many curves can be applied by multiple selection.

options:
xyz='x'/'y'/'z'. xyz is coordinate to use to compare value.
maxmin='max'/'min'. maxmin is comparing criteria by max or min.
'''
import bpy
def changeMultipleCurveOrigin(xyz='x', maxmin='max'):

    # Store multiple selected curves.
    selected_curves = bpy.context.selected_objects

    for curve in selected_curves:
        # Deselect all and select one curve.
        bpy.ops.object.select_all(action='DESELECT')
        curve.select = True

        # Return vertex point where max or min value of x/y/x.
        vert_tip_point = getMaxOrMinVertex(curve,xyz,maxmin)

        # Change cursor's location to the tip point.
        bpy.context.scene.cursor_location = vert_tip_point

        # Activate the curve object
        bpy.context.scene.objects.active = curve

        # Set origin at cursor = vertex tip point.
        bpy.ops.object.origin_set(type='ORIGIN_CURSOR')

# Get curve's vertex point where max/min of x/y/x.
def getMaxOrMinVertex(curve,xyz='x',maxmin='max'):

    # Specify which coordinate will be used to compare.
    coord_index = 0
    if xyz == 'x':
        coord_index = 0
    elif xyz == 'y':
        coord_index = 1
    elif xyz == 'z':
        coord_index = 2
    else:
        coord_index = 0

    # Matrix multiplier for local point to change into global point, due to cursor point using global point.
    curve_matrix_world = curve.matrix_world

    vert_tip_point = (0,0,0)
    for i,d in enumerate(curve.data.splines[0].bezier_points):
        # Multply cooridnate by matrix world to make global coordinate. Don't reverse order, it's linear algebla's multipy!
        coord = curve_matrix_world * d.co
        if i == 0:
            vert_tip_point = coord
        else:
            # Switch max or min comperarison
            if maxmin == 'max':
                if vert_tip_point[coord_index] < coord[coord_index]:
                    vert_tip_point = coord
            elif maxmin == 'min':
                if vert_tip_point[coord_index] > coord[coord_index]:
                    vert_tip_point = coord
            else:
                if vert_tip_point[coord_index] < coord[coord_index]:
                    vert_tip_point = coord
    return vert_tip_point

# Execute.
changeMultipleCurveOrigin(xyz='x', maxmin='max')

Leave a Reply