Exemple d’effacement manuscrit
Cette application s’appuie sur l’exemple de collection d’encre en illustrant la suppression des traits d’encre. L’exemple fournit à l’utilisateur un menu qui a le choix entre quatre modes : entrée manuscrite activée, effacement à cusp, effacement aux intersections et effacement des traits.
En mode ink-enabled, l’objet InkCollector collecte l’entrée manuscrite comme indiqué dans l’exemple de collection d’encre.
En mode d’effacement, les segments des traits d’encre existants que l’utilisateur touche avec le curseur sont effacés. En outre, les cusps ou intersections peuvent être marqués d’un cercle rouge.
Les parties les plus intéressantes de cet exemple résident dans le InkErase
gestionnaire d’événements du OnPaint
formulaire et dans les fonctions d’effacement appelées à partir du gestionnaire d’événements du OnMouseMove
formulaire.
Faire le tour des cusps et des intersections
Le gestionnaire d’événements du OnPaint
formulaire peint d’abord les traits et, selon le mode d’application, peut trouver et marquer tous les cuspps ou intersections avec un petit cercle rouge. Un cusp marque le point où un trait change brusquement de direction. Une intersection marque un point où un trait se croise avec lui-même ou un autre trait.
L’événement Paint se produit chaque fois qu’un contrôle est redessiné.
Notes
L’exemple force le formulaire à se redessiner chaque fois qu’un trait est effacé ou lorsque le mode d’application change, à l’aide de la méthode Refresh du formulaire.
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;
}
}
Dans PaintCusps
, le code itère à travers chaque cusp de chaque trait et dessine un cercle rouge autour de celui-ci. La propriété PolylineCusps du trait retourne les index des points d’un trait qui correspondent à cusps. Notez également la méthode InkSpaceToPixel de l’objet Renderer, qui convertit le point en coordonnées pertinentes pour la méthode 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);
}
}
}
Dans PaintIntersections
, le code itère à travers chaque trait pour trouver ses intersections avec l’ensemble des traits. Notez que la méthode FindIntersections du trait reçoit une collection Strokes et retourne un tableau de valeurs d’index à virgule flottante représentant les intersections. Le code calcule ensuite une coordonnée X-Y pour chaque intersection et dessine un cercle rouge autour de celle-ci.
private void PaintIntersections(Graphics g, Strokes strokesToPaint)
{
foreach (Stroke currentStroke in strokesToPaint)
{
float[] intersections = currentStroke.FindIntersections(strokesToPaint);
}
}
Gestion d’un stylet qui a deux extrémités
Trois gestionnaires d’événements sont définis pour l’objet InkCollector pour les événements CursorDown, NewPackets et Stroke . Chaque gestionnaire d’événements vérifie la propriété Inverted de l’objet Cursor pour voir quelle extrémité du stylet est utilisée. Lorsque le stylet est inversé :
- La
myInkCollector_CursorDown
méthode rend le trait transparent. - La
myInkCollector_NewPackets
méthode efface les traits. - La
myInkCollector_Stroke
méthode annule l’événement. Les événements NewPackets sont générés avant l’événement Stroke.
Suivi du curseur
Que l’utilisateur utilise un stylet ou une souris, les événements MouseMove sont générés. Le gestionnaire d’événements MouseMove vérifie d’abord si le mode actuel est un mode d’effacement et si un bouton de la souris est enfoncé, puis ignore l’événement si ces états ne sont pas présents. Ensuite, le gestionnaire d’événements convertit les coordonnées de pixels du curseur en coordonnées d’espace d’entrée manuscrite à l’aide de la méthode PixelToInkSpace de l’objet Renderer et appelle l’une des méthodes d’effacement du code en fonction du mode d’effacement actuel.
Effacement des traits
La EraseStrokes
méthode prend l’emplacement du curseur dans l’espace d’entrée manuscrite et génère une collection de traits qui sont en HitTestRadius
unités. Le currentStroke
paramètre spécifie un objet Stroke qui ne doit pas être supprimé. Ensuite, la collection de traits est supprimée du collecteur et le formulaire est redessiné.
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();
}
}
Effacement aux intersections
La EraseAtIntersections
méthode itère sur chaque trait qui se trouve dans le rayon de test et génère un tableau d’intersections entre ce trait et tous les autres traits de la collection. Si aucune intersection n’est trouvée, ce trait entier est supprimé ; dans le cas contraire, le point le plus proche du trait au point d’essai est localisé, et à partir de cela, les intersections de part et d’autre du point sont situées, décrivant le segment à supprimer.
La méthode Split de l’objet Stroke est utilisée pour séparer le segment du reste du trait, puis le segment est supprimé, laissant le reste du trait intact. Comme dans EraseStrokes
, le formulaire est redessiné avant le retour de la méthode.
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]);
...
}
...
}
Effacement à Cusps
Pour chaque trait qui se trouve dans le rayon de test, la EraseAtCusps
méthode récupère le tableau de cusps de la méthode PolylineCusps de l’objet Stroke. Chaque extrémité du trait est également un cusp, donc si le trait n’a que deux cuspps, le trait entier est supprimé ; dans le cas contraire, le point le plus proche du trait au point d’essai est localisé, et à partir de cela, les intersections de part et d’autre du point sont situées, décrivant le segment à supprimer.
La méthode Split de l’objet Stroke est utilisée pour séparer le segment du reste du trait, puis le segment est supprimé, laissant le reste du trait intact. Comme dans EraseStrokes
, le formulaire est redessiné avant le retour de la méthode.
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);
...
}
...
}
Fermeture du formulaire
La méthode Dispose du formulaire supprime l’objet InkCollector , myInkCollector
.