Aligning vertices to arch with center in 3D cursor position

I’ve tried to do perfect circled arch, around 3d cursor, with already existing vertices, and found, that it’s not so easy to align vertices not in the sphere or circle, but just a segment of it.

So I’ve created my own script to fix that.

import bpy

def calc_center(selectedVerts):
    median_point = bpy.context.scene.cursor.location
    #median_point.y = selectedVerts[0].co.y
    return median_point

def calc_distance(center, vertex):
    return (vertex.co - center).length

def calc_new_position(center, vertex, length):
    vec_normalized = vertex.co-center
    vec_normalized.normalize()
    return center + vec_normalized * length

def set_new_position(vertex, position):
    print (vertex.co - position)
    vertex.co = position

def make_arch():
    mode = bpy.context.active_object.mode
    bpy.ops.object.mode_set(mode='OBJECT')
    selectedVerts = [v for v in bpy.context.active_object.data.vertices if v.select]
    print("selected {} vertexes", len(selectedVerts))
    median_point = calc_center(selectedVerts)
    length = map(lambda x: calc_distance(median_point, x), selectedVerts)
    sum_length = sum(length)
    median_length = sum_length/len(selectedVerts)
    for v in  selectedVerts:
        set_new_position(v, calc_new_position(median_point, v, median_length))
    bpy.ops.object.mode_set(mode=mode)

By calling make_arch() you can line up to arc org circle segment selected vertices. So it’s easy to adjust them to circle by using array modifier and so on. Position of 3D cursor can affect strongly on resulting position, so be careful with lining it in very begining.

1 Like

mesh_aligment.py (7.0 KB)
So I’ve created separate addon with “Make arch” and “Make line” function which are available from right mouse click in “Edit” mode.
Lining up vertices in line and in arch now became mush easier.
How it works


Feel free to use addon and contact me for error and new functions.

1 Like

New version of script: removed all unnecessary stuff
Only “Make arch” button
vertex_to_arch.py (3.0 KB)

Looks cool! :slight_smile:

I have a strong use case for this addon, where I in some occasions I use the Spin tool and create such arcs. However for editing any existing, it might be a huge pain. I might create the arcs from scratch in order to get precision. In this addon perhaps it might be feasible to save existing arcs.

I tried some changes, first is to make it run continuously with the help of def draw, then the rest of the properties are only extra ideas to be considered, if any of them is useful.

    bl_idname = "mesh.make_arch"
    bl_label = "Make Arch"
    bl_description = "Shape selected vertices into an arch shape with center in 3d cursor"
    bl_options = {'REGISTER', 'UNDO'}
    
    info = {
        'dist-name':'Distance Offset',
        'dist-desc':'Apply extra distance from cursor',
        'spread-name':"Spread",
        'spread-desc':'Add extra position spread of vertices around the cursor',
        'freeze-name':"Freeze Endpoints",
        'freeze-desc':'Freeze position of start/end vertices in selection',        
        'blend-name':"Blend Original",
        'blend-desc':'Amount of blending between new and original positions',        
    }
    
    distance: bpy.props.FloatProperty(name=info['dist-name'], description=info['dist-desc'], min=-1.0, max=1.0, default=0.0)
    spread : bpy.props.FloatProperty(name=info['spread-name'], description=info['spread-desc'], min=-1.0, max=1.0, default=0.0)
    freeze : bpy.props.BoolProperty(name=info['freeze-name'], description=info['freeze-desc'], default=True)
    blend : bpy.props.FloatProperty(name=info['blend-name'], description=info['blend-desc'], min=0.0, max=1.0, default=1.0)

    @classmethod
    def poll(cls, context):
        ob = context.active_object
        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')

    def invoke(self, context, event):
        # load custom settings
        # settings_load(self)
        # return self.execute(context)
        wm = context.window_manager # show operator dialog
        return wm.invoke_props_dialog(self)
    
    def draw(self, context):
        layout = self.layout
        col = layout.column()

        col.label(text='Cursor Location')
        col.prop(context.scene.cursor, 'location')
        
        row = col.row()
        row.prop(self, 'distance')
        row.prop(self, 'spread')
        
        row = col.row()
        row.prop(self, 'freeze')
        row.prop(self, 'blend')   

I thought about making changes, like manually set up the arch radius, and maybe add some spacing between vertices, like circle in LoopTools.

Cool addon, keep up the good work. :slight_smile:

Addon now has it’s own page on blender market

1 Like