简体   繁体   中英

How to create an equally spaced grid of a diamond shaped area

I am trying to construct an equally spaced grid of points within an area that resembles an irregular diamond or rhombus. The border of this diamond is given by the following lists:

xlim = list(np.linspace(0,1/4*(np.sqrt(3)+1), num=56)) + list(np.linspace(1/4*(np.sqrt(3)+1),np.sqrt(3)/2, num=20)) + \
list(np.linspace(np.sqrt(3)/2, 1/4*(np.sqrt(3)+1), num=20)) + list(np.linspace( 1/4*(np.sqrt(3)+1),0, num=56))

ylim = list(np.linspace(0, np.sqrt(3)/4, num=56)) + list(np.linspace(np.sqrt(3)/4,0, num=20)) +\
list(np.linspace(0, -np.sqrt(3)/4,num=20)) + list(np.linspace(-np.sqrt(3)/4,0, num=56))

Then I created border list that holds a tuple with the coordinates of the perimeter:

border = []

for i in range(len(xlim)):
    border.append((xlim[i],ylim[i]))

You can check that by plotting the xlim and ylim arrays we get the polygon shape below这里 .

I am trying to create an equally spaced grid inside of this polygon and including the borders and this is what I have done so far:


width = np.linspace(0,np.sqrt(3)/2,20)
kgrid = []

for i in range(0,len(width)):
    for j in range(0,len(width)):
        
        x = width[i]
        y = width[j]
        
        if (x,y) in border:
            
            continue
            
        else:
            kgrid.append([x,y])

Kgrid would be my resulting list with the tuples of the x and y coordinates of the equally spaced dots, however, I get the entire square of length and width sqrt(3)/2 instead of the grid within the diamond only.

I am not entirely sure what I am doing wrong so any instruction or tips towards the right direction is going to be helpful for me.

EDIT:

Testing out the distance between consecutive intersections or points of Mozway's grid.

Having saved the points in lists:

for x, y in zip(X, Y):
    xs = np.linspace(*x,n1)
    ys = np.linspace(*y,n1)
    
    kx.append(xs)
    ky.append(ys)
        
    ax.plot(xs, ys, c='k', ls='', marker='.')
    plt.gca().set_aspect('equal')

Herein kx and ky, I can flatten these two to obtain the coordinates of the grid:

kx = np.array(kx).flatten()
ky = np.array(ky).flatten()

When I test the distance between (kx,ky) pairs (ie kx[0],ky[0] and kx 1 , ky 1 ), when the loop approaches the length of (kx) in iterations,the distance between consecutive points (kx,ky) decreases. See here:

dist = []

for i in range(len(kx)-1):
    
    dist.append(np.sqrt((kx[i]-kx[i+1])**2 + (ky[i]-ky[i+1])**2))

Checking the output of ``dist``` I see that for several iterations I get the approximate same distance but throughout the whole lifetime of the loop this is not the case.

Check output for example.

...0.049274092704200266,
 0.049274092704200266,
 0.04927409270420008,
 0.04927409270420032,
 0.049274092704200266,
 0.04927409270420008,
 0.04927409270420021,
 0.04927409270420008,
 2.045339229827365,
 0.04868407742479125,
 0.04868407742479123,
 0.04868407742479123,
 0.04868407742479125,
 0.04868407742479125,
 0.048684077424791194,
 0.04868407742479126,
 0.04868407742479124,
 0.04868407742479124,
 0.048684077424791215,
 0.0486840774247913,
 0.048684077424791104,
 0.048684077424791306,
 0.04868407742479132,
 0.0486840774247913,
 0.048684077424791104,
....

EDIT 2:

A reference picture for Mozway. Shown in the figure below is half the area of the grid. The equally spaced points would be the blue ones, but I should be able to control how many points are inside of the grid, and thus how sparse the points are.

[![the figure below][2]][2]

IIUC you want to get a grid of lines joining the opposite sides.

For this you can keep the coordinates of the four sides separate and join the evenly spaced points using loops:

n1 = 10 # number of blue -> green linew
n2 = 20 # number of orange -> red lines

faces = [ # blue
         (np.linspace(0,1/4*(np.sqrt(3)+1), num=n1), np.linspace(0, np.sqrt(3)/4, num=n1)),
          # orange
         (np.linspace(1/4*(np.sqrt(3)+1),np.sqrt(3)/2, num=n2), np.linspace(np.sqrt(3)/4,0, num=n2)),
          # green
         (np.linspace(np.sqrt(3)/2, 1/4*(np.sqrt(3)+1), num=n1), np.linspace(0, -np.sqrt(3)/4,num=n1)),
          # red
         (np.linspace( 1/4*(np.sqrt(3)+1),0, num=n2), np.linspace(-np.sqrt(3)/4,0, num=n2)),
        ]

ax = plt.subplot()
for face in faces:
    ax.plot(face[0], face[1])

for i in range(2):
    x1 = faces[i][0]
    x2 = faces[i+2][0][::-1]
    y1 = faces[i][1]
    y2 = faces[i+2][1][::-1]
    
    X = list(zip(x1, x2))
    Y = list(zip(y1, y2))
    
    for x, y in zip(X, Y):
        ax.plot(x, y, c='k', ls=':')

钻石网格

same with points:

n1 = 10
n2 = 20

faces = [(np.linspace(0,1/4*(np.sqrt(3)+1), num=n1), np.linspace(0, np.sqrt(3)/4, num=n1)),
         (np.linspace(1/4*(np.sqrt(3)+1),np.sqrt(3)/2, num=n2), np.linspace(np.sqrt(3)/4,0, num=n2)),
         (np.linspace(np.sqrt(3)/2, 1/4*(np.sqrt(3)+1), num=n1), np.linspace(0, -np.sqrt(3)/4,num=n1)),
         (np.linspace( 1/4*(np.sqrt(3)+1),0, num=n2), np.linspace(-np.sqrt(3)/4,0, num=n2)),
        ]

ax = plt.subplot()
for face in faces:
    ax.plot(face[0], face[1])

i = 0
    
x1 = faces[i][0]
x2 = faces[i+2][0][::-1]
y1 = faces[i][1]
y2 = faces[i+2][1][::-1]
    
X = list(zip(x1, x2))
Y = list(zip(y1, y2))

for x, y in zip(X, Y):
    xs = np.linspace(*x, num=20)
    ys = np.linspace(*y, num=20)
    ax.plot(xs, ys, c='k', ls='', marker='.')

网格交叉点

same with n1 = 20 and n2 = 20 :

十字路口,20x20

My approach would be to get a gird covering your diamond and then remove the points outside of it.

First I put your points in an array and calculate the center

import numpy as np
import matplotlib.pyplot as plt
import functools

arr = np.array([[ 0.       ,  0.       ],
                [ 0.6830127, -0.4330127],
                [ 0.8660254,  0.       ],
                [ 0.6830127,  0.4330127],
                [ 0.       ,  0.       ]
               ])

center = np.mean(arr, axis=0)

Now I create a grid covering the diamond.

x = np.arange(min(arr[:,0]), max(arr[:,0])+0.04, 0.04)
y = np.arange(min(arr[:,1]), max(arr[:,1])+0.04, 0.04)
a,b = np.meshgrid(x,y)
points = np.stack([a.reshape(-1),b.reshape(-1)]).T

And finally I filter by being inside your diamond using the typical numpy approach of masking. That means I first create a true/false array being true where the points are that I want to keep and false otherwise and then apply it to the points.

def normal(a,b):
    v = b-a
    n = np.array([v[1], -v[0]])
    #normal needs to point out
    if (center-a)@n > 0:
         n *= -1
    return n

mask = functools.reduce(np.logical_and, [((points-a)@normal(a, b)) < 0 for a,b in zip(arr[:-1], arr[1:])])
plt.plot(arr[:,0],arr[:,1])
plt.gca().set_aspect('equal')
plt.scatter(points[mask][:,0], points[mask][:,1])

钻石腰带

Obviously your points are given as points[mask] .

Calculate difference between points to check if distance is constant

Well just shift the points by 1 and do minus like this:

points[mask][1:]-points[mask][:-1]

and you'll get

array([[ 0.04,  0.  ],
       [-0.12,  0.04],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [-0.16,  0.04],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [-0.28,  0.04],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [-0.32,  0.04],
...
       [-0.12,  0.04],
       [ 0.04,  0.  ],
       [ 0.04,  0.  ],
       [ 0.  ,  0.04]])

It starts from the bottom left goes 0.04 to the right (in x direction), then goes up by 0.04 (in y direction) and 0.12 (3 steps of 0.04) to the left (in negative x direction) and so on.

This is btw. not very surprising since I chose it that way in this line:

x = np.arange(min(arr[:,0]), max(arr[:,0])+0.04, 0.04)

I posted the differences since that seemed more understandable. But you could get the actual distances with

np.linalg.norm(points[mask][1:]-points[mask][:-1], axis=1)

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