Beispiel zum Löschen von Ink-Löschungen

Diese Anwendung baut auf dem Beispiel für die Ink-Sammlung auf, indem das Löschen von Ink-Strichen veranschaulicht wird. Das Beispiel stellt dem Benutzer ein Menü bereit, in dem vier Modi zur Auswahl stehen: Freihandaktivierung, Löschung bei Cusp, Löschen an Schnittmengen und Löschen von Strichen.

Im Ink-fähigen Modus erfasst das InkCollector-Objekt Ink,wie im Beispiel zur Ink-Sammlunggezeigt.

In einem Löschmodus werden Segmente vorhandener Ink-Striche, die der Benutzer mit dem Cursor berührt, gelöscht. Außerdem können die Cusps oder Schnittmengen mit einem roten Kreis markiert werden.

Die interessantesten Teile dieses Beispiels liegen im Ereignishandler des InkErase Formulars OnPaint und in den Löschfunktionen, die vom Ereignishandler des Formulars aufgerufen OnMouseMove werden.

Kreisen der Cusps und Schnittmengen

Der Ereignishandler des Formulars OnPaint zeichnet zuerst die Striche und kann je nach Anwendungsmodus alle Cusps oder Schnittmengen mit einem kleinen roten Kreis suchen und markieren. Ein Cusp markiert den Punkt, an dem ein Strich die Richtung plötzlich ändert. Eine Schnittmenge markiert einen Punkt, an dem sich ein Strich mit sich selbst oder einem anderen Strich überschneidet.

Das Paint Ereignis tritt auf, wenn ein Steuerelement neu gezeichnet wird.

Hinweis

Das Beispiel erzwingt, dass sich das Formular neu zeichnet, wenn ein Strich gelöscht wird oder wenn sich der Anwendungsmodus ändert, indem die Refresh-Methode des Formulars verwendet wird.

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;
    }
}

In PaintCusps durchläuft der Code jeden Strich in jedem Strich und zeichnet einen roten Kreis um ihn. Die PolylineCusps-Eigenschaft des Strichs gibt die Indizes der Punkte innerhalb eines Strichs zurück, die cusps entsprechen. Beachten Sie auch die InkSpaceToPixel-Methode des Rendererobjekts, die den Punkt in Koordinaten konvertiert, die für die DrawEllipse-Methode relevant sind.

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);
        }
    }
}

In PaintIntersections durchläuft der Code jeden Strich, um seine Schnittmengen mit dem gesamten Satz von Strichen zu finden. Beachten Sie, dass der FindIntersections-Methode des Strichs eine Strokes-Auflistung übergeben wird und ein Array von Gleitkommaindexwerten zurückgegeben wird, die die Schnittmengen darstellen. Der Code berechnet dann eine X-Y-Koordinate für jede Schnittmenge und zeichnet einen roten Kreis um diese.

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

Behandeln eines Stifts mit zwei Enden

Für das InkCollector-Objekt werden drei Ereignishandler für die Ereignisse CursorDown, NewPacketsund Stroke definiert. Jeder Ereignishandler überprüft die Inverted-Eigenschaft des Cursorobjekts, um festzustellen, welches Ende des Stifts verwendet wird. Wenn der Stift invertiert wird:

  • Die myInkCollector_CursorDown -Methode macht den Strich transparent.
  • Die myInkCollector_NewPackets -Methode löscht Striche.
  • Die myInkCollector_Stroke -Methode bricht das -Ereignis ab. NewPackets-Ereignisse werden vor dem Stroke-Ereignis generiert.

Nachverfolgen des Cursors

Unabhängig davon, ob der Benutzer einen Stift oder eine Maus verwendet, werden MouseMove-Ereignisse generiert. Der MouseMove-Ereignishandler überprüft zunächst, ob der aktuelle Modus ein Löschmodus ist und ob eine Maustaste gedrückt wird, und ignoriert das Ereignis, wenn diese Zustände nicht vorhanden sind. Anschließend konvertiert der Ereignishandler die Pixelkoordinaten für den Cursor mithilfe der PixelToInkSpace-Methode des Rendererobjekts in Freihandraumkoordinaten und ruft abhängig vom aktuellen Löschmodus eine der Löschmethoden des Codes auf.

Löschen von Strichen

Die EraseStrokes -Methode verwendet die Position des Cursors im Freihandraum und generiert eine Auflistung von Strichen, die sich innerhalb von HitTestRadius Einheiten befinden. Der currentStroke -Parameter gibt ein Stroke-Objekt an, das nicht gelöscht werden soll. Anschließend wird die Strichauflistung aus dem Collector gelöscht, und das Formular wird neu gezeichnet.

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();
    }
}

Löschen an Schnittmengen

Die EraseAtIntersections -Methode durchläuft jeden Strich, der in den Testradius fällt, und generiert ein Array von Schnittmengen zwischen diesem Strich und allen anderen Strichen in der Auflistung. Wenn keine Schnittmengen gefunden werden, wird der gesamte Strich gelöscht. Andernfalls befindet sich der nächstgelegene Punkt auf dem Strich zum Testpunkt, und daraus befinden sich die Schnittmengen auf beiden Seiten des Punkts, die das zu entfernende Segment beschreiben.

Die Split-Methode des Stroke-Objekts wird verwendet, um das Segment vom Rest des Strichs zu trennen, und dann wird das Segment gelöscht, sodass der Rest des Strichs intakt bleibt. Wie in EraseStrokes wird das Formular neu gezeichnet, bevor die Methode zurückgegeben wird.

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]);
        ...
    }
    ...
}

Auslöschung bei Cusps

Für jeden Strich, der in den Testradius fällt, ruft die EraseAtCusps -Methode das Array von Cusps aus der PolylineCusps-Methode des Stroke-Objekts ab. Jedes Ende des Strichs ist auch ein Strich. Wenn der Strich also nur zwei Cusps hat, wird der gesamte Strich gelöscht. Andernfalls befindet sich der nächstgelegene Punkt auf dem Strich zum Testpunkt, und daraus befinden sich die Schnittmengen auf beiden Seiten des Punkts, die das zu entfernende Segment beschreiben.

Die Split-Methode des Stroke-Objekts wird verwendet, um das Segment vom Rest des Strichs zu trennen, und dann wird das Segment gelöscht, sodass der Rest des Strichs intakt bleibt. Wie in EraseStrokes wird das Formular neu gezeichnet, bevor die Methode zurückgegeben wird.

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);
        ...
    }
    ...
}

Schließen des Formulars

Die Dispose-Methode des Formulars verwerfen das InkCollector-Objekt myInkCollector .