2017-10-07 16 views
0

Je travaille sur un programme d'édition d'images. J'ai réussi à trouver comment sélectionner un rectangle à partir d'une image, mais j'aimerais aussi un outil de sélection à main levée. Je devais aller jusqu'à rassembler tous les points de la sélection dans une liste et cela suffirait pour dessiner, mais je dois être capable de déterminer quelles parties de l'image sont en dehors de la sélection et ce qu'il y a dedans.Sélection à main levée, copie de la zone sélectionnée à main levée dans C#

J'ai aussi besoin d'un moyen de m'assurer que la sélection ne se croise pas elle-même, ou si cela se produit, pour que la partie croisée soit fusionnée dans la sélection.

Je ne cherche pas quelqu'un pour le faire pour moi mais je ne sais même pas par où commencer à chercher la réponse.

Existe-t-il une bibliothèque ou un moyen préféré de le faire?

Merci à l'avance enter image description here

Mon code:

L'événement mouseMove:

  if (mdown) 
      { 
       cut_points.Add(e.Location); 

       foreach(Point p in cut_points) 
       { 
        if (p.X < cut.X || cut.X == -1) { cut.X = p.X; } 
        if (p.Y < cut.Y || cut.Y == -1) { cut.Y = p.Y; } 
        if (p.X > cut.X + cut.Width) { cut.Width = p.X - cut.X; } 
        if (p.Y > cut.Y + cut.Height) { cut.Height = p.Y - cut.Y; } 
       } 

       this.Invalidate(); 
      } 

L'événement du tirage:

  using (Brush br = new SolidBrush(Color.FromArgb(120, Color.White))) 
      { 
       e.Graphics.FillRectangle(br, new Rectangle(0, 0, Width, Height)); 
      } 

      //Freehand 
      for (int i = 0; i < cut_points.Count; i++) 
      { 
       if(i < cut_points.Count - 1) 
       { 
        e.Graphics.DrawLine(Pens.Blue, cut_points[i], cut_points[i + 1]); 
        e.Graphics.DrawLine(Pens.Blue, new Point(cut_points[i].X + 1, cut_points[i].Y), new Point(cut_points[i + 1].X + 1, cut_points[i + 1].Y)); 
        e.Graphics.DrawLine(Pens.Blue, new Point(cut_points[i].X, cut_points[i].Y + 1), new Point(cut_points[i + 1].X, cut_points[i + 1].Y + 1)); 
       } 
       else 
       { 
        e.Graphics.DrawLine(Pens.Blue, cut_points[i], cut_points[0]); 
        e.Graphics.DrawLine(Pens.Blue, new Point(cut_points[i].X + 1, cut_points[i].Y), new Point(cut_points[0].X + 1, cut_points[0].Y)); 
        e.Graphics.DrawLine(Pens.Blue, new Point(cut_points[i].X, cut_points[i].Y + 1), new Point(cut_points[0].X, cut_points[0].Y + 1)); 
       } 
      } 

      e.Graphics.DrawRectangle(Pens.Black, cut); 
+1

Rechercher [Point algorithme de polygone] (https://en.wikipedia.org/wiki/Point_in_polygon) et des algorithmes intersection du polygone. –

+0

@ OlivierJacot-Descombes Merci pour le conseil! Je vais regarder dans ce – WolfyD

+1

Vous devriez regarder dans le __powerful GraphicsPath__ et ses diverses méthodes! essayez également d'éviter des appels DrawLine séparés si les lignes doivent être continues; utilisez plutôt DrawLines. Et pour la sélection à main levée, pensez à utiliser DrawCurve. – TaW

Répondre

0

Avec l'aide de OlivierJacot-Descombes et TaW J'ai trouvé la solution dont j'avais besoin. J'ai d'abord commencé avec Raycasting mais cela n'est fiable que dans le cas de polygones non complexes. Après quelques recherches, j'ai trouvé que le numéro de Winding est probablement la meilleure solution pour moi.

J'ai trouvé un site Web où ils expliquent très bien le concept et fournissent le code C pour le calcul du nombre de bobinage ainsi que d'autres fonctions impressionnantes liées à l'infographie. (url: http://geomalgorithms.com/a03-_inclusion.html)

J'ai traduit le code de C en C# et ça marche plutôt bien.

code:

Point p = The point you need to test 
Point[] V = The vertices of the polygon as an array of Points 
//Important to note: This version of the algorithm doesn't handle a closed polygon 
//if the last Point in `V` is not V[0] as well! 
int n = V.Length - 1; 

//Returns Integer value depending on the position 
//of the tested point and a line going through 2 other points. 
//Returns >0 if Point is left of line <0 if Point is right of line and 0 if Point is on line. 
public static int isLeft(Point P0, Point P1, Point P2) 
{ 
    return ((P1.X - P0.X) * (P2.Y - P0.Y) 
     - (P2.X - P0.X) * (P1.Y - P0.Y)); 
} 

//Returns the Winding Number of the Point p against the Polygon V[n + 1] 
//V[] should contain all of the vertices of the polygon, ending with V[0] 
//n should be V.Length - 1; 
//It returns 0 if the point is outside the polygon, and any other value (Positive or negative) if it is inside 
public static int wn_PnPoly(Point P, Point[] V, int n) 
{ 
    int wn = 0; 

    // loop through all edges of the polygon 
    for (int i = 0; i < n; i++) 
    { 
     if (V[i].Y <= P.Y) 
     {   
      if (V[i + 1].Y > P.Y) 
      {  
       if (isLeft(V[i], V[i + 1], P) > 0) 
       { 
        ++wn; 
       } 
      } 
     } 
     else 
     { 
      if (V[i + 1].Y <= P.Y) 
      { 
       if (isLeft(V[i], V[i + 1], P) < 0) 
       { 
        --wn; 
       } 
      } 
     } 
    } 
     return wn; 
}