Condividi tramite


Esempio di divisione input penna

Questo esempio è basato sull'esempio di raccolta input penna. Illustra come utilizzare l'oggetto Divider per analizzare l'input penna.

Per informazioni concettuali dettagliate sul divisore, vedere L'oggetto Divider.

Quando il modulo viene aggiornato, l'esempio disegna un rettangolo di delimitazione intorno a ogni unità analizzata, suddivisa in parole, linee, paragrafi e disegni. Oltre a utilizzare colori diversi, questi rettangoli vengono ingranditi da quantità diverse per garantire che nessuno dei rettangoli sia nascosto da altri. La tabella seguente specifica il colore e l'ingrandimento per ogni unità analizzata.

unità analizzata Color Ingrandimento pixel
Word
Green
1
A linee
Fucsia
3
Paragraph
Blu
5
Disegno
Red
1

Configurazione del modulo

Quando il modulo viene caricato, viene creato un oggetto Divider . Viene creato un oggetto InkOverlay e associato a un pannello nel form. I gestori eventi vengono quindi collegati all'oggetto InkOverlay per tenere traccia dell'aggiunta e dell'eliminazione dei tratti. Se i riconoscitori sono disponibili, un oggetto RecognizerContext per il riconoscimento predefinito viene assegnato al divisore. Viene quindi impostata la proprietà LineHeight dell'oggetto Divider e l'insieme Strokes dell'oggetto InkOverlay viene assegnato al Divider. Infine, l'oggetto InkOverlay è abilitato.

// Create the ink overlay and associate it with the form
myInkOverlay = new Microsoft.Ink.InkOverlay(DrawArea.Handle);

// Set the erasing mode to stroke erase.
myInkOverlay.EraserMode = InkOverlayEraserMode.StrokeErase;

// Hook event handler for the Stroke event to myInkOverlay_Stroke.
// This is necessary since the application needs to pass the strokes 
// to the ink divider.
myInkOverlay.Stroke += new InkCollectorStrokeEventHandler(myInkOverlay_Stroke); 

// Hook the event handler for StrokeDeleting event to myInkOverlay_StrokeDeleting.
// This is necessary as the application needs to remove the strokes from 
// ink divider object as well.
myInkOverlay.StrokesDeleting += new InkOverlayStrokesDeletingEventHandler(myInkOverlay_StrokeDeleting);

// Hook the event handler for StrokeDeleted event to myInkOverlay_StrokeDeleted.
// This is necessary to update the layout analysis result when automatic layout analysis
// option is selected.
myInkOverlay.StrokesDeleted += new InkOverlayStrokesDeletedEventHandler(myInkOverlay_StrokeDeleted);

// Create the ink divider object
myInkDivider = new Divider();

// Add a default recognizer context to the divider object
// without adding the recognizer context, the divider would
// not use a recognizer to do its word segmentation and would
// have less accurate results.
// Adding the recognizer context slows down the call to 
// myInkDivider.Divide though.
// It is possible that there is no recognizer installed on the
// machine for this language. In that case the divider does
// not use a recognizer to improve its accuracy.
// Get the default recognizer if any
try
{
    Recognizers recognizers = new Recognizers();
     myInkDivider.RecognizerContext = recognizers.GetDefaultRecognizer().CreateRecognizerContext();
}
catch (InvalidOperationException)
{
     //We are in the case where no default recognizers can be found
}

    // The LineHeight property helps the InkDivider distinguish between 
    // drawing and handwriting. The value should be the expected height 
    // of the user's handwriting in ink space units (0.01mm).
    // Here we set the LineHeight to 840, which is about 1/3 of an inch.
    myInkDivider.LineHeight = 840;

// Assign ink overlay's strokes collection to the ink divider
// This strokes collection is updated in the event handler
myInkDivider.Strokes = myInkOverlay.Ink.Strokes;

// Enable ink collection
myInkOverlay.Enabled = true;

L'insieme Strokes dell'oggetto Divider deve essere mantenuto sincronizzato con l'insieme Strokes dell'oggetto InkOverlay, accessibile tramite la proprietà InkOverlay dell'oggetto Ink. Per assicurarsi che ciò avvenga, il gestore eventi Stroke per l'oggetto InkOverlay viene scritto come segue. Si noti che il gestore eventi verifica innanzitutto se EditingMode è impostato su Ink per filtrare i tratti della gomma. Se l'utente ha richiesto l'analisi automatica del layout, l'applicazione chiama il metodo DivideInk del modulo e aggiorna l'area di disegno.

private void myInkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e )
{
    // Filter out the eraser stroke.
    if(InkOverlayEditingMode.Ink == myInkOverlay.EditingMode)
    {
        // Add the new stroke to the ink divider's strokes collection
        myInkDivider.Strokes.Add(e.Stroke);
        
        if(miAutomaticLayoutAnalysis.Checked)
        {
            // Call DivideInk
            DivideInk();

            // Repaint the screen to reflect the change
            DrawArea.Refresh();
        }
    }
}

Divisione dell'input penna

Quando l'utente fa clic su Divide nel menu File, viene chiamato il metodo Divide sull'oggetto Divider . Il riconoscitore predefinito viene usato, se disponibile.

DivisionResult divResult = myInkDivider.Divide();

L'oggetto DivisionResult risultante, a cui fa riferimento la variabile divResult, viene passato a una funzione di utilità, getUnitBBBoxes(). La funzione di utilità restituisce una matrice di rettangoli per qualsiasi tipo di divisione richiesto: segmenti, linee, paragrafi o disegni.

myWordBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Segment, 1);
myLineBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Line, 3);
myParagraphBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Paragraph, 5);
myDrawingBoundingBoxes = getUnitBBoxes(divResult, InkDivisionType.Drawing, 1);

Infine, il pannello del modulo viene forzato a ridisegnare in modo che vengano visualizzati i rettangoli di delimitazione.

DrawArea.Refresh();

Risultati dell'analisi input penna

Nella funzione di utilità l'oggetto DivisionResult viene sottoposto a query per i risultati usando il metodo ResultByType , in base al tipo di divisione richiesto dal chiamante. Il metodo ResultByType restituisce un insieme DivisionUnits . Ogni DivisionUnit nell'insieme rappresenta un disegno, un singolo segmento di riconoscimento della grafia, una linea di grafia o un blocco di grafia, a seconda di ciò che è stato specificato quando è stata chiamata la funzione di utilità.

DivisionUnits units = divResult.ResultByType(divType);

Se è presente almeno una DivisionUnit, viene creata una matrice di rettangoli contenente un rettangolo di delimitazione per unità. I rettangoli vengono gonfiati in base a quantità diverse per ogni tipo di unità, mantenuti nella variabile gonfia, per evitare sovrapposizioni.

// If there is at least one unit, we construct the rectangles
if((null != units) && (0 < units.Count))
{
    // We need to convert rectangles from ink units to
    // pixel units. For that, we need Graphics object
    // to pass to InkRenderer.InkSpaceToPixel method
    using (Graphics g = DrawArea.CreateGraphics())
    {

    // InkSpace to Pixel Space conversion setup done here. 
    // Not shown for brevity.

        // Iterate through the collection of division units to obtain the bounding boxes
        foreach(DivisionUnit unit in units)
        {
            // Get the bounding box of the strokes of the division unit
            divRects[i] = unit.Strokes.GetBoundingBox();

            // Div unit rect Ink space to Pixel space conversion done here. 
            // Not shown for brevity.

            // Inflate the rectangle by inflate pixels in both directions
            divRects[i].Inflate(inflate, inflate);

            // Increment the index
            ++i;
        }

    } // Relinquish the Graphics object
}

Ridisegno del modulo

Quando il ridisegno viene forzato sopra, il codice seguente viene eseguito per disegnare i rettangoli di delimitazione per ogni DivisionUnit nel form intorno all'input penna.

private void DrawArea_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            // Create the Pen used to draw bounding boxes.
            // First set of bounding boxes drawn here are 
            // the bounding boxes of paragraphs.
            // These boxes are drawn with Blue pen.
            Pen penBox = new Pen(Color.Blue, 2);

            // First, draw the bounding boxes for Paragraphs
            if(null != myParagraphBoundingBoxes)
            {
                // Draw bounding boxes for Paragraphs
                e.Graphics.DrawRectangles(penBox, myParagraphBoundingBoxes);
            }

            // Next, draw the bounding boxes for Lines
            if(null != myLineBoundingBoxes)
            {
                // Color is Magenta pen
                penBox.Color = Color.Magenta;
                // Draw the bounding boxes for Lines
                e.Graphics.DrawRectangles(penBox, myLineBoundingBoxes);
            }
            
            // Then, draw the bounding boxes for Words
            if(null != myWordBoundingBoxes)
            {
                // Color is Green
                penBox.Color = Color.Green;
                // Draw bounding boxes for Words
                e.Graphics.DrawRectangles(penBox, myWordBoundingBoxes);
            }
            
            // Finally, draw the boxes for Drawings
            if(null != myDrawingBoundingBoxes)
            {
                // Color is Red pen
                penBox.Color = Color.Red;
                // Draw bounding boxes for Drawings
                e.Graphics.DrawRectangles(penBox, myDrawingBoundingBoxes);
            }
        }

Chiusura del modulo

Il metodo Dispose del modulo elimina gli oggetti InkOverlay, Divider, RecognizerContext e l'insieme Strokes utilizzato nell'esempio.