HELP: How to get the outline GraphicsPath?

  • Thread starter Thread starter Altramagnus
  • Start date Start date
A

Altramagnus

I have n number of circles. Some of them might overlap.
I need to draw the outline of all circles but not those overlap areas.

Initially, I am try to use a Region, because a Region object has a Union
function
Creating a GraphicsPath of 1 circle is easy. So I convert each GraphicsPath
to a Region and then Union them.
But I could not get back a GraphicsPath of the Unioned Region.

Does anyone know how to solve my problem?
Thanks.
 
This is an example of a classic graphics problem known as the "convex hull"
problem. Try a search on groups.google.com on that search term, limiting it
to the microsoft .Net groups, and see what you come up with.

Regards,
Tom Dacon
Dacon Software Consulting
 
Correct me if I am wrong, but it seems a bit different.

The circles might not overlap at all, so I might end up with a graphicspath
that consists of difference circles.

The Convex Hull problem seems to me it is finding the set of points that
encompasses
the rest of the points.

Moreover I could not find anything on the microsoft .NET groups
I searched the Web instead.

Thanks anyway.

Regards,
Altramagnus
 
Surprisingly it is extremely easy implementing in Java.
I did the following 2 test codes:

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;

public class TestShape {
private static class DisplayComponent extends JComponent {
private Shape s;
private GeneralPath p = new GeneralPath();
private Area a;

public DisplayComponent() {
this.setSize( 500, 500 );
this.setPreferredSize( new Dimension( 500, 500 ) );
p.append( new Ellipse2D.Double( 50, 50, 50, 50 ), false );
p.append( new Ellipse2D.Double( 75, 75, 50, 50 ), false );
p.append( new Ellipse2D.Double( 150, 150, 50, 50 ), false );
a = new Area( p );
} // end DisplayComponent

public void paintComponent( Graphics g ) {
Graphics2D g2d= (Graphics2D)g;
g2d.setColor( new Color( 255, 0, 0 ) );
g2d.draw( a );
} // end paintComponent
} // end clas

public static void main( String[] args ) {
JFrame frame = new JFrame();
DisplayComponent c = new DisplayComponent();
frame.getContentPane().add( c );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.show();
} // end main
} // end class TestShape

The corresponding CSharp test program.

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

namespace TestGraphicsPath
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.PictureBox pictureBox1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(55, 35);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(670, 410);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.Paint += new
System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(832, 553);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void pictureBox1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
GraphicsPath p1 = new GraphicsPath();
GraphicsPath p2 = new GraphicsPath();
GraphicsPath p3 = new GraphicsPath();
p1.AddEllipse( 50, 50, 50, 50 );
p2.AddEllipse( 75, 75, 50, 50 );
p3.AddEllipse( 150, 150, 50, 50 );
Region r = new Region( p1 );
r.Union( p2 );
r.Union( p3 );
g.FillRegion( Brushes.White, r );
}
}
}


For java, Area is the Region equivalent.
Java , you call call graphics.draw( Area ) and it will draw the outline of
the area.
In CSharp, there isn't graphics.draw( Region ) there is only
graphics.Fill( Region )

I wonder how Java does it.
It does not seem to have much computing effort like the convex hull problem.

Thanks. However, I still need help to implement in CSharp.

Regards,
Altramagnus
 
If you create the GraphicsPath with the winding fillmode you don't need to
do all that with the three regions and the union.

GraphicsPath gp=new GraphicsPath(FillMode.Winding);
gp.AddEllipse(....);
gp.AddEllipse(....);
gp.AddEllipse(....);
e.Graphics.FillPath(Brushes.Black,gp);


--
Bob Powell [MVP]
Visual C#, System.Drawing

The Image Transition Library wraps up and LED style instrumentation is
available in the June of Well Formed for C# or VB programmers
http://www.bobpowell.net/currentissue.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm

The GDI+ FAQ RSS feed: http://www.bobpowell.net/faqfeed.xml
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tipstricks.xml
Bob's Blog: http://bobpowelldotnet.blogspot.com/atom.xml






Altramagnus said:
Surprisingly it is extremely easy implementing in Java.
I did the following 2 test codes:

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;

public class TestShape {
private static class DisplayComponent extends JComponent {
private Shape s;
private GeneralPath p = new GeneralPath();
private Area a;

public DisplayComponent() {
this.setSize( 500, 500 );
this.setPreferredSize( new Dimension( 500, 500 ) );
p.append( new Ellipse2D.Double( 50, 50, 50, 50 ), false );
p.append( new Ellipse2D.Double( 75, 75, 50, 50 ), false );
p.append( new Ellipse2D.Double( 150, 150, 50, 50 ), false );
a = new Area( p );
} // end DisplayComponent

public void paintComponent( Graphics g ) {
Graphics2D g2d= (Graphics2D)g;
g2d.setColor( new Color( 255, 0, 0 ) );
g2d.draw( a );
} // end paintComponent
} // end clas

public static void main( String[] args ) {
JFrame frame = new JFrame();
DisplayComponent c = new DisplayComponent();
frame.getContentPane().add( c );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.show();
} // end main
} // end class TestShape

The corresponding CSharp test program.

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

namespace TestGraphicsPath
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.PictureBox pictureBox1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(55, 35);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(670, 410);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.Paint += new
System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(832, 553);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void pictureBox1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
GraphicsPath p1 = new GraphicsPath();
GraphicsPath p2 = new GraphicsPath();
GraphicsPath p3 = new GraphicsPath();
p1.AddEllipse( 50, 50, 50, 50 );
p2.AddEllipse( 75, 75, 50, 50 );
p3.AddEllipse( 150, 150, 50, 50 );
Region r = new Region( p1 );
r.Union( p2 );
r.Union( p3 );
g.FillRegion( Brushes.White, r );
}
}
}


For java, Area is the Region equivalent.
Java , you call call graphics.draw( Area ) and it will draw the outline of
the area.
In CSharp, there isn't graphics.draw( Region ) there is only
graphics.Fill( Region )

I wonder how Java does it.
It does not seem to have much computing effort like the convex hull problem.

Thanks. However, I still need help to implement in CSharp.

Regards,
Altramagnus


Tom Dacon said:
This is an example of a classic graphics problem known as the "convex hull"
problem. Try a search on groups.google.com on that search term, limiting it
to the microsoft .Net groups, and see what you come up with.

Regards,
Tom Dacon
Dacon Software Consulting
 
Thanks Bob.
I think there is a misunderstanding.

I need to draw the outline, not to paint the entire region.

The java program is able to draw the outline, but I could not do it with C#.
With C#, I can only paint the region.

Correction. I have 3 graphicspaths and only 1 region not 3 regions.
Yes, I agree that your program will have the same effect as mine.
But what I need is to draw only the outline.

Thanks.

Regards,
Altramagnus



Bob Powell said:
If you create the GraphicsPath with the winding fillmode you don't need to
do all that with the three regions and the union.

GraphicsPath gp=new GraphicsPath(FillMode.Winding);
gp.AddEllipse(....);
gp.AddEllipse(....);
gp.AddEllipse(....);
e.Graphics.FillPath(Brushes.Black,gp);


--
Bob Powell [MVP]
Visual C#, System.Drawing

The Image Transition Library wraps up and LED style instrumentation is
available in the June of Well Formed for C# or VB programmers
http://www.bobpowell.net/currentissue.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdiplus_faq.htm

The GDI+ FAQ RSS feed: http://www.bobpowell.net/faqfeed.xml
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tipstricks.xml
Bob's Blog: http://bobpowelldotnet.blogspot.com/atom.xml






Altramagnus said:
Surprisingly it is extremely easy implementing in Java.
I did the following 2 test codes:

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;

public class TestShape {
private static class DisplayComponent extends JComponent {
private Shape s;
private GeneralPath p = new GeneralPath();
private Area a;

public DisplayComponent() {
this.setSize( 500, 500 );
this.setPreferredSize( new Dimension( 500, 500 ) );
p.append( new Ellipse2D.Double( 50, 50, 50, 50 ), false );
p.append( new Ellipse2D.Double( 75, 75, 50, 50 ), false );
p.append( new Ellipse2D.Double( 150, 150, 50, 50 ), false );
a = new Area( p );
} // end DisplayComponent

public void paintComponent( Graphics g ) {
Graphics2D g2d= (Graphics2D)g;
g2d.setColor( new Color( 255, 0, 0 ) );
g2d.draw( a );
} // end paintComponent
} // end clas

public static void main( String[] args ) {
JFrame frame = new JFrame();
DisplayComponent c = new DisplayComponent();
frame.getContentPane().add( c );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.show();
} // end main
} // end class TestShape

The corresponding CSharp test program.

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

namespace TestGraphicsPath
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.PictureBox pictureBox1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(55, 35);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(670, 410);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.Paint += new
System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(832, 553);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void pictureBox1_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
GraphicsPath p1 = new GraphicsPath();
GraphicsPath p2 = new GraphicsPath();
GraphicsPath p3 = new GraphicsPath();
p1.AddEllipse( 50, 50, 50, 50 );
p2.AddEllipse( 75, 75, 50, 50 );
p3.AddEllipse( 150, 150, 50, 50 );
Region r = new Region( p1 );
r.Union( p2 );
r.Union( p3 );
g.FillRegion( Brushes.White, r );
}
}
}


For java, Area is the Region equivalent.
Java , you call call graphics.draw( Area ) and it will draw the outline of
the area.
In CSharp, there isn't graphics.draw( Region ) there is only
graphics.Fill( Region )

I wonder how Java does it.
It does not seem to have much computing effort like the convex hull problem.

Thanks. However, I still need help to implement in CSharp.

Regards,
Altramagnus


Tom Dacon said:
This is an example of a classic graphics problem known as the "convex hull"
problem. Try a search on groups.google.com on that search term,
limiting
it
to the microsoft .Net groups, and see what you come up with.

Regards,
Tom Dacon
Dacon Software Consulting

I have n number of circles. Some of them might overlap.
I need to draw the outline of all circles but not those overlap areas.

Initially, I am try to use a Region, because a Region object has a Union
function
Creating a GraphicsPath of 1 circle is easy. So I convert each
GraphicsPath
to a Region and then Union them.
But I could not get back a GraphicsPath of the Unioned Region.

Does anyone know how to solve my problem?
Thanks.
 
Yep, you're right. Sorry about that.

Tom

Altramagnus said:
Correct me if I am wrong, but it seems a bit different.

The circles might not overlap at all, so I might end up with a graphicspath
that consists of difference circles.

The Convex Hull problem seems to me it is finding the set of points that
encompasses
the rest of the points.

Moreover I could not find anything on the microsoft .NET groups
I searched the Web instead.

Thanks anyway.

Regards,
Altramagnus
 
Back
Top