2012-07-21 25 views
7

考慮這個ASCII圖紙:iOS的 - 如何繪製一個特定CGPath與無序CGPoints

A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|        | 
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| 
B         C 

點A,B,C,和d已知的NSMutableArrayCGPoints,並已用於創建一個充滿CGPath 。現在考慮該圖:

A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D 
|        | 
|        | 
|        | 
|        | 
|   H _ _ _ I   | 
|    |  |   | 
|    |  |   | 
|  F _ _ _|  |   | 
|  |  G |   | 
|  |   |_ _ _ K | 
|  |   J  |  | 
|  |     |  | 
|_ _ _ _| _ _ _ _ _ _ _ _ |_ _ _| 
B   E    L  C 

CGPoints E,F,G,H,I,J,K,和L是已知的並且已被附加到NSMutableArray的末尾。

問題

我怎樣才能重新排列陣列中的所有點以創建CGPath看起來像下面的圖紙?

A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D 
|        | 
|        | 
|        | 
|        | 
|   H _ _ _ I   | 
|    |  |   | 
|    |  |   | 
|  F _ _ _|  |   | 
|  |  G |   | 
|  |   |_ _ _ K | 
|  |   J  |  | 
|  |     |  | 
|_ _ _ _|     |_ _ _| 
B   E    L  C 

目前,我有沒有問題創造了CGPath - 如果我知道CGpoints的順序 - 通過他們的循環:

CGPoint firstPoint = [[points objectAtIndex:0] CGPointValue]; 
CGMutablePathRef path = CGPathCreateMutable(); 
CGPathMoveToPoint(path, NULL, firstPoint.x, firstPoint.y); 
for (int i = 0; i < [points count]; i++) 
{ 
    CGPathAddLineToPoint(path, NULL, [[points objectAtIndex:i] CGPointValue].x, [[points objectAtIndex:i] CGPointValue].y); 
} 
CGPathCloseSubpath(path); 

...但這個假設一個行應該從繪製陣列i中的每個點到以下點i + 1。在上圖中,線將必須從A → B,B → E,E → F ... K → L,L → C,C → D得出。如果E不在B之後,C不在數組L之後(它們不會),那麼這顯然不會正確繪製。

更多信息

  1. 所有行互相垂直繪製,因此所有CGPoints應該共享同一個xy之前和之後他們與CGPoint協調。
  2. (#1的延伸)一個點將始終與它之前和之後的點成直角。
  3. 不可能預測點將在方塊內出現的位置,並且當附加到數組末尾時,新的一組點可能會或可能不會按順序排列。
  4. ...

其他可能佈局

A _ _ _ _ _ _ _ K   P _ _ _ D 
|    |   |  | 
|    |   |  | 
|    | N _ _ _|  | 
|    |  |  O | 
|    |_ _ _|   | 
|   L  M   | 
|        | 
|   F _ _ _ G   | 
|    |  |   | 
|    |  |_ _ _ I | 
|    | H  |  | 
|    |   |  | 
|_ _ _ _ _ _ _|   |_ _ _| 
B    E   J  C 


A _ _ _ _ _ _ _ _ _ _ M 
|     |   
|     |   
|     |_ _ _ _ _ _ O 
|     N   | 
|   H _ _ _ I   | 
|    |  |   | 
|    |  |   | 
|  F _ _ _|  |   | 
|  |  G |   | 
|  |   |_ _ _ K | 
|  |   J  |  | 
|  |     |  | 
|_ _ _ _|     |_ _ _| 
B   E    L  C 
+0

你如何把點放入你的數組?爲什麼你不能按照你需要的順序擁有它們? – rdelmar 2012-07-21 16:07:09

+0

這些點總是與另一個成直角,還是僅用於這個例子? – 2012-07-21 17:38:52

+0

@rdelmar在數組初始化之後的未知時間添加點。陣列中僅有的四個點在初始化時是四個角落。 – Anthony 2012-07-21 19:09:04

回答

2

我認爲這可能做到這一點。我用幾組數字對它進行了測試,它似乎工作。基本上,我從索引0開始(任何起點應該工作),將其添加到arrangePoints數組,然後查找具有相同y值的最近點 - 該點將添加到排列好的點並從原始隨機點中刪除陣列。然後,我在x方向上做同樣的事情並重復,直到randomPoints數組中只剩下一個點,並將其添加到arrangePoints的末尾。

-(void)arrangePoints:(NSMutableArray *) randomPoints { 
    NSMutableArray *arrangedPoints = [NSMutableArray array]; 
    [arrangedPoints addObject:[randomPoints objectAtIndex:0]]; 
    [randomPoints removeObjectAtIndex:0]; 

    while (randomPoints.count > 1) { 
     //Look for the closest point that has the same y value 
     int yValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].y; 
     int xValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].x; 
     NSIndexSet *indSet = [randomPoints indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){ 
      return yValueOfknownPoint == [obj CGPointValue].y; 
     }]; 
     NSLog(@"%d",indSet.count); 

     if (indSet.count == 1) { 
      [arrangedPoints addObject:[randomPoints objectAtIndex:indSet.firstIndex]]; 
      [randomPoints removeObjectAtIndex:indSet.firstIndex]; 
     }else{ 
      __block int min = 10000000; 
      __block int foundIndex; 
      [indSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 
       int posibleMin = fabs(xValueOfknownPoint - [[randomPoints objectAtIndex:idx]CGPointValue].x); 
       if (posibleMin < min) { 
        min = posibleMin; 
        foundIndex = idx; 
       } 
      }]; 
      [arrangedPoints addObject:[randomPoints objectAtIndex:foundIndex]]; 
      [randomPoints removeObjectAtIndex:foundIndex]; 
     } 

     //Look for the closest point that has the same x value 
     xValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].x; 
     yValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].y; 
     indSet = [randomPoints indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){ 
      return xValueOfknownPoint == [obj CGPointValue].x; 
     }]; 

     if (indSet.count == 1) { 
      [arrangedPoints addObject:[randomPoints objectAtIndex:indSet.firstIndex]]; 
      [randomPoints removeObjectAtIndex:indSet.firstIndex]; 
     }else{ 
      __block int min = 10000000; 
      __block int foundIndex; 
      [indSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 
       int posibleMin = fabs(yValueOfknownPoint - [[randomPoints objectAtIndex:idx]CGPointValue].y); 
       if (posibleMin < min) { 
        min = posibleMin; 
        foundIndex = idx; 
       } 
      }]; 
      [arrangedPoints addObject:[randomPoints objectAtIndex:foundIndex]]; 
      [randomPoints removeObjectAtIndex:foundIndex]; 
     } 
    } 
    [arrangedPoints addObject:randomPoints.lastObject]; 
    NSLog(@"%@",arrangedPoints); 

} 

一些額外的點來解決已知問題:

爲了對付像從N個G和M等距點,我想我會守點的套獨立 - 而不是把每一件事情到一個數組,我會保留原來的矩形,並將每個新的點集合分開。然後,當我構建路徑時,我只會在自己的一組點或原始矩形內尋找點,而不是在其他任何點中尋找點。

爲了解決提出的問題,提醒自己,我認爲你將不得不確定一組點是否與一個邊或一個角相交 - 我認爲只有角點纔會出現這個問題。您可以通過查看2個點落在原始矩形的2條不同線上(而不是在同一條線上)來檢查角點。然後你必須計算出缺少的點(上面最後一個例子中的一個假定點p),並查看原始矩形的哪個點也是相同的,然後從路徑中刪除該點。我認爲我的算法會正常工作。

+0

您的方法是否與上面的「其他可能佈局」中的最後一個圖形一起工作,其中取出的塊是原始矩形的一個角中的較小矩形?較小的矩形將與原始矩形共享一個共同點,即上述示例中左上角的點。 – inwit 2012-07-21 23:46:09

+0

我這麼認爲,因爲我的方法沒有任何原始矩形的概念。它只是尋找沿x方向的最近點,然後是y方向 - 所有點都可以按隨機順序排列。 – rdelmar 2012-07-22 00:01:11

+0

下面是測試您的方法的測試用例。它是一組8個點,前4個代表原來的矩形,接下來的4個代表從其一個角落移除的更小的矩形。 (0,0),(10,0),(10,10),(0,10),(10,9),(10,10),(9,10),(9,9)。 (請注意,點(10,10)是退化的,也就是說它出現在列表中兩次,我認爲這會導致本身的「雙重返回」,這對於填充不會造成問題,但會導致筆畫的突出位。) – inwit 2012-07-22 00:09:56

0

好吧,這看起來非常複雜的算法(它是遠非最佳),但我想接近它喜歡這個。

1. Find the point(s) with lowest X-value 

2. Of those points find point P (using a loop) such that: 
    - P has a nabour N with the same X-value 
    - There exists no other point that vertically lies between P and its nabour N with the same Y value 
    (if no P exists with a nabour, the algorithm has ended, after joining P with its horizontally aligned point) 

3. If there exists a point with the same X value as P (horizontally aligned), join that point and P with a line. 

4. Now join point P with its nabour N 

5. Find all points with the same X-value as N (horizontally aligned) 

6. Goto 2 

我希望它的工作(沒有測試過)。

2

這是一種方法(在僞代碼),如果你感興趣的是,填充和不招:

  1. 創建使用CGPathCreateMutable()空可變的路徑。

  2. 將原始矩形圖形添加到可變路徑作爲閉環。

  3. 將每個附加的不規則圖形分別添加到可變路徑中,作爲一個閉環單獨添加。

  4. 使用函數CGContextEOFillPath()填充使用偶數填充規則的侵蝕圖。

奇偶填充規則將在節Filling a PathQuartz 2D Programming Guide說明。

您還可能有興趣在this

+0

謝謝你了。筆畫可能是必需的,但是爲偶數的填充規則信息注滿效果。 – Anthony 2012-07-22 18:55:27

+0

你甚至需要偶數的填充規則嗎?如果你只是用背景顏色填充其他封閉的人物,它應該給你你想要的充滿腐蝕的人物(不是嗎?)。 – rdelmar 2012-07-22 21:25:30