2013-03-28 77 views
4

嘗試繪製餅圖時出現問題。 Design example餅圖圖標放置算法

當然,繪製圖表沒有問題,問題在於圖標的放置。 理想情況下,圖標應放置在一個圓上(讓我們暫時忘記百分比標籤)。

然而,當有相鄰項目的值很小時,設計顯然會中斷。

Implementation example

您建議的算法解決這一問題?爲了簡化,作爲輸入,我們有:
PIE_RADIUS - 餡餅的外半徑。
ICON_RADIUS - 圖標圓的半徑。
ICON_PLACEMENT_RADIUS - 圖標中心應放在理想位置時的圓的半徑。
NUM_ICONS - 放置圖標的數量。
iconAngles角度爲每個圖標,在其截面中心

需要的輸出:
要麼iconAngles用於移動圖標,把自己的理想圓的時候周圍放置餡餅或iconPositions項目。

我知道如何檢查兩個圖標是否重疊。 我們可以認爲餡餅的中心位於(0, 0)

(該實現是iOS應用程序的一部分,但我對通用算法感興趣)。

回答

0

我實現該解決方案是以下內容:

  1. 計算位置對於所有相對於它們的切片(圖標中心ICON_PLACEMENT_RADIUS
  2. 查找重疊的圖標(迭代的圖標,並檢查的序列的圖標下一個與前一個重疊)。
  3. 計算兩個圖標(約(2.0f * ICON_RADIUS + 1.0f)/ICON_PLACEMENT_RADIUS
  4. 計算序列的中心(總結所有片的序列並找到中心)之間的最小的角距離,圖標放置在一起(在它們之間的距離是最小的角距離)。
  5. 放置所有圖標時,檢查圖標是否重疊,如果是,則合併它們的序列並重復。

注意這個算法只能如果所有圖標的數量是比較小的圈子的大小,但它的簡單和速度非常快。

結果是:
enter image description here

+0

這不是最好的解決方案,但它足夠好並且很容易實現。對於閱讀此內容的人,請閱讀其他答案。 – Sulthan 2013-05-23 10:51:39

+0

蘇丹 - 你好,你在乎分享完整的解決方案嗎?我會非常感謝代碼本身,我確實需要它的Android,但iOS的例子也將作爲一個很好的參考。 – sahar 2017-05-16 14:10:49

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 

有了這個第一算法一些圖標會futher從中心以外。但它沒有通過改變角度來利用可能的地方。通過將其應用於第二個設計(具有較小的值),顯然該解決方案將遠離理想的解決方案。

第二少幼稚算法中,首先我們分配一個新的角度(大於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算法,這是更健壯的方法來實現你的目標,其中一個難點是找到節點的正確力量(你的圖標,你沒有邊緣)。

+0

感謝您的回答。我沒有實現它只改變角度,因爲你提到的'push'方法實現起來也非常棘手。感謝您的鏈接,我一定會學習算法。但是,我一直在尋找簡單的解決方案,這是程序員可以在一天(或兩天)內實現的。圖表繪圖庫可以實現一些先進的算法,但是普通程序員沒有時間並且必須找到不完美的算法,只有足夠好。 – Sulthan 2013-04-03 16:03:48

+0

另一種解決方案是改變角度,如果發生某些重疊仍然存在,則增加ICON_PLACEMENT_RADIUS。關於「推」的方法,我不知道你的座標系,但它很容易在極座標和笛卡爾座標之間切換,並且極座標「推」只是增加了距離原點的距離(對於你的情況來說是完美的,因爲餡餅的中心位於(0,0))。 – 2013-04-03 16:15:22

+0

如果你這樣做,你會增加繪製餅圖所需的總空間。我試過這個解決方案,但看起來不太好。特別是當多個圖標幾乎在同一個地方時。 – Sulthan 2013-04-03 17:57:05

1

只要頭腦風暴:

的遺傳算法使用具有用於重疊的高懲罰加上等於每個候選位置及其理想位置之間的角距離的平方之和的懲罰健身功能(相對中心到它的片段)。

+0

我在互聯網上看到了一種使用遺傳算法的解決方案,但對於我的使用情況來說似乎太複雜了。但是,如果我正在實施圖表繪圖庫,我肯定會選擇遺傳算法。 – Sulthan 2013-04-03 18:51:37