Delen via


Voorbeeld van het verwijderen van inkt

Deze toepassing bouwt voort op het inktverzamelingsvoorbeeld door het verwijderen van pennenstreken te demonstreren. Het voorbeeld biedt de gebruiker een menu met vier modi waaruit u kunt kiezen: inkt ingeschakeld, wissen bij cusp, wissen op snijpunten en wissen van pennenstreken.

In de modus Met inkt ingeschakeld, verzamelt het object InkCollector inkt, zoals wordt weergegeven in Voorbeeld van inktverzameling.

In de verwijdermodus worden segmenten van bestaande pennenstreken die de gebruiker met de aanwijzer raakt gewist. Bovendien kunnen de cusps of snijpunten worden gemarkeerd met een rode cirkel.

De interessantste onderdelen van dit voorbeeld liggen in de gebeurtenis-handler van het InkErase-formulier OnPaint en in de wiskundige functies die worden aangeroepen vanuit de gebeurtenis-handler van het formulier OnMouseMove.

Het omcirkelen van de cusps en kruispunten

De OnPaint-gebeurtenishandler van het formulier schildert eerst de streken en kan, afhankelijk van de toepassingsmodus, alle knikpunten of snijpunten met een kleine rode cirkel vinden en markeren. Een cusp markeert het punt waar een pennenstreek plotseling van richting verandert. Een snijpunt markeert een punt waar een lijn met zichzelf of met een andere lijn kruist.

De gebeurtenis Paint vindt plaats wanneer een bedieningselement opnieuw wordt getekend.

Notitie

In het voorbeeld wordt het formulier gedwongen opnieuw te tekenen wanneer een lijn wordt gewist of wanneer de toepassingsmodus wordt gewijzigd, door de Vernieuwen methode van het formulier te gebruiken.

 

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 PaintCuspsdoorloopt de code elke cusp in elke lijn en tekent er een rode cirkel omheen. De eigenschap PolylineCusps van de stroke retourneert de indexen van de punten binnen een stroke die overeenkomen met cusps. Let ook op de methode Renderer object InkSpaceTo Pixel, waarmee het punt wordt geconverteerd naar coördinaten die relevant zijn voor de methode DrawEllipse.

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 PaintIntersectionsdoorloopt de code elke trek om de kruisingspunten te vinden met de gehele set van trekken. Let op dat de FindIntersections-methode een Strokes verzameling ontvangt en een array met drijvende-komma-indexwaarden retourneert die de kruispunten vertegenwoordigen. De code berekent vervolgens een X-Y-coördinaat voor elk snijpunt en tekent een rode cirkel eromheen.

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

Omgaan met een pen die twee uiteinden heeft

Er worden drie gebeurtenis-handlers gedefinieerd voor het object InkCollector voor de gebeurtenissen CursorDown, NewPacketsen Stroke gebeurtenissen. Elke gebeurtenishandler controleert de eigenschap Cursor object omgekeerde om te zien welk einde van de pen wordt gebruikt. Wanneer de pen wordt omgekeerd:

  • De methode myInkCollector_CursorDown maakt de lijn transparant.
  • Met de methode myInkCollector_NewPackets worden streken gewist.
  • De myInkCollector_Stroke-methode annuleert de gebeurtenis. NewPackets evenementen worden gegenereerd vóór het evenement Stroke.

De cursor bijhouden

Of de gebruiker nu een pen of muis gebruikt, MouseMove gebeurtenissen worden gegenereerd. De MouseMove-gebeurtenishandler controleert eerst of de huidige modus een wis-modus is en of er een muisknop is ingedrukt, en negeert de gebeurtenis als aan deze voorwaarden niet is voldaan. Vervolgens converteert de gebeurtenis-handler de pixelcoördinaten voor de cursor naar inktruimtecoördinaten met behulp van de methode Renderer object PixelToInkSpace en roept een van de gummethoden van de code aan, afhankelijk van de huidige gummodus.

Strokes verwijderen

De methode EraseStrokes neemt de locatie van de cursor in de inktruimte en genereert een verzameling pennenstreken die zich binnen HitTestRadius eenheden bevinden. De parameter currentStroke geeft een Stroke-object op dat niet mag worden verwijderd. Vervolgens wordt de verzameling pennenstreken verwijderd uit de collector en wordt het formulier opnieuw getekend.

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

Wissen op kruispunten

De methode EraseAtIntersections doorloopt elke lijn die binnen de teststraal valt en genereert een matrix van snijpunten tussen die lijn en alle andere stroken in de verzameling. Als er geen snijpunten worden gevonden, wordt die hele lijn verwijderd; anders bevindt het dichtstbijzijnde punt van de lijn naar het testpunt zich en van daaruit bevinden de snijpunten aan beide zijden van het punt zich, waarin het segment wordt beschreven dat moet worden verwijderd.

De methode Stroke object Split wordt gebruikt om het segment te scheiden van de rest van de lijn en vervolgens wordt het segment verwijderd, waardoor de rest van de lijn intact blijft. Net als in EraseStrokeswordt het formulier opnieuw getekend voordat de methode wordt geretourneerd.

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

Wissen bij Cusps

Voor elke lijn die binnen de teststraal valt, haalt de EraseAtCusps methode de matrix van cusps op uit de methode Stroke object PolylineCusps. Elk uiteinde van de streek is ook een knik, dus als de streek maar twee knikken heeft, wordt de hele streek verwijderd; anders wordt het dichtstbijzijnde punt van de streek bij het testpunt bepaald, en vanaf daar worden de snijpunten aan beide zijden van dat punt vastgesteld om het te verwijderen segment te beschrijven.

De methode Stroke object Split wordt gebruikt om het segment te scheiden van de rest van de lijn en vervolgens wordt het segment verwijderd, waardoor de rest van de lijn intact blijft. Net als in EraseStrokeswordt het formulier opnieuw getekend voordat de methode terugkeert.

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

Het formulier sluiten

Met de methode Dispose van het formulier wordt het InkCollector-object myInkCollectorverwijderd.