다음을 통해 공유


잉크 지우기 샘플

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

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

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

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

Cusps 및 교집합 순환

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

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코드는 각 스트로크의 각 cusp를 반복하고 주위에 빨간색 원을 그립니다. 스트로크의 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 개체에 대해 세 가지 이벤트 처리기가 정의됩니다. 각 이벤트 처리기는 Cursor 개체의 반전된 속성을 확인하여 펜의 끝을 확인합니다. 펜이 반전된 경우:

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

커서 추적

사용자가 펜을 사용하든 마우스를 사용하든 MouseMove 이벤트가 생성됩니다. MouseMove 이벤트 처리기는 먼저 현재 모드가 지우기 모드인지, 마우스 단추를 눌렀는지 여부를 확인하고 이러한 상태가 없는 경우 이벤트를 무시합니다. 그런 다음, 이벤트 처리기는 렌더러 개체의 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]);
        ...
    }
    ...
}

커프스에서 지우기

테스트 반지름 내에 속하는 각 스트로크에 대해 메서드는 EraseAtCuspsStroke 개체의 PolylineCusps 메서드에서 cusps 배열을 검색합니다. 스트로크의 각 끝도 cusp이므로 스트로크에 두 개의 커프스만 있으면 전체 스트로크가 삭제됩니다. 그렇지 않으면 스트로크에서 테스트 지점까지의 가장 가까운 지점이 있으며, 그로부터 지점의 양쪽에 있는 교차점이 위치하여 제거할 세그먼트를 설명합니다.

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삭제합니다.