====== UVDistribute - Vertex Distribute ====== As of 2/7/2022, (see other page with better working code) this works as a script run in a Blender Text window, but isn't completed into a full add on. This allows you to select 3 or more Vertexes, select one point as the Active vertex, and they will be placed into alignment and distributed, using the farthest vertex as one anchor, and the Active vertex to be the other. The mode set to OBJECT then to EDIT should not be necessary, but without it, the change is not visible within the 3D View window. Later I may be able to fix this. To do this quickly, I found a copy of articles: one to determine the Active vertex, and one to determine the selected Vertexes. There probably is an easier way. But this does work. This code is contained within my file "reflexPortExtension.blend". import bpy import bmesh import math mode = bpy.context.active_object.mode bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') ob = bpy.context.object me = ob.data bm = bmesh.new() bm.from_mesh(me) def bmesh_vert_active(bm): if bm.select_history: elem = bm.select_history[-1] if isinstance(elem, bmesh.types.BMVert): return elem return None def distance_between_vertexes(vert1, vert2): myDistance = 0 for i in range(3): myDistance += (vert1.co[i] - vert2.co[i]) ** 2 return math.sqrt(myDistance) def vertsAreEqual(vert1, vert2): if (vert1 == None or vert2 == None): return False for i in range(3): if abs(vert1.co[i] - vert2.co[i]) > .00001: # print("out of range: ", i, vert1.co[i], vert2.co[i]) return False return True # For now, we'll do this the simple way. We can find the "Active" vertex with the method # "bmesh_vert_active(bm)". Then we'll iterate and find the farthest vertex away. Then # We'll distribute between these two points. def main(): activeVertex = bmesh_vert_active(bm) if (activeVertex == None): print("Active Vertex must be selected, usually the extreme left one.") return # bpy.ops.object.mode_set(mode='OBJECT') # bpy.ops.object.mode_set(mode='EDIT') # bpy.ops.object.mode_set(mode='EDIT') # we need to switch from Edit mode to Object mode so the selection gets updated # selectedVerts = [v for v in bpy.context.active_object.data.vertices if v.select] selectedVerts = [v for v in bm.verts if v.select] for v in selectedVerts: print("Selected vert: ", v.co) if (len(selectedVerts) < 3): print ("Requires 3 or more vertices to operate. Found: ", len(selectedVerts)) else: print ("\nStart") print("Active vertex coordinates: ", activeVertex.co) # Find farthest vertex from the Active vertex oppositeVertex = None oppositeVertexDistance = 0 for v in selectedVerts: d2verts = distance_between_vertexes(activeVertex, v) if d2verts > oppositeVertexDistance: oppositeVertex = v oppositeVertexDistance = d2verts # I have the oppositeVertex now print("oppositeVertex is: ", oppositeVertex.co) # Calculate amounts to change changeAmount = [0,0,0] for i in range(3): changeAmount[i] = oppositeVertex.co[i] - activeVertex.co[i] print("changeAmount: ", changeAmount) # Now we can change the vertex(s) in between the outer 2 vertexes # Remove activeVertex and oppositeVertex. Have to use this # syntax because activeVertex is a BMVert print("length of selectedVerts before removing 2 maxes", len(selectedVerts)) middleVerts = [] for v in selectedVerts: if vertsAreEqual(activeVertex, v) or vertsAreEqual(oppositeVertex, v): pass else: # Append a tuple middleVerts.append((distance_between_vertexes(activeVertex,v), v)) print("length of middleVerts after removing 2 maxes", len(middleVerts)) # A function that returns the 'year' value: for mvTuple in middleVerts: print("middleVert Pre: ", mvTuple[1].co) # Index is used to calculate distributed new distance index = 0 for mvTuple in sorted(middleVerts): for xyz in range(3): # Distance between activeVertex and this middleVert mvTuple[1].co[xyz] = activeVertex.co[xyz] + changeAmount[xyz]*(1+index)/(len(middleVerts)+1) index = index + 1 print("Done.") for mvTuple in middleVerts: print("middleVert Post: ", mvTuple[1].co) bpy.ops.object.mode_set(mode='OBJECT') bm.to_mesh(me) bm.free() bpy.ops.object.mode_set(mode=mode) main() #