简体   繁体   中英

generate an ordered zig-zag set of points (path) given bounds, direction, and starting point

say we want to generate a zig-zag set of points as a numpy array like the following image such that the array elements' order is similar to moving on the path:

we are given:

  • The bounds where this path should be in (eg, the above image has x=[-2500:2500], y=[-200, 200])
  • the starting point that defines the order of points in such path (eg, in the blow image it is (2500, 200)
  • teeth direction (eg, the below image is in y) direction, that is why the starting point starts going down in the beginning)
  • the step size between each point (eg, 10)
  • the width of each teeth

What is the simplest way to generate such numpy array? I tried scipy square wave but aside from other required features it only generates the teeth edge points but not all the path in a way that can be shown with scatter plot

在此处输入图像描述

Apologies in advance for ignoring your starting point and teeth direction . I started without considering them and when I was finished and only had to add them I thought that you can very likely do that yourself. I also think there could be a more pretty solution to your x pixel point distance request than just getting a lot of points and filtering them so that is satisfied. Let me know if that's important to you. That aside I think this is a nice solution.

def zig_zag(x_interval,y_interval,tooth_width,step_size):
    #finding the teeth edge points
    x_vals = np.arange(*x_interval,tooth_width)
    idx = np.arange(x_vals.shape[0]*2-1)%4
    mask = ((idx == 0) | (idx == 1))
    
    x = np.empty(mask.shape, dtype='int')
    y = np.empty(mask.shape, dtype='int')
    
    x[mask] = x_vals
    x[~mask] = x_vals[1:]
    y[mask] = y_interval[1]
    y[~mask] = y_interval[0]
    
    #interpolating between the teeth edge points and get way to many points
    tck, u = interpolate.splprep([x,y],s=0,k=1)
    x, y = interpolate.splev(np.linspace(0, 1, 10**6), tck)
    
    #pick the perfect points
    arr = np.array(tuple(filter_points(x,y,step_size)))
    x = arr[:,0]
    y = arr[:,1]
    
    #plot it
    ax = plt.gca()
    ax.scatter(x, y)
    ax.set_aspect('equal')
    plt.savefig("teeth.png")
    
def filter_points(x,y,step_size):
    found = x[0],y[0]
    step_size **= 2
    yield found
    for x,y in zip(x,y):
        if (found[0]-x)**2+(found[1]-y)**2 >= step_size:
            found = x,y
            yield found
        
        
zig_zag((0,700),(0, 200),100,5)

牙齿

I have so far the following answer:

from copy import copy
import numpy as np


class ZigZagTraj(object):
    def __init__(self, xs, ys, xe, ye, tooth_direction='x', tooth_width=0.2, step=0.05):
        self.xs, self.ys, self.xe, self.ye = xs, ys, xe, ye
        self.tooth_direction = tooth_direction
        self.tooth_width = tooth_width
        self.step = step
        
        self.bounds = {'x': {'lb':None, 'ub':None },
                      'y': {'lb':None, 'ub':None }}
        if xe - xs > 0:
            self.bounds['x']['ub'] = self.xe
            self.bounds['x']['lb'] = self.xs
        else:
            self.bounds['x']['ub'] = self.xs
            self.bounds['x']['lb'] = self.xe
        if ye - ys > 0:
            self.bounds['y']['ub'] = self.ye
            self.bounds['y']['lb'] = self.ys
        else:
            self.bounds['y']['ub'] = self.ys
            self.bounds['y']['lb'] = self.ye

        self.x_increment_sign =  np.sign(self.xe - self.xs)
        self.y_increment_sign =  np.sign(self.ye - self.ys)
        
        self.curr_direction = tooth_direction
        self.curr_tooth_width = 0

        self.traj = []
        self.traj.append([xs, ys])

    def change_curr_direction(self):
        if self.curr_direction == 'x':
            self.curr_direction = 'y'
        elif self.curr_direction == 'y':
            self.curr_direction = 'x'
        return self.curr_direction

    def in_bound(self,new_point):
        return self.in_x_bound(new_point) and self.in_y_bound(new_point)

    def in_x_bound(self,new_point):
        return self.bounds['x']['lb'] <= new_point[0] <= self.bounds['x']['ub']

    def in_y_bound(self, new_point):
        return self.bounds['y']['lb'] <= new_point[1] <= self.bounds['y']['ub']
    
    def generate_trajectory(self):
        self.tooth_direction = self.tooth_direction 
        curr_tooth_width = 0
        traj = []
        traj.append([self.xs, self.ys])
        #print('self.x_increment_sign',self.x_increment_sign, 'self.x_increment_sign',self.x_increment_sign)
        while True:
            #print(traj[-1], 'for direction', self.curr_direction)
            new_point = copy(traj[-1])
            if self.curr_direction == 'x':
                new_point[0] += self.step * self.x_increment_sign
            elif self.curr_direction == 'y':
                new_point[1] += self.step * self.y_increment_sign

            if self.curr_direction != self.tooth_direction:  # we're on a tooth
                curr_tooth_width += self.step
                #print('checking if tooth width is reached', curr_tooth_width, tooth_width)
                if curr_tooth_width >= self.tooth_width:
                    if self.tooth_direction == 'x':  # along the tooth direction we should now run backwards
                        self.x_increment_sign *= -1
                    else:
                        self.y_increment_sign *= -1
                    curr_tooth_width = 0
                    self.change_curr_direction()
                    #print('not append(tooth width). moving to direction: ', self.curr_direction)
                    continue
            elif not self.in_bound(new_point): # we're on tooth length ( out of bound for lenght direction)
                self.change_curr_direction()
                #print('not append(tooth length)')
                continue

            #print('checking if we should append')
            #print('new point', new_point)
            #print(self.in_x_bound(new_point), self.in_y_bound(new_point))
            if not self.in_x_bound(new_point) or not self.in_y_bound(new_point):
                #print('not append(break)')
                break
            new_point[0] = round(new_point[0], 3)
            new_point[1] = round(new_point[1], 3)
            traj.append(new_point)
        return np.array(traj)

with the following result:

[![zig = ZigZagTraj( 1.2, 1.2, 0, 0, tooth_direction='x', tooth_width=0.2, step=0.05)
traj = zig.generate_trajectory()
fig, ax = plt.subplots()
ax.scatter(traj\[:, 0\], traj\[:, 1\])
plt.show()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM