Article: GraphicsPath experiment

Home Page


Consultancy

  • Service Vouchers
  • Escrow Service

Shop



Programming
  • Articles
  • Tools
  • Links

Search

 

Contact

 

Chess Puzzles




DWHS

Valid XHTML 1.0 Transitional
Valid CSS!
Mobile-friendly!

Figuring out what Graphics.DrawPath and GraphicsPath.IsVisible() do for self-intersecting paths.

category 'experiment', language C#, created 25-Jan-2010, version V1.0, by Luc Pattyn


License: The author hereby grants you a worldwide, non-exclusive license to use and redistribute the files and the source code in the article in any way you see fit, provided you keep the copyright notice in place; when code modifications are applied, the notice must reflect that. The author retains copyright to the article, you may not republish or otherwise make available the article, in whole or in part, without the prior written consent of the author.

Disclaimer: This work is provided “as is”, without any express or implied warranties or conditions or guarantees. You, the user, assume all risk in its use. In no event will the author be liable to you on any legal theory for any special, incidental, consequential, punitive or exemplary damages arising out of this license or the use of the work or otherwise.


I don't use GraphicsPath very often, and I wanted to figure how it fills, and how it can be used to check for points lying inside or outside of the path. I have chosen a pentagram, which is a star defined by five points; this simple drawing has intersecting edges, leaving some doubt whether the center would be considered inside or not.

GraphicsPath.IsVisible()

The drawing contains four parts:

  • the black dots represent the five points that define the pentagram;
  • the black lines are the result of Graphics.DrawPath();
  • the yellow areas are the result of Graphics.FillPath();
  • the blue and red points are random points; their color depends on the result of GraphicsPath.IsVisible(): the blue ones have IsVisible() true, the red ones false. We can easily see that IsVisible() corresponds to the inside of the path, in the same way as FillPath treats the path.

Program structure

The environment used is the Microsoft .NET Framework (version 2.0 or above) and the C# programming language.

This is the bulk of the code:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace GraphicsPath1 {
	public partial class GraphicsPath1 : Form {
		GraphicsPath path;
		PointF[] testPoints=new PointF[100];
		PointF[] polyPoints=new PointF[5];

		public GraphicsPath1() {
			InitializeComponent();

			int radius=180;
			double toRadians=Math.PI/180;
			path=new GraphicsPath();
			for (int i=0; i<polyPoints.Length; i++) {
				int angle=270+360*2/5*i;
				float x=(float)(radius*Math.Cos(angle*toRadians));
				float y=(float)(radius*Math.Sin(angle*toRadians));
				PointF current=new PointF(x, y);
				Console.WriteLine("point "+current);
				polyPoints[i]=current;
			}
			path.AddPolygon(polyPoints);
			Random random=new Random();
			radius=radius*8/10;
			for (int i=0; i<testPoints.Length; i++) {
				float x=random.Next(-radius, radius);
				float y=random.Next(-radius, radius);
				testPoints[i]=new PointF(x, y);
			}
		}

		[STAThread]
		static void Main() {
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new GraphicsPath1());
		}

		private void panCanvas_Paint(object sender, PaintEventArgs e) {
			if (path!=null) {
				Graphics g=e.Graphics;
				g.TranslateTransform(panCanvas.Width/2, panCanvas.Height/2);
				g.FillPath(Brushes.Yellow, path);
				g.DrawPath(Pens.Black, path);
				foreach (PointF p in testPoints) drawPoint(g, p, path.IsVisible(p)?Brushes.Blue:Brushes.Red);
				foreach (PointF p in polyPoints) drawPoint(g, p, Brushes.Black);
			}
		}

		private void drawPoint(Graphics g, PointF p, Brush brush) {
			int size=5;
			g.FillEllipse(brush, p.X-size, p.Y-size, 2*size, 2*size);
		}
	}
}

And here is the designer-generated code which has to be added to the above to set up the GUI:

		private System.ComponentModel.IContainer components = null;

		protected override void Dispose(bool disposing) {
			if (disposing && (components != null)) {
				components.Dispose();
			}
			base.Dispose(disposing);
		}

		private void InitializeComponent() {
			this.panCanvas = new System.Windows.Forms.Panel();
			this.SuspendLayout();
			// 
			this.panCanvas.BackColor = System.Drawing.Color.White;
			this.panCanvas.Location = new System.Drawing.Point(28, 30);
			this.panCanvas.Name = "panCanvas";
			this.panCanvas.Size = new System.Drawing.Size(400, 400);
			this.panCanvas.TabIndex = 0;
			this.panCanvas.Paint += new System.Windows.Forms.PaintEventHandler(this.panCanvas_Paint);
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(458, 458);
			this.Controls.Add(this.panCanvas);
			this.Name = "Form1";
			this.Text = "GraphicsPath.IsVisible() demo";
			this.ResumeLayout(false);
		}
		private System.Windows.Forms.Panel panCanvas;

Conclusion

GraphicsPath.IsVisible() returns true for points inside the path. Graphics.FillPath() and GraphicsPath.IsVisible() both use the same definition of inside, which seems to correspond to the even/odd rule as presented here.



Perceler

Copyright © 2012, Luc Pattyn

Last Modified 02-Sep-2013