2012-07-21 11 views
7

は、このASCIIの描画を考えてみましょう:iOSの - 順不同CGPointsで特定CGPathにを描画する方法

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 → BB → EE → F ... K → LL → CC → Dから引き出さなければなりません。 EがBの後でなく、Cが配列のLの後でない場合(そうでない場合)、これは明らかに正しく描画されません。

詳しく

  1. すべての行は互いに直交する描かれているので、全てCGPointsx又はy前とそれらの後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

+0

ポイントは常に互いに直角になっていますか、それとも単なる例ですか? –

+0

@rdelmar点は、配列が初期化された後、不明な時刻に追加されます。初期化時の配列内の唯一の4つの点は四隅です。 – Anthony

答えて

2

に興味があるかもしれません。私は数組の数でそれをテストし、それは動作するように見えました。基本的には、インデックス0のポイントから開始して、そのポイントをalignedPoints配列に追加してから、同じy値を持つ最も近いポイントを探します。そのポイントは、alignedPointsに追加され、元のrandomPointsから削除されますアレイ。私はx方向に同じことを行い、randomPoints配列に残っているポイントが1つしかなくなるまでrepeatを繰り返して、これをalignedPointsの最後に追加します。

-(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つの異なる線に当たることを見て、コーナー1を確認することができます。欠落しているポイント(上の最後の例の推定ポイントp)を計算し、元の矩形のどのポイントも同じであることを確認し、そのポイントをパスから削除する必要があります。私のアルゴリズムは正しく動作すると思います。

+0

あなたのメソッドは上記の「その他の可能なレイアウト」の最後の図で動作しますか?取り出されるチャンクは元の矩形の1つの角にある小さな矩形ですか?小さい方の矩形は、元の矩形と共通の点を共有し、前述の例では左上の点を共有します。 – inwit

+0

私の方法は元の矩形の概念を持っていないので、そうだと思います。 x方向に沿った最も近い点とそれに続くy方向を探します。すべての点はランダムな順番になります。 – rdelmar

+0

以下は、あなたのメソッドに対してテストするためのテストケースです。これは8点の集合で、最初の4点は元の矩形を表し、次の4点はその1隅から削除された小さな矩形を表します。 (0,0)、(10,0)、(10,10)、(0,10)、(10,9)、(10,10)、(9,10)、(9,9)である。 (ポイント(10,10)は縮退している、つまりリストに2回現れることに注意してください。これはパスを "二重に戻す"と考えていますが、これは塗りつぶしには問題ありませんが、ストロークの突き出しビット) – inwit

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. を使用して、偶数奇数塗りつぶし規則を使用して侵食された図形を塗りつぶします。

偶奇塗りつぶし規則はQuartz 2D Programming GuideセクションFilling a Pathに記載されています。

また、私は、これはそれを行うかもしれないと思うthis

+0

ありがとうございました。ストロークは必要かもしれませんが、奇数の塗りつぶしルール情報の場合は上向きです。 – Anthony

+0

偶数の塗りつぶしルールも必要ですか?追加の閉じた図形を背景色で塗りつぶすだけで、あなたが望む塗りつぶした図形をあなたに与えるはずです(そうしてはいけませんか?)。 – rdelmar

関連する問題