Self-intersecting GraphicsPath with z-order - c#

I need to create a framed GraphicsPath that self-intersects giving a z-order feeling:
The code that I used to obtain the image is the following:
private void Example1(PaintEventArgs e) {
Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));
GraphicsPath path1 = new GraphicsPath(FillMode.Winding);
path1.AddLines(new Point[] {
new Point(400, 200),
new Point(400, 300),
new Point(100, 300),
new Point(100, 400),
new Point(500, 400),
new Point(500, 100)
});
e.Graphics.FillPath(brush, path1);
e.Graphics.DrawPath(Pens.Blue, path1);
GraphicsPath path2 = new GraphicsPath(FillMode.Winding);
path2.AddLines(new Point[] {
new Point(500, 100),
new Point(200, 100),
new Point(200, 500),
new Point(300, 500),
new Point(300, 200),
new Point(400, 200)
});
e.Graphics.FillPath(brush, path2);
e.Graphics.DrawPath(Pens.Blue, path2);
}
in which I draw the two paths independently.
My need is to handle it as a unique graphic object, but if I join the paths I obtain this image:
Example code:
private void Example2(PaintEventArgs e) {
Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));
GraphicsPath path1 = new GraphicsPath(FillMode.Winding);
path1.AddLines(new Point[] {
new Point(400, 200),
new Point(400, 300),
new Point(100, 300),
new Point(100, 400),
new Point(500, 400),
new Point(500, 100)
});
GraphicsPath path2 = new GraphicsPath(FillMode.Winding);
path2.AddLines(new Point[] {
new Point(500, 100),
new Point(200, 100),
new Point(200, 500),
new Point(300, 500),
new Point(300, 200),
new Point(400, 200)
});
path1.AddPath(path2, true);
e.Graphics.FillPath(brush, path1);
e.Graphics.DrawPath(Pens.Blue, path1);
}
Same problem if I use StartFigure/CloseFigure. Maybe I can solve the problem using the SetMarkers method in conjunction with the GraphicsPathIterator, but it seems overwhelming.

The simplest way that I found is to use the GraphicsPathIterator. In this way I can store more figures on a single path and have the flexibility I need during the painting. The only drawback is that the paint method has to be modified accordingly.
Here is an example in which I define the path and that do also the painting:
private void Example4(PaintEventArgs e) {
Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));
GraphicsPath path = new GraphicsPath(FillMode.Winding);
path.StartFigure();
path.AddLines(new Point[] {
new Point(400, 200),
new Point(400, 300),
new Point(100, 300),
new Point(100, 400),
new Point(500, 400),
new Point(500, 100)
});
path.StartFigure();
path.AddLines(new Point[] {
new Point(500, 100),
new Point(200, 100),
new Point(200, 500),
new Point(300, 500),
new Point(300, 200),
new Point(400, 200)
});
GraphicsPathIterator pathIterator = new GraphicsPathIterator(path);
GraphicsPath p = new GraphicsPath();
while (pathIterator.NextSubpath(p, out bool isClosed) > 0) {
e.Graphics.FillPath(brush, p);
e.Graphics.DrawPath(Pens.Blue, p);
}
}

Related

Getting "Argument Exception" while drawing curve

When I was trying to draw curve line in C# windows form application, I got argument exception. Th exception is "Parameter not valid".
Point point1 = new Point(37, 28);
Point point2 = new Point(30, 40);
Point point3 = new Point(23, 35);
Point point4 = new Point(30, 30);
Point point5 = new Point(40, 35);
Point point6 = new Point(40, 40);
Point point7 = new Point(39, 42);
Point[] curvePoints = { point1, point2, point3, point4, point5, point6, point7 };
//e.Graphics.DrawCurve(blackpen, curvePoints);
//Thread.Sleep(10);
Point[] curve = {};
for (nI = 0; nI < 7; nI++)
{
curve = new Point[nI + 1];
curve[nI] = curvePoints[nI];
e.Graphics.DrawCurve(blackpen, curve);
Thread.Sleep(50);
}
g.Dispose();
How to write correctly ...?

C# fill polygon (triangle)

I have problem with draw two polygons.
I want to fill two triangles, but one is greater than the second.
I am using UserControl in winforms.
Code:
Point[] DOWN = new Point[] {new Point(0, 0), new Point(10, 0), new Point(5, 5)};
Point[] UP = new Point[] { new Point(0, 15), new Point(10, 15), new Point(5, 10) };
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
SolidBrush brush = new SolidBrush(Color.FromArgb(253, 198, 19));
e.Graphics.FillPolygon(brush, DOWN);
e.Graphics.FillPolygon(brush, UP);
brush.Dispose();
}
Where is problem?
Try setting the PixelOffsetMode property:
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
using (SolidBrush brush = new SolidBrush(Color.FromArgb(253, 198, 19))) {
e.Graphics.FillPolygon(brush, DOWN);
e.Graphics.FillPolygon(brush, UP);
}
Result:
Try keeping the order counter-clockwise and start from the highest point:
new Point(5, 10), new Point(10, 15), new Point(0, 15)
Tell us if that helped. Sometimes those algorithms don't behave well on border conditions.

Interpolation anomaly during drawing

I have a problem with AntiAliasing smoothing mode and drawing.
Let say I have a signal with min and max values at the same points.
So I want to display it to see where it "thicker".
So the method I use is to draw vertical lines and use antialiasing.
Here is the problem, the rising edge seems to be antialiased, but the falling not.
If I added some noise to the second signal the same thing observable.
Without noise
With noise
![With noise][2]
Can anyone point out what am I missing? Or this problem comes from somewhere else?
Code (moved from comments):
Bitmap drawBitmap = new Bitmap(pictureBox1.Height, _
pictureBox1.Width, _
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics drawGraph;
Point[] pts = new Point[] { new Point(0, 60), new Point(0, 59), new Point(1, 35), _
new Point(1, 47), new Point(2, 25), new Point(2, 35), _
new Point(3, 17), new Point(3, 25), new Point(4, 12), _
new Point(4, 27), new Point(5, 10), new Point(5, 22), _
new Point(6, 10), new Point(6, 11), new Point(7, 11), _
new Point(7, 16), new Point(8, 16), new Point(8, 24), _
new Point(9, 24), new Point(9, 34), new Point(10, 34), _
new Point(10, 46), new Point(11, 46), new Point(11, 59), _
new Point(12, 59), new Point(12, 72)};
using (drawGraph = Graphics.FromImage(drawBitmap)) {
drawGraph.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic;
drawGraph.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias;
for (int i = 1; i < pts.Length - 1; i += 2) {
drawGraph.DrawLine(new Pen(Color.Black, 1), pts[i], pts[i - 1]);
drawGraph.DrawLine(new Pen(Color.Black, 1), pts[i], pts[i + 1]);
}
}
pictureBox1.Image = drawBitmap;
Apply a pixel offset mode as well:
drawGraph.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality;
The InterpolationMode can be removed as it do nothing with lines (only with images when resized).

Graphics from windows forms to Silverlight?

The following code works for windows forms.
How can I do this to Silverlight?
I guess there is no graphics object.
Bitmap bm = new Bitmap(600, 600);
Graphics g = Graphics.FromImage(bm);
Brush b = new LinearGradientBrush(
new Point(1, 1), new Point(600, 600),
Color.White, Color.Red);
Point[] points = new Point[]
{new Point(10, 10),
new Point(77, 500),
new Point(590, 100),
new Point(250, 590),
new Point(300, 410)};
g.FillPolygon(b, points);
bm.Save("testandoImagem.jpg", ImageFormat.Jpeg);
Alan, even from a SL client application you can do this all server side, you are not showing anything in the User Interface, I would put this code in the business layer which has full access to the .NET Framework. Keep in mind that from SL you can't save on the client machine directly so you should use another way.
You could render the shape as a WriteableBitmap, but Silverlight does not have built in support for encoding the data to JPEG.
See these StackOverflow questions:
How to save BitmapImage / WriteableBitmap using SaveFileDialog in Silverlight 3.0?
Best Jpeg Encoder for Silverlight 4.0
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.render(v=VS.95).aspx
WriteableBitmap wb = new WriteableBitmap(600, 600);
Polygon p = new Polygon();
p.Points = new PointCollection() { new Point(10, 10), new Point(77, 500), new Point(590, 100), new Point(250, 590), new Point(300, 410) };
p.Fill = new LinearGradientBrush()
{
//Gradient angle is 0,0 to 1,1 by default
GradientStops = new GradientStopCollection() {
new GradientStop() { Color = Colors.White, Offset = 0 },
new GradientStop() { Color = Colors.Red, Offset = 1 } }
};
wb.Render(p, null);
wb.Invalidate();
//Save WriteableBitmap as described in other questions

Drawing polygon with more than one hole?

I'm trying to draw a polygon with more than one holes. I tried the following code and it does not work correctly. Please advise.
PointF[] mypoly = new PointF[6 + 5 + 5];
mypoly[0] = new PointF(0, 0);
mypoly[1] = new PointF(100, 0);
mypoly[2] = new PointF(100, 100);
mypoly[3] = new PointF(0, 100);
mypoly[4] = new PointF(10, 80);
mypoly[5] = new PointF(0, 0);
mypoly[6] = new PointF(10, 10);
mypoly[7] = new PointF(10, 20);
mypoly[8] = new PointF(20, 20);
mypoly[9] = new PointF(20, 10);
mypoly[10] = new PointF(10, 10);
mypoly[11] = new PointF(40, 10);
mypoly[12] = new PointF(40, 20);
mypoly[13] = new PointF(60, 20);
mypoly[14] = new PointF(60, 10);
mypoly[15] = new PointF(40, 10);
g.FillPolygon(new SolidBrush(Color.Red), mypoly, FillMode.Winding);
The first part is the outer polygon. The second and the third parts are the two holes inside the polygon.
Use a GraphicsPath instead. You can draw it with Graphics.FillPath, like this:
using System.Drawing.Drawing2D;
...
using (var gp = new GraphicsPath()) {
PointF[] outer = new PointF[] { new PointF(0, 0), new PointF(100, 0),
new PointF(100, 100), new PointF(0, 100), new PointF(10, 80),new PointF(0, 0) };
gp.AddPolygon(outer);
PointF[] inner1 = new PointF[] { new PointF(10, 10), new PointF(10, 20),
new PointF(20, 20), new PointF(20, 10), new PointF(10, 10) };
gp.AddPolygon(inner1);
PointF[] inner2 = new PointF[] { new PointF(40, 10), new PointF(40, 20),
new PointF(60, 20), new PointF(60, 10), new PointF(40, 10) };
gp.AddPolygon(inner2);
e.Graphics.FillPath(Brushes.Black, gp);
}

Categories