다음을 통해 공유


잉크 지우기 샘플

이 애플리케이션은 잉크 스트로크 삭제를 보여 줌으로써 잉크 컬렉션 샘플 샘플을 기반으로 합니다. 이 샘플에서는 잉크 사용, 커프스 지우기, 교차점 지우기, 스트로크 지우기 등 선택할 수 있는 4가지 모드가 있는 메뉴를 사용자에게 제공합니다.

잉크 사용 모드에서 InkCollector 개체는 잉크 컬렉션 샘플표시된 대로 잉크를 수집합니다.

지우기 모드에서는 사용자가 커서를 사용하여 터치하는 기존 잉크 스트로크의 세그먼트가 지워집니다. 또한 첨점 또는 교집합은 빨간색 원으로 표시될 수 있습니다.

이 샘플에서 가장 흥미로운 부분은 InkErase 폼의 OnPaint 이벤트 처리기 및 폼의 OnMouseMove 이벤트 처리기에서 호출되는 지우기 함수에 있습니다.

Cusps와 교집합 둘러보기

폼의 OnPaint 이벤트 처리기는 먼저 스트로크를 그린 후, 애플리케이션 모드에 따라 모든 뾰족점 또는 교차점을 찾아 작은 빨간 원으로 표시할 수 있습니다. 커프는 스트로크가 갑자기 방향을 변경하는 지점을 표시합니다. 교차점은 한 스트로크가 자체 또는 다른 스트로크와 교차하는 지점을 표시합니다.

Paint 이벤트는 컨트롤이 다시 그려질 때마다 발생합니다.

메모

이 샘플에서는 스트로크가 지워질 때마다 또는 애플리케이션 모드가 변경될 때마다 양식의 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 속성은 cusps에 해당하는 스토크 내의 점 인덱스를 반환합니다. 또한 점을 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);
    }
}

양쪽 끝이 있는 펜 다루기

CursorDown, NewPacketsStroke 이벤트에 대한 InkCollector 개체에 대해 세 개의 이벤트 처리기가 정의됩니다. 각 이벤트 처리기는 커서 개체의 뒤집힌 속성을 확인하여 펜의 어느 끝을 사용 중인지 확인합니다. 펜이 반전되는 경우:

  • myInkCollector_CursorDown 메서드는 스트로크를 투명하게 만듭니다.
  • myInkCollector_NewPackets 메서드는 스트로크를 지웁니다.
  • myInkCollector_Stroke 메서드는 이벤트를 취소합니다. NewPackets 이벤트는 Stroke 이벤트 전에 생성됩니다.

커서 추적

사용자가 펜을 사용하든지 마우스를 사용하든지 MouseMove 이벤트가 생성됩니다. MouseMove 이벤트 처리기는 먼저 현재 모드가 지우기 모드인지 여부와 마우스 단추를 눌렀는지 여부를 확인하고 이러한 상태가 없는 경우 이벤트를 무시합니다. 그런 다음 이벤트 처리기는 Renderer 개체의 PixelToInkSpace 메서드를 사용하여 커서의 픽셀 좌표를 잉크 공간 좌표로 변환하고 현재 지우기 모드에 따라 코드의 지우기 메서드 중 하나를 호출합니다.

스트로크 지우기

EraseStrokes 메서드는 잉크 공간에서 커서의 위치를 가져와서 HitTestRadius 단위 내에 있는 스트로크 컬렉션을 생성합니다. currentStroke 매개 변수는 삭제해서는 안 되는 Stroke 개체를 지정합니다. 그런 다음 스트로크 컬렉션이 수집기에서 삭제되고 양식이 다시 그려집니다.

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에서 지우기

테스트 반경 내에 속하는 각 스트로크에 대해 EraseAtCusps 메서드는 Stroke 개체의 PolylineCusps 메서드에서 커프스 배열을 검색합니다. 스트로크의 각 끝도 꼭지점이므로, 스트로크에 두 개의 꼭지점만 있으면 전체 스트로크가 삭제됩니다. 그렇지 않으면, 스트로크에서 테스트 지점에 가장 가까운 지점을 찾아 해당 지점 양쪽의 교차점을 찾아 제거할 세그먼트를 설명합니다.

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 메서드는 InkCollector 개체를 해제합니다. myInkCollector