“最新代码”-http://jsfiddle.net/NYEaX/336/(注意:仅是概念性的,高度非优化!)
我不确定 d3 是否可以以某种方式自动执行此操作,但您总是可以找出 x 和 y 自己用一些数学计算点的位置:
一种方法是随机放置每个点,直到它正确放置。这绝对不是最快的方法,但如果你没有太多的点要放置,它可能仍然足够好。
假设您的最小圆的半径为 rs 和中心点 (xs sub>, ys) 和你的中间圆圈 rm 和 (xm, ym) 和你最大的圆圈 rl 和 (xl, yl),然后你可以检查一个点是哪个圆圈或者通过比较它从圆的中心点到该圆的半径的距离,不会落入:
例如,如果您想在中间的圆圈中放置一个点:
- 选择一个随机位置(x、y),使其可以落在该圆圈中的任何位置:
-
xm - rm ≤ x ≤ xm + rm
-
ym - rm ≤ y ≤ ym + rm
- 确保它确实在圆圈内:
- 检查 (x - xm)2 + (y - ym)2 ≤ rm2
- 如果不是这种情况,请重新开始并选择不同的 (x, y)
- 确保它不在小圆圈内:
- 检查 (x - xs)2 + (y - ys)2 > rs2
- 如果不是这种情况,请重新开始并选择不同的 (x, y)
现在您有一些随机点位于中间圆圈内,但不是小圆圈。将一个放入更大的圆圈中的工作方式相同(只需替换 xm、ym sub> 和 rm 和 xl、yl 和 rl 以及 xs, ys 和 rs 和 xm、ym 和 rm i>)。要将一个点放入最小的圆圈中,您只需要检查第一个条件(与 xm, y m 和 rm 替换为 x s、ys 和 rs)。
现在,您可以停在这里(但取决于您的点密度,这可能不是最漂亮的图片),或者您可以尝试将点之间的间距设置得更好一些。一种方法如下:
- 循环遍历所有点(x1、y1) ... (xn, yn)
- 计算每个点到其他点的距离
- 找到最接近的两个
- 在这两个中,找出哪个更接近它的邻居
- 去掉这个点,再用上面介绍的方法随机放置
- 要么重复此操作数次,要么直到任意两个点之间的距离达到可接受的最小距离(我会尝试最有效的方法)
通过调整上面的两个检查方程,您还可以通过替换 rm 在圆的边界周围添加一些圆点将避免的间隙2 与 (rm - d)2 和 rs2 与 ( rs + d)2。
肯定有很多方法可以优化这个简单的方法:例如,您可以选择您的初始 (x、y) 在极坐标中的位置,通过选择 r 和 α 然后计算 x 和 y 以确保您永远不会选择不在您想要的圆圈内的点。只需确保从正确加权的分布中选择 r,以便 x 和 y 结果是均匀分布的。此外,您可以在放置点时立即检查从新放置的点到其所有邻居的距离,而不是在最后的第二步中。例如,为每个点找到 10 个地点,然后始终从与最近邻点距离最大的地点中选择一个。
更新
这就是不用担心点间距的样子:http://jsfiddle.net/NYEaX/328/
实现点放置的相关部分在这里(变量名称已更改为与上面匹配):
function getXCoordinateInCircleSection(i, xm, ym, rm, xs, ys, rs) {
done = false;
while (!done) {
x = getRandomCoordinate(xm-rm, xm+rm);
y = getRandomCoordinate(ym-rm, ym+rm);
done = true;
if ((x-xm)*(x-xm)+(y-ym)*(y-ym) > (rm-10)*(rm-10)) done = false;
if ((x-xs)*(x-xs)+(y-ys)*(y-ys) <= (rs+10)*(rs+10)) done = false;
}
window.ys[i] = y;
return x;
}
function getYCoordinateInCircleSection(i) {
return window.ys[i];
}
并改进点间距:http://jsfiddle.net/NYEaX/329/
(这两个都是基于@TheOldCounty创建的http://jsfiddle.net/NYEaX/326/)