185

I have this practice project that allows the user to draw on the screen as they touch with their fingers. Very simple App I did as an exercise way back. My little cousin took the liberty of drawing things with his finger with my iPad on this App (Kids drawings: circle, lines, etc, whatever came to his mind). Then he started to draw circles and then he asked me to make it a "good circle" (from my understanding: make the drawn circle perfectly round, as we know no matter how stable we try to draw something with our finger on the screen, a circle is never really as rounded as a circle should be).

So my question here is that, is there any way in code where we can first detect a line drawn by the user that forms a circle and generate approximately the same size of the circle by making it perfectly round on the screen. Making a not so straight line straight is something I would know how to do, but as for circle, I don't quite know how to go about doing it with Quartz or other methods.

My reasoning is that, the start and the end point of the line must touch or cross each other after the user lifts his finger to justify the fact that he was trying to actually draw a circle.

4

8 に答える 8

5

ここに別の方法があります。UIView touchesBegan、touchesMoved、touchesEnded を使用して、配列にポイントを追加します。配列を半分に分割し、一方の配列のすべての点が、他方の配列の対応する点と他のすべてのペアの直径とほぼ同じかどうかをテストします。

    NSMutableArray * pointStack;

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // Detect touch anywhere
    UITouch *touch = [touches anyObject];


    pointStack = [[NSMutableArray alloc]init];

    CGPoint touchDownPoint = [touch locationInView:touch.view];


    [pointStack addObject:touchDownPoint];

    }


    /**
     * 
     */
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {

            UITouch* touch = [touches anyObject];
            CGPoint touchDownPoint = [touch locationInView:touch.view];

            [pointStack addObject:touchDownPoint];  

    }

    /**
     * So now you have an array of lots of points
     * All you have to do is find what should be the diameter
     * Then compare opposite points to see if the reach a similar diameter
     */
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
            uint pointCount = [pointStack count];

    //assume the circle was drawn a constant rate and the half way point will serve to calculate or diameter
    CGPoint startPoint = [pointStack objectAtIndex:0];
    CGPoint halfWayPoint = [pointStack objectAtIndex:floor(pointCount/2)];

    float dx = startPoint.x - halfWayPoint.x;
    float dy = startPoint.y - halfWayPoint.y;


    float diameter = sqrt((dx*dx) + (dy*dy));

    bool isCircle = YES;// try to prove false!

    uint indexStep=10; // jump every 10 points, reduce to be more granular

    // okay now compare matches
    // e.g. compare indexes against their opposites and see if they have the same diameter
    //
      for (uint i=indexStep;i<floor(pointCount/2);i+=indexStep)
      {

      CGPoint testPointA = [pointStack objectAtIndex:i];
      CGPoint testPointB = [pointStack objectAtIndex:floor(pointCount/2)+i];

      dx = testPointA.x - testPointB.x;
      dy = testPointA.y - testPointB.y;


      float testDiameter = sqrt((dx*dx) + (dy*dy));

      if(testDiameter>=(diameter-10) && testDiameter<=(diameter+10)) // +/- 10 ( or whatever degree of variance you want )
      {
      //all good
      }
      else
      {
      isCircle=NO;
      }

    }//end for loop

    NSLog(@"iCircle=%i",isCircle);

}

その音大丈夫?:)

于 2013-09-27T16:35:38.150 に答える
3

ユーザーが描画を開始した場所から図形を描画し終えたと判断したら、ユーザーが描画した座標のサンプルを取得し、それらを円に当てはめてみることができます。

この問題に対する MATLAB ソリューションがここにあります: http://www.mathworks.com.au/matlabcentral/fileexchange/15060-fitcircle-m

これは、Walter Gander、Gene H. Golub、Rolf Strebel による 円と楕円の最小二乗フィッティングの論文に基づいています: http://www.emis.de/journals/BBMS/Bulletin/sup962/gander.pdf

カンタベリー大学 (NZ) の Ian Cooope 博士は、次の要約を含む論文を発表しました。

平面内の一連の点に最適な円を決定する問題 (または n 次元への明白な一般化) は、ガウス ニュートン最小化アルゴリズムを使用して解決できる非線形の総最小二乗問題として簡単に定式化されます。この単純なアプローチは非効率的であり、外れ値の存在に非常に敏感であることが示されています。別の定式化では、問題を単純に解決できる線形最小二乗問題に減らすことができます。推奨されるアプローチには、非線形最小二乗アプローチよりも異常値の影響を受けにくいという追加の利点があることが示されています。

http://link.springer.com/article/10.1007%2FBF00939613

MATLAB ファイルは、非線形 TLS と線形 LLS の両方の問題を計算できます。

于 2013-09-24T23:56:37.637 に答える
3

私は形状認識の専門家ではありませんが、問題へのアプローチ方法を次に示します。

まず、ユーザーのパスをフリーハンドで表示しながら、点 (x, y) のサンプルのリストを時間と共に密かに蓄積します。ドラッグ イベントから両方の事実を取得し、それらを単純なモデル オブジェクトにラップして、それらを可変配列に積み重ねることができます。

おそらく、0.1 秒ごとなど、かなり頻繁にサンプルを取得する必要があります。もう 1 つの可能性は、非常に頻繁に (おそらく 0.05 秒ごとに) 開始しユーザーがドラッグする時間を監視することです。一定時間以上ドラッグする場合は、サンプル周波数を 0.2 秒程度に下げます (見逃していたサンプルをドロップします)。

(そして、私の数字を福音と見なさないでください。なぜなら、私は帽子からそれらを引き出したからです。実験して、より良い値を見つけてください。)

次に、サンプルを分析します。

2 つの事実を導出する必要があります。まず、形状の中心。(IIRC) は、すべてのポイントの平均になります。次に、その中心からの各サンプルの平均半径。

@ user1118321が推測したように、多角形をサポートしたい場合、残りの分析はその決定を行うことで構成されます:ユーザーが円または多角形を描きたいかどうか。サンプルを多角形として見て、その決定を行うことができます。

使用できる基準はいくつかあります。

  • 時間: ユーザーがあるポイントで他のポイントよりも長くホバーしている場合 (サンプルが一定の間隔である場合、空間内で互いに近接する連続したサンプルのクラスターとして表示されます)、それらはコーナーである可能性があります。各コーナーで意図的に一時停止するのではなく、ユーザーが無意識にこれを実行できるように、コーナーのしきい値を小さくする必要があります。
  • 角度: 円は、あるサンプルから次のサンプルまでほぼ同じ角度になります。多角形には、直線セグメントで結合されたいくつかの角度があります。角は角です。正多角形 (不規則な多角形の楕円への円) の場合、角の角度はすべてほぼ同じである必要があります。不規則な多角形の角の角度は異なります。
  • 間隔: 正多角形の角は角度寸法内で等間隔になり、半径は一定になります。不規則な多角形は、不規則な角度間隔および/または一定でない半径を持ちます。

最後の 3 番目のステップは、以前に決定された中心点を中心として、以前に決定された半径で形状を作成することです。

私が上で述べたことがうまくいくか、または効率的であるという保証はありませんが、少なくともあなたが正しい軌道に乗ってくれることを願っています.これについては、コメントまたは独自の回答を自由に投稿してください。

于 2013-09-22T01:51:18.077 に答える
2

私は、適切に訓練された $1 認識装置 ( http://depts.washington.edu/aimgroup/proj/dollar/ )でかなり幸運に恵まれました。丸、線、三角、四角に使いました。

UIGestureRecognizer の前のずっと前のことですが、適切な UIGestureRecognizer サブクラスを作成するのは簡単だと思います。

于 2013-09-24T21:16:49.993 に答える