将x点均匀分布在一个圆内
Uniformly distribute x points inside a circle
我想在一个圆圈内均匀分布一组预定的点。通过均匀分布,我的意思是它们彼此之间的距离应该相等(因此随机方法不起作用)。我尝试了六边形方法,但一直无法到达最外半径。
我目前的方法是嵌套 for 循环,其中每次外部迭代都会减少半径和点数,并且每个内部循环会在新半径上均匀地丢弃点。本质上,它是一堆嵌套的圆圈。不幸的是,这远非平衡。有关如何正确执行此操作的任何提示?
区域内均匀分布和边界上均匀分布的目标冲突;任何解决方案都是两者之间的妥协。我用一个附加参数 alpha
扩充了 sunflower seed arrangement,它表示人们对边界均匀度的关心程度。
alpha=0
给出了典型的向日葵排列,边界呈锯齿状:
使用alpha=2
边界更平滑:
(进一步增加 alpha 是有问题的:边界上的点太多)。
算法放置n
个点,其中第k
个点放置在距离边界sqrt(k-1/2)
处(索引以k=1
开头),并且极角 2*pi*k/phi^2
其中 phi
是黄金比例。例外:最后 alpha*sqrt(n)
个点放在圆的外边界上,其他点的极半径被缩放以说明这一点。极半径的计算是在函数 radius
.
中完成的
编码在MATLAB.
function sunflower(n, alpha) % example: n=500, alpha=2
clf
hold on
b = round(alpha*sqrt(n)); % number of boundary points
phi = (sqrt(5)+1)/2; % golden ratio
for k=1:n
r = radius(k,n,b);
theta = 2*pi*k/phi^2;
plot(r*cos(theta), r*sin(theta), 'r*');
end
end
function r = radius(k,n,b)
if k>n-b
r = 1; % put on the boundary
else
r = sqrt(k-1/2)/sqrt(n-(b+1)/2); % apply square root
end
end
偶然发现了这个问题和 (所以所有的信任都归功于 user3717023 和 Matt)。
只需在此处将我的翻译添加到 R 中,以防其他人需要:)
library(tibble)
library(dplyr)
library(ggplot2)
sunflower <- function(n, alpha = 2, geometry = c('planar','geodesic')) {
b <- round(alpha*sqrt(n)) # number of boundary points
phi <- (sqrt(5)+1)/2 # golden ratio
r <- radius(1:n,n,b)
theta <- 1:n * ifelse(geometry[1] == 'geodesic', 360*phi, 2*pi/phi^2)
tibble(
x = r*cos(theta),
y = r*sin(theta)
)
}
radius <- function(k,n,b) {
ifelse(
k > n-b,
1,
sqrt(k-1/2)/sqrt(n-(b+1)/2)
)
}
# example:
sunflower(500, 2, 'planar') %>%
ggplot(aes(x,y)) +
geom_point()
不妨在我的 Python 翻译上加标签。
from math import sqrt, sin, cos, pi
phi = (1 + sqrt(5)) / 2 # golden ratio
def sunflower(n, alpha=0, geodesic=False):
points = []
angle_stride = 360 * phi if geodesic else 2 * pi / phi ** 2
b = round(alpha * sqrt(n)) # number of boundary points
for k in range(1, n + 1):
r = radius(k, n, b)
theta = k * angle_stride
points.append((r * cos(theta), r * sin(theta)))
return points
def radius(k, n, b):
if k > n - b:
return 1.0
else:
return sqrt(k - 0.5) / sqrt(n - (b + 1) / 2)
# example
if __name__ == '__main__':
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
points = sunflower(500, alpha=2, geodesic=False)
xs = [point[0] for point in points]
ys = [point[1] for point in points]
ax.scatter(xs, ys)
ax.set_aspect('equal') # display as square plot with equal axes
plt.show()
建立在 @OlivelsAWord 之上,这是一个使用 numpy 的 Python 实现:
import numpy as np
import matplotlib.pyplot as plt
def sunflower(n: int, alpha: float) -> np.ndarray:
# Number of points respectively on the boundary and inside the cirlce.
n_exterior = np.round(alpha * np.sqrt(n)).astype(int)
n_interior = n - n_exterior
# Ensure there are still some points in the inside...
if n_interior < 1:
raise RuntimeError(f"Parameter 'alpha' is too large ({alpha}), all "
f"points would end-up on the boundary.")
# Generate the angles. The factor k_theta corresponds to 2*pi/phi^2.
k_theta = np.pi * (3 - np.sqrt(5))
angles = np.linspace(k_theta, k_theta * n, n)
# Generate the radii.
r_interior = np.sqrt(np.linspace(0, 1, n_interior))
r_exterior = np.ones((n_exterior,))
r = np.concatenate((r_interior, r_exterior))
# Return Cartesian coordinates from polar ones.
return r * np.stack((np.cos(angles), np.sin(angles)))
# NOTE: say the returned array is called s. The layout is such that s[0,:]
# contains X values and s[1,:] contains Y values. Change the above to
# return r.reshape(n, 1) * np.stack((np.cos(angles), np.sin(angles)), axis=1)
# if you want s[:,0] and s[:,1] to contain X and Y values instead.
if __name__ == '__main__':
fig, ax = plt.subplots()
# Let's plot three sunflowers with different values of alpha!
for alpha in (0, 1, 2):
s = sunflower(500, alpha)
# NOTE: the 'alpha=0.5' parameter is to control transparency, it does
# not have anything to do with the alpha used in 'sunflower' ;)
ax.scatter(s[0], s[1], alpha=0.5, label=f"alpha={alpha}")
# Display as square plot with equal axes and add a legend. Then show the result :)
ax.set_aspect('equal')
ax.legend()
plt.show()
我想在一个圆圈内均匀分布一组预定的点。通过均匀分布,我的意思是它们彼此之间的距离应该相等(因此随机方法不起作用)。我尝试了六边形方法,但一直无法到达最外半径。
我目前的方法是嵌套 for 循环,其中每次外部迭代都会减少半径和点数,并且每个内部循环会在新半径上均匀地丢弃点。本质上,它是一堆嵌套的圆圈。不幸的是,这远非平衡。有关如何正确执行此操作的任何提示?
区域内均匀分布和边界上均匀分布的目标冲突;任何解决方案都是两者之间的妥协。我用一个附加参数 alpha
扩充了 sunflower seed arrangement,它表示人们对边界均匀度的关心程度。
alpha=0
给出了典型的向日葵排列,边界呈锯齿状:
使用alpha=2
边界更平滑:
(进一步增加 alpha 是有问题的:边界上的点太多)。
算法放置n
个点,其中第k
个点放置在距离边界sqrt(k-1/2)
处(索引以k=1
开头),并且极角 2*pi*k/phi^2
其中 phi
是黄金比例。例外:最后 alpha*sqrt(n)
个点放在圆的外边界上,其他点的极半径被缩放以说明这一点。极半径的计算是在函数 radius
.
编码在MATLAB.
function sunflower(n, alpha) % example: n=500, alpha=2
clf
hold on
b = round(alpha*sqrt(n)); % number of boundary points
phi = (sqrt(5)+1)/2; % golden ratio
for k=1:n
r = radius(k,n,b);
theta = 2*pi*k/phi^2;
plot(r*cos(theta), r*sin(theta), 'r*');
end
end
function r = radius(k,n,b)
if k>n-b
r = 1; % put on the boundary
else
r = sqrt(k-1/2)/sqrt(n-(b+1)/2); % apply square root
end
end
偶然发现了这个问题和
只需在此处将我的翻译添加到 R 中,以防其他人需要:)
library(tibble)
library(dplyr)
library(ggplot2)
sunflower <- function(n, alpha = 2, geometry = c('planar','geodesic')) {
b <- round(alpha*sqrt(n)) # number of boundary points
phi <- (sqrt(5)+1)/2 # golden ratio
r <- radius(1:n,n,b)
theta <- 1:n * ifelse(geometry[1] == 'geodesic', 360*phi, 2*pi/phi^2)
tibble(
x = r*cos(theta),
y = r*sin(theta)
)
}
radius <- function(k,n,b) {
ifelse(
k > n-b,
1,
sqrt(k-1/2)/sqrt(n-(b+1)/2)
)
}
# example:
sunflower(500, 2, 'planar') %>%
ggplot(aes(x,y)) +
geom_point()
不妨在我的 Python 翻译上加标签。
from math import sqrt, sin, cos, pi
phi = (1 + sqrt(5)) / 2 # golden ratio
def sunflower(n, alpha=0, geodesic=False):
points = []
angle_stride = 360 * phi if geodesic else 2 * pi / phi ** 2
b = round(alpha * sqrt(n)) # number of boundary points
for k in range(1, n + 1):
r = radius(k, n, b)
theta = k * angle_stride
points.append((r * cos(theta), r * sin(theta)))
return points
def radius(k, n, b):
if k > n - b:
return 1.0
else:
return sqrt(k - 0.5) / sqrt(n - (b + 1) / 2)
# example
if __name__ == '__main__':
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
points = sunflower(500, alpha=2, geodesic=False)
xs = [point[0] for point in points]
ys = [point[1] for point in points]
ax.scatter(xs, ys)
ax.set_aspect('equal') # display as square plot with equal axes
plt.show()
建立在 @OlivelsAWord 之上,这是一个使用 numpy 的 Python 实现:
import numpy as np
import matplotlib.pyplot as plt
def sunflower(n: int, alpha: float) -> np.ndarray:
# Number of points respectively on the boundary and inside the cirlce.
n_exterior = np.round(alpha * np.sqrt(n)).astype(int)
n_interior = n - n_exterior
# Ensure there are still some points in the inside...
if n_interior < 1:
raise RuntimeError(f"Parameter 'alpha' is too large ({alpha}), all "
f"points would end-up on the boundary.")
# Generate the angles. The factor k_theta corresponds to 2*pi/phi^2.
k_theta = np.pi * (3 - np.sqrt(5))
angles = np.linspace(k_theta, k_theta * n, n)
# Generate the radii.
r_interior = np.sqrt(np.linspace(0, 1, n_interior))
r_exterior = np.ones((n_exterior,))
r = np.concatenate((r_interior, r_exterior))
# Return Cartesian coordinates from polar ones.
return r * np.stack((np.cos(angles), np.sin(angles)))
# NOTE: say the returned array is called s. The layout is such that s[0,:]
# contains X values and s[1,:] contains Y values. Change the above to
# return r.reshape(n, 1) * np.stack((np.cos(angles), np.sin(angles)), axis=1)
# if you want s[:,0] and s[:,1] to contain X and Y values instead.
if __name__ == '__main__':
fig, ax = plt.subplots()
# Let's plot three sunflowers with different values of alpha!
for alpha in (0, 1, 2):
s = sunflower(500, alpha)
# NOTE: the 'alpha=0.5' parameter is to control transparency, it does
# not have anything to do with the alpha used in 'sunflower' ;)
ax.scatter(s[0], s[1], alpha=0.5, label=f"alpha={alpha}")
# Display as square plot with equal axes and add a legend. Then show the result :)
ax.set_aspect('equal')
ax.legend()
plt.show()