Compartir a través de


Ejemplo de borrado de entrada de lápiz

Esta aplicación se basa en el ejemplo de ejemplo de colección de lápiz mostrando la eliminación de trazos de lápiz. En el ejemplo se proporciona al usuario un menú que tiene cuatro modos para elegir: habilitado para entrada de lápiz, borrado en cusp, borrado en intersecciones y borrado de trazos.

En el modo habilitado para entrada de lápiz, el objeto InkCollector recopila la entrada de lápiz como se muestra en El ejemplo de colección de tintas.

En un modo de borrado, se borran segmentos de trazos de lápiz existentes que el usuario toca con el cursor. Además, las cúps o intersecciones se pueden marcar con un círculo rojo.

Las partes más interesantes de este ejemplo se encuentran en el InkErase controlador de eventos del OnPaint formulario y en las funciones de borrado a las que se llama desde el controlador de eventos del OnMouseMove formulario.

Circling the Cusps and Intersections

El controlador de eventos del OnPaint formulario pinta primero los trazos y, en función del modo de aplicación, puede encontrar y marcar todas las cusps o intersecciones con un círculo rojo pequeño. Un cusp marca el punto donde un trazo cambia de dirección abruptamente. Una intersección marca un punto donde un trazo se interseca con sí mismo u otro trazo.

El evento Paint se produce cada vez que se vuelve a dibujar un control.

Nota

El ejemplo obliga al formulario a volver a dibujarse cada vez que se borra un trazo o cuando cambia el modo de aplicación mediante el método Refresh del formulario.

 

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

En PaintCusps, el código recorre en iteración cada cusp de cada trazo y dibuja un círculo rojo alrededor de él. La propiedad PolylineCusps del trazo devuelve los índices de los puntos dentro de un movimiento que corresponden a cusps. Además, tenga en cuenta el método InkSpaceToPixel del objeto Renderer, que convierte el punto en coordenadas relevantes para el método 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);
        }
    }
}

En PaintIntersections, el código recorre en iteración cada trazo para encontrar sus intersecciones con todo el conjunto de trazos. Tenga en cuenta que el método FindIntersections del trazo se pasa a una colección Strokes y devuelve una matriz de valores de índice de punto flotante que representan las intersecciones. A continuación, el código calcula una coordenada X-Y para cada intersección y dibuja un círculo rojo alrededor de ella.

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

Control de un lápiz que tiene dos extremos

Se definen tres controladores de eventos para el objeto InkCollector para los eventos CursorDown, NewPackets y Stroke . Cada controlador de eventos comprueba la propiedad Inverted del objeto Cursor para ver el final del lápiz que se está usando. Cuando se invierte el lápiz:

  • El myInkCollector_CursorDown método hace que el trazo sea transparente.
  • El myInkCollector_NewPackets método borra los trazos.
  • El myInkCollector_Stroke método cancela el evento. Los eventos NewPackets se generan antes del evento Stroke .

Seguimiento del cursor

Tanto si el usuario usa un lápiz como un mouse, se generan eventos MouseMove . El controlador de eventos MouseMove comprueba primero si el modo actual es un modo de borrado y si se presiona algún botón del mouse y omite el evento si estos estados no están presentes. A continuación, el controlador de eventos convierte las coordenadas de píxel del cursor en coordenadas de espacio de entrada de lápiz mediante el método PixelToInkSpace del objeto Renderer y llama a uno de los métodos de borrado del código en función del modo de borrado actual.

Borrar trazos

El EraseStrokes método toma la ubicación del cursor en el espacio de entrada de lápiz y genera una colección de trazos que están dentro HitTestRadius de unidades. El currentStroke parámetro especifica un objeto Stroke que no se debe eliminar. A continuación, la colección strokes se elimina del recopilador y se vuelve a dibujar el formulario.

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

Borrar en intersecciones

El EraseAtIntersections método recorre en iteración cada trazo que se encuentra dentro del radio de prueba y genera una matriz de intersecciones entre ese trazo y todos los demás trazos de la colección. Si no se encuentra ninguna intersección, se elimina todo el trazo; de lo contrario, se encuentra el punto más cercano del trazo al punto de prueba y, desde ese punto, se encuentran las intersecciones de cualquier lado del punto, que describen el segmento que se va a quitar.

El método Split del objeto Stroke se usa para separar el segmento del resto del trazo y, a continuación, se elimina el segmento, dejando intacto el resto del trazo. Como en EraseStrokes, el formulario se vuelve a dibujar antes de que el método devuelva.

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

Borrar en cusps

Para cada trazo que se encuentre dentro del radio de prueba, el EraseAtCusps método recupera la matriz de cusps del método PolylineCusps del objeto Stroke. Cada extremo del trazo también es una cusp, por lo que si el trazo solo tiene dos cups, se elimina todo el trazo; de lo contrario, se encuentra el punto más cercano del trazo al punto de prueba y, desde ese punto, se encuentran las intersecciones de cualquier lado del punto, que describen el segmento que se va a quitar.

El método Split del objeto Stroke se usa para separar el segmento del resto del trazo y, a continuación, se elimina el segmento, dejando intacto el resto del trazo. Como en EraseStrokes, el formulario se vuelve a dibujar antes de que el método devuelva.

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

Cerrar el formulario

El método Dispose del formulario elimina el objeto InkCollector , myInkCollector.