YAF one.
_Also late to the party, cooked a GPU, can report 2.91 runs with a Gforce 220 lol _
For a string of edges can use the method from How can I sort vertex positions sequentially indices in a closed area? to fill the edges. The new face will have edges in its winding order. The new edge to close path is used to set order.
Face edges angle - python
Added a simple UI to also make it "without scripting" 8)_ (Be a quick task re-jigging to use code from @MVB's excellent answer)
To use, select a single vert of the edge string, and the axis to align to. Keeps the selected vert in place.
import bpy
import bmesh
from mathutils import Matrix
from itertools import cycle, islice
def main(op, context, align):
def con_edges(vert):
x, s = set(), set(vert.link_edges)
while s - x: # edges growing
x, s = s, s.union(
e for le in s
for v in le.verts
for e in v.link_edges
if len(v.link_edges) < 3)
return list(x)
ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
av = bm.select_history.active
if not isinstance(av, bmesh.types.BMVert):
op.report({'INFO'}, "Select a vert")
return {'CANCELLED'}
# keep at active vert location.
loc = av.co.copy()
edges = set(bm.edges)
f = bmesh.ops.contextual_create(
bm,
geom=con_edges(av),
)["faces"][0]
# will throw error if cyclic.
new_edge = (set(bm.edges) - edges).pop()
edges = f.edges[:]
for e in bm.edges:
e.select_set(e in edges)
i = edges.index(new_edge) + 1
# direction
if align == 'ENDS':
vec = (new_edge.verts[1].co - new_edge.verts[0].co).normalized()
elif align in 'XYZ':
vec = Matrix.Identity(3)['XYZ'.index(align)]
# edge loop around face
loop = [(v, e, e.calc_length()) for v, e in islice(cycle(zip(f.verts, f.edges)),i, i + len(f.edges) - 1)]
for v0, e, l in loop:
#v0 = f.verts[edges.index(e)]
v1 = e.other_vert(v0)
v1.co = v0.co + l * vec
#remove face link edge & move back so vert "doesn't appear to move"
bm.edges.remove(new_edge)
bm.transform(
Matrix.Translation((loc - av.co))
)
bmesh.update_edit_mesh(me)
return {'FINISHED'}
class StraightenEdgeOperator(bpy.types.Operator):
"""Straighten Edges"""
bl_idname = "mesh.straighten_edges"
bl_label = "Straighten Edges"
bl_options = {'REGISTER', 'UNDO'}
align : bpy.props.EnumProperty(
items=[
('X', 'X Axis', ''),
('Y', 'Y Axis', ''),
('Z', 'Z Axis', ''),
('ENDS', 'Segment Ends', ''),
],
name="Align",
default = 'ENDS',
)
def draw(self, context):
layout = self.layout
layout.prop(self, "align", expand=True)
@classmethod
def poll(cls, context):
return context.edit_object is not None and context.mode.startswith('EDIT_MESH')
def execute(self, context):
return main(self, context, self.align)
def register():
bpy.utils.register_class(StraightenEdgeOperator)
def unregister():
bpy.utils.unregister_class(StraightenEdgeOperator)
if __name__ == "__main__":
register()