我在尝试绘制饼图时遇到问题。
当然,绘制图表没有问题,问题是图标放置。 理想情况下,图标应放在圆圈上(让我们暂时忘记百分比标签)。
然而,当存在具有较小值的邻居项时,设计显然会中断。
您能推荐一种解决此问题的算法吗?为了简化,作为输入,我们有:
PIE_RADIUS
- 馅饼的外半径。
ICON_RADIUS
- 图标圈的半径
ICON_PLACEMENT_RADIUS
- 理想放置图标中心时圆的半径
NUM_ICONS
- 要放置的图标数量
iconAngles
每个图标的角度,位于其部分的中心
要求的输出:
对于放置在饼图周围的项目,iconAngles
或iconPositions
将图标移出理想圆圈时,可以(0, 0)
。
我知道如何检查两个图标是否重叠。 我们可以认为馅饼的中心位于{{1}}。
(该实现是iOS应用程序的一部分,但我对一般算法感兴趣)。
答案 0 :(得分:1)
第一个天真的算法,我们“推”与其他图标重叠的图标:
FOR iconToPlace in icons do:
isPlaced = false
WHILE(not isPlaced) DO:
isPlaced = true
FOR icon in icons DO:
IF overlap(iconToPlace, icon) AND iconToPlace != icon THEN:
isPlaced = false
push(iconToPlace) // same angle but the icon is now further
BREAK
ENDIF
ENDFOR
ENDWHILE
ENDFOR
使用这个第一个算法,一些图标将从中心进一步比其他图标更远。但它没有通过改变角度来利用可能的地方。通过将其应用于您的第二个设计(具有较小的值),很明显该解决方案将远离理想的解决方案。
第二个不太天真的算法,首先我们为每个图标分配一个新的角度(差值小于DeltaAngleMax),然后我们应用第一个算法:
icons = SORT(icons)
iconsRef = icons
isFinished = false
WHILE(not isFinished) DO:
isFinished = true
FOR i = 0 TO i = NUM_ICONS-1 DO:
IF overlap(icons(i), icons(i+1 % NUM_ICONS))
AND not overlap(icons(i), icons(i-1 % NUM_ICONS)) //seems useless
AND not overlap(icons(i)-DeltaAngle % 360, icons(i-1 % NUM_ICONS))
AND ABS(icons(i)-iconsRef(i)) <= DeltaAngleMax THEN:
//overlap with next icon but not with previous,
//if we decrease angle we still not overlap with previous icon and
//the futur delta angle is less than DeltaAngleMax
//then we can move the icon :
icons(i) = icons(i)-DeltaAngle
isFinished = false
ELSE IF overlap(icons(i), icons(i-1 % NUM_ICONS))
AND not overlap(icons(i), icons(i+1 % NUM_ICONS)) //seems useless
AND not overlap(icons(i)+DeltaAngle % 360, icons(i+1 % NUM_ICONS))
AND ABS(icons(i)-iconsRef(i)) <= DeltaAngleMax THEN:
//vice et versa:
icons(i) = icons(i)+DeltaAngle
isFinished = false
ENDFOR
ENDWHILE
APPLY_FIRST_ALGO
明智地选择deltaAngle和DeltaAngleMax。 deltaAngle太少会导致大的运行时间。
为了更进一步,你应该看看the force-directed graph drawing算法,这是一种更加健壮的方法来实现你的目标,其中一个难点是找到正确的节点力(你的图标,你没有边缘) )。
答案 1 :(得分:1)
只是头脑风暴:
具有适应度函数的遗传算法,其具有重叠的高惩罚加上等于每个候选位置与其理想位置之间的角距离的平方和(相对于其切片居中)的惩罚。
答案 2 :(得分:0)
我实施的解决方案如下:
ICON_PLACEMENT_RADIUS
为中心的图标)(2.0f * ICON_RADIUS + 1.0f) / ICON_PLACEMENT_RADIUS
)请注意,只有当所有图标数量与圆圈的大小相比较小时,此算法才有效,但它很简单且非常快。
结果是: