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 |
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.
The drawing contains four parts:
Graphics.DrawPath()
;Graphics.FillPath()
;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.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;
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 20-Dec-2024 |