假设我有一个圆和一组数字2、3、5、7、11。
我想将圆分成相当于这些数字的部分(就像饼图一样),但形成类似于蜂窝状的结构。
这个是可能的吗?对于只完成了一些基本饼图渲染的人来说,这是否过于困难?
这是我快速浏览后对此的看法。
一个通用解决方案,假设有 n
个具有 k
个顶点/边的多边形,将取决于解决 n
个方程的解决方案,其中每个方程的变量不超过 2nk
(但恰好有 2k
个非零变量)。每个多边形方程中的变量都是相同的 x_1,x_2,x_3... x_nk
和 y_1,y_2,y_3... y_nk
变量。每个多边形方程中恰好有四个 x_1,x_2,x_3... x_nk
具有非零系数,每个多边形方程中恰好有四个 y_1,y_2,y_3... y_nk
具有非零系数。根据父形状,x_i
和 y_i
的边界条件不同。为了简单起见,我们假设形状是圆形。边界条件是:(x_i)^2 + (y_i)^2 <= r^2
注意:我说的不超过2nk
,因为我不确定下限,但知道它不会超过2nk
。这是由于多边形作为要求共享顶点。
这些方程式是一组明确的、但变量有界的积分,表示每个多边形的面积,其中第 i 个多边形的面积相等:
A_i = pi*r^2/S_i
其中r
是父圆的半径,S_i
是分配给多边形的数字,就像您的图表中一样。
在多边形方程式中,四个单独的(x_j,y_j)
对,两者都具有非零系数,将产生多边形的顶点。
这可能证明是相当困难的。
边界是从一开始就固定的,还是可以稍微变形一下?
如果我要解决这个问题,我会按照面积从大到小的顺序进行排序。然后,从最大的区域开始,我会首先生成一个随机凸多边形(顶点沿着圆形),大小符合要求。下一个区域将与第一个区域共享一个边缘,但也是随机和凸的。之后的每个多边形都会从已经存在的多边形中选择一个现有的边缘,并且还会共享任何从那里开始的“凸边缘”(其中“凸边缘”是指如果用于新多边形,则新多边形仍然是凸的边缘)。
通过评估“总边界接近所需边界”的不同潜在多边形位置,您可能可以生成对初始目标的廉价近似。这与词云所做的非常相似:从大到小逐步放置东西,同时尝试填充一个更或多或少封闭的空间。
给定一组 Voronoi 中心(即每个中心的坐标列表),我们可以计算最靠近每个中心的区域:
area[i] = areaClosestTo(i,positions)
假设这些有点不正确,因为我们没有把中心放在正确的位置。因此,我们可以通过比较面积与理想面积来计算当前集合中的误差:
var areaIndexSq = 0;
var desiredAreasMagSq = 0;
for(var i = 0; i < areas.length; ++i) {
var contrib = (areas[i] - desiredAreas[i]);
areaIndexSq += contrib*contrib;
desiredAreasMagSq += desiredAreas[i]*desiredAreas[i];
}
var areaIndex = Math.sqrt(areaIndexSq/desiredAreasMagSq);
这是区域和期望区域之间差向量的向量范数。可以将其视为最小二乘拟合线的好坏程度的一种度量。
我们还想要一些蜂窝状图案,因此我们可以称之为honeycombness(positions)
,并获得整个事物质量的总体度量(这只是一个起点,权重或形式可以随意调整):
var overallMeasure = areaIndex + honeycombnessIndex;
然后我们有一种机制来知道猜测的准确程度,我们可以将其与修改位置的机制相结合;最简单的方法就是向每个中心的x和y坐标添加随机量。或者您可以尝试将每个点移动到面积过高的邻域,远离面积过低的邻域。
这不是一个直接的解决方案,但除了计算每个点最接近的区域之外,它需要很少的数学知识,并且易于理解。困难的部分可能是识别局部极小值并处理它们。
顺便说一句,获取该过程的起始点应该相对容易;饼图切片的质心不应该离真实值太远。
明显的优点是,您可以使用中间计算来动画显示从饼图到Voronoi的转换。