# Move points along their own path in python

I have a list of vertices.
I want to move the verts/white squares along their own paths like so:

(Assume the polygon is closed)
How can I do that with python and get a list of shifted vertices back?

• Every time I read this I get more confused. Is setup something akin to this answer blender.stackexchange.com/a/133032/15543 sliding edges (connected vertices?) along a path. Is the goal not to have the icospheres intersect? Sep 6, 2021 at 14:41
• Perhaps OP needs a tool like vertex slide, except in that tool at start a copy of geometry would be made, then converted to a path, then all vertices would be moved towards either of two ends of the path, depending in which way the mouse is moving... Sep 6, 2021 at 14:44
• I completely rewrote the question, hope it's clear now. @Markus von Broady You are right, vertex slide, but verts can travel beyond their adjacent neighbours. Sep 6, 2021 at 15:13
• Ok think I have it. As mentioned, convert a copy to a path and then flatten the edges and feed onto it as in first link commented. See blender.stackexchange.com/questions/214036/… Sep 6, 2021 at 16:51
• Not sure I understand. Flatten the polygon and doing the shifting on a straight line and then transform back? How does transforming back look like in python? Sep 7, 2021 at 7:52

Here is the solution I ended up using. Suggestions welcome.

import bpy
import numpy as np

#assumes closed polygon with vertices in linear order
#creates new objetc with shifted/slid verts
#https://blender.stackexchange.com/questions/191649/how-can-i-sort-vertex-positions-sequentially-indices-in-a-closed-area
def multi_slide_verts(obj, shift_length):

length = len(obj.data.vertices)
coords = np.empty(length*3, dtype=np.float64)
obj.data.vertices.foreach_get('co',coords)
coords.shape = (length, 3)
return coords #numpy array of vert array [[x,y,z],[x,y,z]...]

def write_obj_from_pydata(name, verts, edges=None, close=True):
if edges is None:
# join vertices into one uninterrupted chain of edges.
edges = [[i, i+1] for i in range(len(verts)-1)]
if close:
edges.append([len(verts)-1, 0]) #connect last to first

me = bpy.data.meshes.new(name)
me.from_pydata(verts, edges, [])

obj = bpy.data.objects.new(name, me)

#collect segments, their length and directions in parallel numpy arrays
P2 = np.roll(P1, -1, axis=0)
segs = P2-P1
dists = np.linalg.norm(P2-P1, axis=1)+0.000000001
dirs = segs/dists[:, np.newaxis]  #.np.new axis to give same shape, https://stackoverflow.com/questions/7140738/numpy-divide-along-axis

shifted_pts = []
for i in range(len(P1)):#iterate over all points

#normal/easiest case, shift point on own segment in segment direction
if dists[i]>=shift_length:#dist is big enough
copy_original_pt = P1[i][:]
shifted_pt = copy_original_pt+(dirs[i]*shift_length)
shifted_pts.append(shifted_pt)

#case where you need to look beyond neighbouring verts for shifting direction/dist
else: #dist is not enough to apply shift, so you need to lookahead and see if next seg dist is enough.
traveled_dist = dists[i]

while traveled_dist < shift:
#check if next segment is enough and note down traveled_dist

#to make lookahead indices stay in range when looking further than last point
rotate_index = (i+lookahead)%len(dists) #rotate i lookahead goes further then last point, cause for now your path is cyclic!
traveled_dist+=dists[rotate_index]

#same for distance to calculate rest amount you didn't travel yet.
shift_rest = shift - (traveled_dist-dists[rotate_index])
copy_original_pt = P1[rotate_index][:]
shifted_pt = copy_original_pt+(dirs[rotate_index]*shift_rest)
shifted_pts.append(shifted_pt)

write_obj_from_pydata('shifted_pts', shifted_pts, edges=None, close=True)

obj = bpy.context.active_object
multi_slide_verts(obj, 9.3)