none
Suche so etwas wie DrawClosedCurve um die Objekte im GraphicsPath RRS feed

  • Frage

  • Hallo Leute,
    ich in meinem GraphicsPath sind Kreise und Rechtecke enthalten.
    Das gesamte Gebilde möchte ich gerne umschließen mit einer Linie.
    Gibt es dazu eine Funktion (so etwas wie DrawClosedCurve um die Objekte im GraphicsPath)?

    Grüße
    Wolfgang

    Freitag, 27. Mai 2011 14:04

Antworten

    • Frank schrieb: Wenn man eine engere Umrandung haben möchte, wäre das Aussehen zu klären, wenn sich die Figuren zum Beispiel nicht überschneiden.

    Die GDI+ Flat API stellt dafür bereits eine Methode dafür zur Verfügung, dann quasi die Semantik der minimalsten Fläche benutzt (wie: GdipWindingModeOutline), die kann man auch von C# aus nutzen (in C++ übrigens über GraphicsPath.Outline() zugänglich). Hier ein Beispiel: 

    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WinGraphicsDemo
    {
     public partial class Form1 : Form
     {
     public Form1()
     {
      InitializeComponent();
      Width = 400; Height = 400;
     }
     
     private void Form1_Paint(object sender, PaintEventArgs e)
     {
      GraphicsPath gp = new GraphicsPath();
      gp.AddEllipse(new Rectangle(50, 50, 100, 100));
      gp.AddRectangle(new Rectangle(130, 70, 140, 140));
      Graphics g = e.Graphics;
      g.SmoothingMode = SmoothingMode.AntiAlias;
      g.DrawPath(Pens.DarkBlue, gp);
      UmrissZeichnen(e, gp);
      gp.Dispose();
     }
    
     [DllImport(@"gdiplus.dll")]
     public static extern int GdipWindingModeOutline(
      HandleRef href, IntPtr matrix, float flatness);
    
     Pen umrissFarbe = new Pen(Color.FromArgb(200, Color.Yellow), 5);
    
     void UmrissZeichnen(PaintEventArgs e, GraphicsPath pfad)
     {
      HandleRef href = new HandleRef(pfad,
      (IntPtr)pfad.GetType().GetField("nativePath",
      BindingFlags.NonPublic | BindingFlags.Instance).GetValue(pfad));
      GdipWindingModeOutline(href, IntPtr.Zero, 0.25F);
      e.Graphics.DrawPath(umrissFarbe, pfad);
     }
     }
    }
    
    
     
     

    ciao Frank
    • Als Antwort vorgeschlagen Thorsten Gudera Sonntag, 29. Mai 2011 10:23
    • Als Antwort markiert wolfgangh Montag, 30. Mai 2011 06:38
    Sonntag, 29. Mai 2011 08:24

Alle Antworten

  • Hallo Wolfgang,
    eine rechteckige Umrandung aller Gebilde kannst Du zum Beispiel folgendermaßen erreichen:
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    
    namespace WinGraphicsDemo
    {
     public partial class Form1 : Form
     {
     public Form1()
     {
      InitializeComponent();
      Width = 400; Height = 400;
     }
     Pen umrissFarbe = new Pen(Brushes.Yellow, 5);
    
     private void Form1_Paint(object sender, PaintEventArgs e)
     {
      GraphicsPath gp = new GraphicsPath();
      gp.AddEllipse(new Rectangle(50, 50, 100, 100));
      gp.AddRectangle(new Rectangle(130, 70, 140, 140));
      Graphics g = e.Graphics;
      g.DrawRectangle(umrissFarbe, Rectangle.Truncate(gp.GetBounds()));
      g.DrawPath(Pens.DarkBlue, gp);
      gp.Dispose();
     }
     }
    }
    
    
     

    ----------------

    Wenn man eine engere Umrandung haben möchte, wäre das Aussehen zu klären, wenn sich die Figuren zum Beispiel nicht überschneiden.

     


    ciao Frank
    Samstag, 28. Mai 2011 05:39
  • Hallo,

    das Problem ist, was soll gemacht werden, wenn die Objekte im path sich nicht überschneiden? Sollen dan  zwei, oder mehr, Linien/Kurven gezeichnet werden? Wenn die Objekte zusammenhängen - und die umschließende Kurve nicht intelligent sein soll, dann kannst Du mit folgendem ein wenig herumexperimentieren:

      public partial class Form1 : Form
      {
        GraphicsPath _gPath = null;
    
        public Form1()
        {
          InitializeComponent();
    
          this.Width *= 2;
          this.Height *= 2;
    
          GraphicsPath gPath = new GraphicsPath();
          gPath.AddEllipse(new RectangleF(12, 12, 124, 224));
          gPath.AddEllipse(new RectangleF(212, 12, 124, 224));
    
          //wäre nicht verbunden
          //gPath.AddRectangle(new RectangleF(this.ClientRectangle.Width + 112, 212, 124, 44));
    
          gPath.AddRectangle(new RectangleF(112, 212, 124, 44));
    
          //wäre verbunden
          //gPath.AddEllipse(this.ClientRectangle);
    
          _gPath = gPath;
    
          this.Paint += new PaintEventHandler(Form1_Paint);
          this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
        }
    
        void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
          if (_gPath != null)
            _gPath.Dispose();
        }
    
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
          GraphicsPath gP = (GraphicsPath)_gPath.Clone();
          GraphicsPath gP2 = (GraphicsPath)_gPath.Clone();
    
          gP2.FillMode = FillMode.Winding;
    
          //geweiteten Path zeichnen
          using (Pen p = new Pen(Color.Black, 2))
          {
            gP.Widen(p);
            e.Graphics.DrawPath(p, gP);
          }
    
          //"normalen" Path mit Hintergrundfarbe füllen
          using(SolidBrush b = new SolidBrush(this.BackColor))
            e.Graphics.FillPath(b, gP2);
    
          gP.Dispose();
          gP2.Dispose();
        }
      }

     

    Viele Grüße,

      Thorsten


    Samstag, 28. Mai 2011 21:34
    • Frank schrieb: Wenn man eine engere Umrandung haben möchte, wäre das Aussehen zu klären, wenn sich die Figuren zum Beispiel nicht überschneiden.

    Die GDI+ Flat API stellt dafür bereits eine Methode dafür zur Verfügung, dann quasi die Semantik der minimalsten Fläche benutzt (wie: GdipWindingModeOutline), die kann man auch von C# aus nutzen (in C++ übrigens über GraphicsPath.Outline() zugänglich). Hier ein Beispiel: 

    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WinGraphicsDemo
    {
     public partial class Form1 : Form
     {
     public Form1()
     {
      InitializeComponent();
      Width = 400; Height = 400;
     }
     
     private void Form1_Paint(object sender, PaintEventArgs e)
     {
      GraphicsPath gp = new GraphicsPath();
      gp.AddEllipse(new Rectangle(50, 50, 100, 100));
      gp.AddRectangle(new Rectangle(130, 70, 140, 140));
      Graphics g = e.Graphics;
      g.SmoothingMode = SmoothingMode.AntiAlias;
      g.DrawPath(Pens.DarkBlue, gp);
      UmrissZeichnen(e, gp);
      gp.Dispose();
     }
    
     [DllImport(@"gdiplus.dll")]
     public static extern int GdipWindingModeOutline(
      HandleRef href, IntPtr matrix, float flatness);
    
     Pen umrissFarbe = new Pen(Color.FromArgb(200, Color.Yellow), 5);
    
     void UmrissZeichnen(PaintEventArgs e, GraphicsPath pfad)
     {
      HandleRef href = new HandleRef(pfad,
      (IntPtr)pfad.GetType().GetField("nativePath",
      BindingFlags.NonPublic | BindingFlags.Instance).GetValue(pfad));
      GdipWindingModeOutline(href, IntPtr.Zero, 0.25F);
      e.Graphics.DrawPath(umrissFarbe, pfad);
     }
     }
    }
    
    
     
     

    ciao Frank
    • Als Antwort vorgeschlagen Thorsten Gudera Sonntag, 29. Mai 2011 10:23
    • Als Antwort markiert wolfgangh Montag, 30. Mai 2011 06:38
    Sonntag, 29. Mai 2011 08:24
  • guten Morgen,

    um die offene Frage noch zu klären: die entstehende Figur hat eine geschlossenen Randlinie und hat innen keine "Löcher".
    Die gesuchte .NET-Funktion gibt es wohl dazu nicht, aber der Vorschlag von Frank leistet das laut Beschreibung (habs noch nicht ausprobiert).

    Allen besten Dank für die Antworten
    Wolfgang

     

    Montag, 30. Mai 2011 06:37