インク消去サンプル

このアプリケーションは、インク ストロークの削除を示すことによって 、Ink Collection サンプル サンプルに基づいています。 このサンプルでは、インク対応、カスプでの消去、交差点での消去、ストロークの消去の 4 つのモードから選択できるメニューがユーザーに提供されます。

インク対応モードでは、 InkCollector オブジェクトは、「Ink Collection Sample」に示すように インクを収集します。

消去モードでは、ユーザーがカーソルでタッチした既存のインク ストロークのセグメントが消去されます。 また、カスプまたは交差部分には赤い円が付いている場合があります。

このサンプルの最も興味深い部分はInkErase、フォームのイベント ハンドラーと、フォームOnMouseMoveOnPaintイベント ハンドラーから呼び出される消去関数にあります。

カスプと交差点を周回する

フォームの OnPaint イベント ハンドラーは最初にストロークを描画し、アプリケーション モードによっては、すべてのカスプまたは交差部分を小さな赤い円で見つけてマークする場合があります。 カスプは、ストロークの方向が急激に変化するポイントをマークします。 交差は、1 つのストロークがそれ自体または別のストロークと交差する点をマークします。

Paint イベントは、コントロールが再描画されるたびに発生します。

Note

このサンプルでは、フォームの Refresh メソッドを使用して、ストロークが消去されたとき、またはアプリケーション モードが変更されるたびにフォーム自体を強制的に再描画します。

 

private void InkErase_OnPaint(object sender, PaintEventArgs e)
{
    Strokes strokesToPaint = myInkCollector.Ink.Strokes;

    myInkCollector.Renderer.Draw(e.Graphics, strokesToPaint);

    switch (mode)
    {
        case ApplicationMode.CuspErase:
            PaintCusps(e.Graphics, strokesToPaint);
            break;
        case ApplicationMode.IntersectErase:
            PaintIntersections(e.Graphics, strokesToPaint);
            break;
    }
}

では PaintCusps、コードは各ストロークの各カスプを反復処理し、その周りに赤い円を描画します。 ストロークの PolylineCusps プロパティは、カスプに対応するストーク内のポイントのインデックスを返します。 また、DrawEllipse メソッドに関連する座標にポイントを変換する Renderer オブジェクトの InkSpaceToPixel メソッドにも注意してください。

private void PaintCusps(Graphics g, Strokes strokesToPaint)
{
    foreach (Stroke currentStroke in strokesToPaint)
    {
        int[] cusps = currentStroke.PolylineCusps;

        foreach (int i in cusps)
        {
            Point pt = currentStroke.GetPoint(i);

            // Convert the X, Y position to Window based pixel coordinates
            myInkCollector.Renderer.InkSpaceToPixel(g, ref pt);

            // Draw a red circle as the cusp position
            g.DrawEllipse(Pens.Red, pt.X-3, pt.Y-3, 6, 6);
        }
    }
}

では PaintIntersections、コードは各ストロークを反復処理して、ストロークのセット全体との交差部分を見つけます。 ストロークの FindIntersections メソッドには Strokes コレクションが渡され、交差部分を表す浮動小数点インデックス値の配列が返されることに注意してください。 次に、各交差の X-Y 座標を計算し、その周りに赤い円を描画します。

private void PaintIntersections(Graphics g, Strokes strokesToPaint)
{
    foreach (Stroke currentStroke in strokesToPaint)
    {
        float[] intersections =            currentStroke.FindIntersections(strokesToPaint);
    }
}

2 つの端を持つペンの処理

CursorDownNewPacketsStroke イベントの InkCollector オブジェクトには、3 つのイベント ハンドラーが定義されています。 各イベント ハンドラーは 、Cursor オブジェクトの Inverted プロパティをチェックして、使用されているペンの末尾を確認します。 ペンが反転している場合:

  • メソッドを myInkCollector_CursorDown 使用すると、ストロークが透明になります。
  • メソッドは myInkCollector_NewPackets ストロークを消去します。
  • メソッドは myInkCollector_Stroke イベントを取り消します。 NewPackets イベントは 、Stroke イベントの前に生成されます。

カーソルの追跡

ユーザーがペンまたはマウスのどちらを使用しているかに関係なく、 MouseMove イベントが生成されます。 MouseMove イベント ハンドラーは、最初に、現在のモードが消去モードかどうか、およびマウス ボタンが押されているかどうかを確認し、これらの状態が存在しない場合はイベントを無視します。 次に、イベント ハンドラーは 、Renderer オブジェクトの PixelToInkSpace メソッドを使用してカーソルのピクセル座標をインク空間座標に変換し、現在の消去モードに応じてコードの消去メソッドのいずれかを呼び出します。

消去ストローク

メソッドは EraseStrokes 、インク空間内のカーソルの位置を取得し、単位内 HitTestRadius にあるストロークのコレクションを生成します。 パラメーターは currentStroke 、削除すべきではない Stroke オブジェクトを指定します。 次に、strokes コレクションがコレクターから削除され、フォームが再描画されます。

private void EraseStrokes(Point pt, Stroke currentStroke)
{
    Strokes strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius);

    if (null!=currentStroke && strokesHit.Contains(currentStroke))
    {
        strokesHit.Remove(currentStroke);
    }

    myInkCollector.Ink.DeleteStrokes(strokesHit);

    if (strokesHit.Count > 0)
    {
        this.Refresh();
    }
}

交差点での消去

メソッドは EraseAtIntersections 、テスト半径内にある各ストロークを反復処理し、そのストロークとコレクション内の他のすべてのストローク間の交差の配列を生成します。 交差が見つからない場合は、ストローク全体が削除されます。それ以外の場合は、テスト ポイントに対するストロークの最も近いポイントが配置され、そこからポイントの両側の交差が配置され、削除するセグメントが記述されます。

Stroke オブジェクトの Split メソッドは、ストロークの残りの部分からセグメントを分離するために使用され、セグメントは削除され、ストロークの残りの部分はそのまま残ります。 と同様に EraseStrokes、 メソッドが戻る前にフォームが再描画されます。

private void EraseAtIntersections(Point pt)
{
    Strokes strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius);

    foreach (Stroke currentStroke in strokesHit)
    {
        float[] intersections = currentStroke.FindIntersections(myInkCollector.Ink.Strokes);
        ...
        float findex = currentStroke.NearestPoint(pt);
        ...
        strokeToDelete = currentStroke.Split(intersections[i]);
        ...
    }
    ...
}

Cusps での消去

メソッドは、テスト半径内にあるストロークごとに、EraseAtCuspsStroke オブジェクトの PolylineCusps メソッドから cusps の配列を取得します。 ストロークの各端もカスプであるため、ストロークに 2 つのカスプしかない場合は、ストローク全体が削除されます。それ以外の場合は、テスト ポイントに対するストロークの最も近いポイントが配置され、そこからポイントの両側の交差が配置され、削除するセグメントが記述されます。

Stroke オブジェクトの Split メソッドは、ストロークの残りの部分からセグメントを分離するために使用され、セグメントは削除され、ストロークの残りの部分はそのまま残ります。 と同様に EraseStrokes、 メソッドが戻る前にフォームが再描画されます。

private void EraseAtCusps(Point pt)
{
    ...
    strokesHit = myInkCollector.Ink.HitTest(pt, HitTestRadius);
    
    foreach (Stroke currentStroke in strokesHit)
    {
        int[] cusps = currentStroke.PolylineCusps;
        ...
        float findex = currentStroke.NearestPoint(pt);
        ...
        strokeToDelete = currentStroke.Split(cusps[i]); 
        myInkCollector.Ink.DeleteStroke(strokeToDelete);
        ...
    }
    ...
}

フォームを閉じる

フォームの Dispose メソッドは、myInkCollectorInkCollector オブジェクト を破棄します。