饼图图标放置算法

我在尝试绘制饼图时遇到问题.

当然,绘制图表没有问题,问题是图标放置.
理想情况下,图标应放在圆圈上(让我们忘记现在的百分比标签).

但是,当存在具有较小值的邻居项时,设计显然会中断.

你能推荐一个解决这个问题的算法吗?为了简化,作为输入,我们有:
PIE_RADIUS – 馅饼的外半径.
ICON_RADIUS – 图标圆的半径.
ICON_PLACEMENT_RADIUS – 理想放置图标中心时的圆的半径.
NUM_ICONS – 要放置的图标数.
iconAngles每个图标的角度,位于其截面的中心

所需输出:
当图标移出理想圆圈时,可以在饼图或iconPositions周围放置项目的iconAngles.

我知道如何检查两个图标是否重叠.
我们可以认为饼图的中心位于(0,0).

(该实现是iOS应用程序的一部分,但我对一般的algorihm感兴趣).

最佳答案 第一个天真的算法,我们“推”与其他图标重叠的图标:

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算法,这是实现你的目标更加健壮的方法,其中一个难点是找到正确的节点力(你的图标,你没有边缘).

点赞