2016-11-15 3 views
1

Ich habe eine Liste mit Polylinien (PointCollection) wie in der Grafik gezeigt. Einige Segmente überlappen sich wie die blaue und orange Linie, wie in "Original" gezeigt. Ich weiß schon, welche Segmente das sind. Ich muss die überlappenden Segmente auseinander schieben. Das Schwierige ist, neue Überlappungen mit anderen Zeilen zu vermeiden, wie sie in "falsch" angezeigt werden.Polyline-Shifting-Algorithmus

enter image description here

Ich habe das Problem, dass ich nur die Koordinaten der Knoten und keine Informationen über die Segmente haben. Gibt es eine Möglichkeit zu bestimmen, ob ich einen Knoten auf ein Segment einer anderen Linie verschiebe? Hat jemand eine gute Idee wie ich dieses Problem lösen könnte?

+0

Worauf zielen Sie ab: Winforms, WPF, ASP ..? __Always__ tag Ihre Frage richtig! - Wie willst du umziehen? Manuell oder im Code? Welche Richtung? Nach dem Zufallsprinzip? Sie können eine Trial-and-error-Routine schreiben, die denselben Test verwendet, um die Überlappung zu überprüfen, die Sie zuerst finden müssen. (Hinweis: Sie können die Polylinien zu Grafikpfaden machen und sie zu einer Region kombinieren, die auf Leerheit getestet werden kann.) – TaW

+0

Ich bereite die Daten für ein Drittanbieter-Tool vor und visualisiere es nicht in meiner Anwendung. Ziel ist es, den Knoten nach Code zu verschieben. Meine Idee ist, die Knoten entweder nach links oder nach rechts in Richtung der Winkelhalbierenden zwischen zwei Segmenten zu verschieben. Bevor ich den Knoten verschiebe, möchte ich testen, welche Richtung leer ist. Wie kann ich Polylinien in Grafikpfade konvertieren? – Nindalf

+0

Sie können GDI + Grafiken verwenden und trotzdem nur die Ergebnisse exportieren, ohne tatsächlich etwas anzuzeigen. Zum Testen der Routinen kann ein kleines winforms Projekt eine gute Idee sein ... Sie fügen einfach den Punktarray in einen leeren Grafikpfad ein: 'gp.AddLines (pointlist .ToArray()) '. Um einen GP zu bewegen, benutze eine Matrix und gp.tranform! Erstellen Sie eine Region aus einem gp und testen Sie mit reg.Intersect (gp2) und if (reg.IsEmtpy (Grafikobjekt)) .. – TaW

Antwort

1

Wie in den Kommentaren darauf hingewiesen haben Sie eine Auswahl an

  • das Problem analytisch durch geometrische Berechnungen zu lösen oder von
  • einige + Methoden GDI mit

Hier ist ein Beispiel für letzteres ist:

Zuerst muss Ihre Konsolenanwendung einen Verweis auf System.Drawing und einige using-Klauseln enthalten:

using System.Drawing; 
using System.Drawing.Drawing2D; 
using System.Drawing.Imaging; //optional, used for bitmap saving only 

Hier ist eine statische Funktion, wenn zwei GraphicsPaths Tests schneiden:

static bool intersect(GraphicsPath gp1, GraphicsPath gp2, Graphics g) 
{ 
    using (Region reg = new Region(gp1)) 
    { 
     reg.Intersect(gp2); 
     return !reg.IsEmpty(g); 
    } 
} 

Es dauert zwei GraphicsPaths und aslo ein Graphics Objekt.

Hier ist ein Testbed, um zu demonstrieren, wie man es benutzen kann. Es erzeugt 2 zufällige Polylinien und verschiebt dann die zweite um jeweils 50 Pixel nach rechts, bis sie die erste nicht mehr schneidet.

Alle Stufen werden in eine Bitmap gezeichnet, die gespeichert wird dann ..:

kann

enter image description here

Sie die Bahnpunkte verschoben Zugriff als:

static void Main(string[] args) 
{ 
    int w = 1234; 
    int h = 1234; 

    Random rnd = new Random(0); 
    for (int t = 0; t < 33; t++) 
    { 
     List<Point> l1 = new List<Point>(); 
     List<Point> l2 = new List<Point>(); 
     for (int i = 0; i < 4; i++) 
     { 
      l1.Add(new Point(rnd.Next(1234), rnd.Next(567))); 
      l2.Add(new Point(rnd.Next(567), rnd.Next(1234))); 
     } 

     using (Matrix m = new Matrix()) 
     using (Bitmap bmp = new Bitmap(w, h)) 
     using (Graphics g = Graphics.FromImage(bmp)) 
     using (GraphicsPath gp1 = new GraphicsPath()) 
     using (GraphicsPath gp2 = new GraphicsPath()) 
     { 
      gp1.AddLines(l1.ToArray()); 
      gp2.AddLines(l2.ToArray()); 
      m.Translate(50, 0); 
      bool intersects = intersect(gp1, gp2, g); 
      g.Clear(Color.White); 
      g.DrawPath(Pens.Blue, gp1); 
      g.DrawPath(intersects ? Pens.Red : Pens.Green, gp2); 

      while (intersects) 
      { 
       gp2.Transform(m); 
       intersects = intersect(gp1, gp2, g); 
       g.DrawPath(intersects ? Pens.Red : Pens.Green, gp2); 
       intersects = intersect(gp1, gp2, g); 
      } 


      bmp.Save(@"D:\scrape\x\__xTest_" + t.ToString("000") + ".png", 
        ImageFormat.Png); 

     } 
    } 
} 

Hier einer der Ausgabedateien ist

List<PointF> l3 = gp2.PathPoints.ToList(); 

Beachten Sie, dass Sie entweder diemachen solltengroß genug für Ihre tatsächlichen Zahlen oder skalieren Sie sie und arbeiten Sie mit floats!

+0

Ok, ich mag Ihren Ansatz mit GDI +. Danke für das Beispiel. Meine Idee ist, das Flugzeug zuerst mit den Linien zu bevölkern, die keine Überschneidungen haben. Dann wähle ich das erste eines überlappenden Paares (zum Beispiel das blaue) und zeichne es auch. Als nächstes wähle ich den zweiten (den orangefarbenen) und verschiebe ihn nach rechts. Dann vergleiche ich es mit den bereits gezeichneten Linien, um zu überprüfen, ob ich noch Kreuzungen habe. Wenn ja, verschiebe ich es nach links und wiederhole den Check. Ist das ein guter Ansatz? Ist es möglich, einen GraphicsPath mit dem bereits gezeichneten GraphicsPath in der Ebene zu vergleichen, um nach Kreuzungen zu suchen? – Nindalf

+0

Sicher, legen Sie sie einfach in eine 'List ' und Schleife darüber. Beachten Sie, dass ich sie nur zeichne, um die Idee zu demonstrieren; Sie müssen nicht wirklich zeichnen. Sie brauchen das 'Graphics'-Objekt, um die Funktion aufzurufen, also brauchen Sie auch eine' Bitmap'; aber die ganze Zeichnung ist nicht notwendig! – TaW