I am working on a program which I want to draw diode curves in a WinForms application. I have a list of diode names and I have theire points as you can see at the right side of the picture. That is Voltage as X and Current as Y ( A curve contains like 50 points).
What I want to do is by selecting one or more diodes from the list theire curve show up on my plot. What you see is just a picture box at the moment filled with a bmp. I know that this is not a reliable solution, so I am asking you what can be the best approach to do such thing? I dont know any good component which can make me do this. So I just need to know what can be the best approuch for this task?
A diode curve is something like:
I might have up to 100 of diode curves in my program which all of them (single or multiple) should be drawn by clicking on them in the list.
So what you think?
UPDATE
ALSO important thing is by deselecting a pin in the curve, its curve should be removed from the plot!
I am drawing that axis you see using the code below:
Bitmap xyCords = new Bitmap(500, 500);
Graphics g = Graphics.FromImage(xyCords);
g.DrawLine(penAxis, 250, 0, 250, 500);
g.DrawLine(penAxis, 0, 250, 500, 250);
curveBox.Image = xyCords;
how is it possible later if I made a new Graphics I append it like:
curveBox.Image += newGraphic;
** Please let me know if there is any component or something which already can do what I want. or else show me a good approach! Thanks!
Try using Graphics.DrawCurve. You just put all of the points you want in an array, and pass that and a pen to the method.
Edit:
Add this after your code to prove to yourself that both graphs coexist. To erase one or the other, just plot the same points, but in the background color of the bitmap (test for it, I don't remember what it is).
Point[] ptarray = new Point[3];
ptarray[0] = new Point(250, 250);
ptarray[1] = new Point(300, 300);
ptarray[2] = new Point(350, 400);
Pen pengraph = new Pen(Color.Green, 0.75F);
g.DrawCurve(pengraph, ptarray);
Point[] ptarray2 = new Point[3];
ptarray2[0] = new Point(100, 100);
ptarray2[1] = new Point(200, 150);
ptarray2[2] = new Point(250, 250);
Pen pengraph2 = new Pen(Color.Yellow, 1.25F);
g.DrawCurve(pengraph2, ptarray2);
Related
I am new to drawing and paints in c# & I am trying to make a simple program it has 3 intersecting circles (A,B,C). What i want to do is paint a certain (according to result I get).
For example: If I get 1 as a result I want to fill the yellow bordered region, if I get 4 I want to fill green bordered region and so on.
My Code to draw these circles:
private void button1_Click(object sender, EventArgs e)
{
Graphics A = this.CreateGraphics();
Graphics B = this.CreateGraphics();
Graphics C = this.CreateGraphics();
Pen Bluepen = new Pen(Color.Blue, 2);
Pen RedPen = new Pen(Color.Red, 2);
Pen BlackPen = new Pen(Color.Black, 2);
A.DrawEllipse(Bluepen,100, 100, 150, 150);
B.DrawEllipse(RedPen, 195, 100, 150, 150);
C.DrawEllipse(BlackPen, 145, 190, 150, 150);
}
Since you are new to this topic I have to tell you: This is a lot harder that one would hope for.
Three solutions come to mind:
Construct a GraphicsPath you could fill from three Arcs. To calculate the arcs you need the rectangles you have but also the sweeping angle and also the starting angle. This will take quite some math..
After having drawn into a Bitmap you could floodfill the area you want to color. This will only work for bitamps from which you can extract the current color of each pixel, not for drawing onto controls..
The simplest way it still a bit involved, but only mildly so
Solution 3 (Create a Region and fill it)
You can use all sorts of set operations to combine areas called Regions. And you can construct a Region from a GraphicsPath. And you can construct a GraphicsPath by adding an ellipse. And you can clip the drawing area of a Graphics object to a Region.
Let's try:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle r1 = new Rectangle(100, 100, 150, 150);
Rectangle r2 = new Rectangle(195, 100, 150, 150);
Rectangle r3 = new Rectangle(145, 190, 150, 150);
GraphicsPath gp1 = new GraphicsPath();
GraphicsPath gp2 = new GraphicsPath();
GraphicsPath gp3 = new GraphicsPath();
gp1.AddEllipse(r1);
gp2.AddEllipse(r2);
gp3.AddEllipse(r3);
Region r_1 = new Region(gp1);
Region r_2 = new Region(gp2);
Region r_3 = new Region(gp3);
r_1.Intersect(r_2); // just two of five..
r_1.Exclude(r_3); // set operations supported!
g.SetClip(r_1, CombineMode.Replace);
g.Clear(Color.Magenta); // fill the remaining region
g.ResetClip();
g.DrawEllipse(Pens.Red, r1);
g.DrawEllipse(Pens.Blue, r2);
g.DrawEllipse(Pens.Green, r3);
// finally dispose of all Regions and GraphicsPaths!!
r_1.Dispose();
gp1.Dispose();
.....
}
Do note that the region operations change the current region; if you want to fill more areas you need to restore the changed region!
Also note that I draw where any persistent drawing belongs: In the Paint event and that I use its e.Graphics object..
GraphicsPaths as Regions are GDI objects and should be disposed off!
Notes on solution 1 (Create a GraphicsPath by Math)
The full math is rather involved. By making a few assumptions the task can be greatly simplified: Let's assume the circles have the same size. Also that we first look at two circles only, with the same y-position. Finally that the circles form a symmetrical figure. (Which btw they don't: the red circle should have x=190 and the green one y=186,45..)
Getting the two intersection points as well as the sweeping angle is not so hard.
Next one can rotate the two points twice around the center of the whole figure by 120° using a Matrix; see here for an example. Now we have six points; we still need the smaller sweeping angle, which is also found with simple math.
Finally we can construct all 12 (!) GraphicsPaths from the 12 arcs and combine them at will.
The good part is that we can both fill and draw those paths. But, the code is rather extensive..
Notes on solution 2 (floodfill)
While you can't floodfill directly on a control you can prepare the result in a bitmap and then display that image on the control with Graphics.DrawImage.
For an example of coding a floodfill see this post!
I'm trying to draw half and partial circles (all BLACK lines) on a bitmap.
My INTENDED result looks like this:
My CURRENT result looks like this:
I've tried so many different alternatives but it nevers looks right.
using (var b = new Bitmap(200, 100, PixelFormat.Format24bppRgb))
{
using (var g = Graphics.FromImage(b))
{
g.FillRectangle(new SolidBrush(Color.LightGray), 0, 0, 200, 100);
// RED COLOR
Rectangle rec = new Rectangle(-15, 50, 70, 100);
g.DrawRectangle(new Pen(Color.Red, 1f), rec);
g.DrawArc(new Pen(Color.Red, 3f), rec, 50, 100);
// WHITE COLOR
Rectangle rec = new Rectangle(10, 50, 70, 70);
g.DrawRectangle(new Pen(Color.White, 1f), rec);
g.DrawEllipse(new Pen(Color.White, 3f), rec);
}
}
But it always look totally wrong and after hours of playing with the numbers, I could not find a way to control the output.
Question:
Is there a simple way to design the 3 black lines on my INTENDED image in a graphic object using C# ??
The easy way to achieve this is to draw three concentric circles and let clipping take care of the fact that two of them fall outside the drawing region.
The way to achieve the arc-based drawing you want is probably to start with the concentric circles (so you know you have the rects in the right places), and then change the DrawEllipse to DrawArc, setting the start and sweep angles to the right values.
Start angle is measured in degrees from the x axis (horizontal line towards the right of the circle's centre), so for the smaller arc you will need an angle approximately 305 degrees. From there you need it to draw for about 90 degrees. The outer arc will be similar, but a smaller arc, so it might go from about 330 degrees for a sweep of about 60 degrees.
It seems the solution is to draw a rectangle outside the boundaries of the bitmap and use the graphic.DrawEllipse method to draw the curve line.
Here is a snippet of the working code:
Pen pen = new Pen(Color.White);
Rectangle rec = new Rectangle(-30, 50, 100, 100);
g.DrawEllipse(pen, rec);
rec = new Rectangle(-30, 10, 150, 150);
g.DrawEllipse(pen, rec);
rec = new Rectangle(-30, -30, 200, 200);
g.DrawEllipse(pen, rec);
Many thanks to Hans Passant to point me to this line of thinking.
I have a paint program made in C#/GDI+ in which I draw different shapes with interchangeable colors and pen sizes on a panel. I have got the shape-drawing methods working OK, but when it comes to using a free pen (as you would in MS Paint) I have made a method that does the job, just quite ugly (see pic in link).
if (crtanje)
{
debljina = float.Parse(debljina_box.Text);
Graphics gr = Graphics.FromImage(bit);
gr.SmoothingMode = SmoothingMode.HighQuality;
olovka = new Pen(boja, debljina);
gr.DrawLine(olovka, new Point(prethodnoX ?? e.X, prethodnoY ?? e.Y), new Point(e.X, e.Y));
panel1.CreateGraphics().DrawImageUnscaled(bit, new Point(0, 0));
prethodnoX = e.X;
prethodnoY = e.Y;
}
Can this code be fixed to make drawing smoother or should I take some other approach?
the pic
I suppose you could iterate through a for loop and increase it by a very small amount so that it draws points more frequently and makes the line smoother. You could save the current point and calculate the next one, then draw a line between them. That's how you could make it smoother!
I'm using .NET to draw a diagram, and I want to highlight objects when the user performs a click on them. It is easy when a figure is fully contained in a rectangle:
if (figure.Bounds.Contains(p)) // bounds is a rectangle
But I don't know how to manage it if the figure is a complex GraphicsPath.
I have defined the following GraphicsPath for the figure (the green circle).
I want to highlight the figure when the user click on it. I would like to know if a Point is contained in that GraphicsPath.
Any ideas? Thanks in advance.
I don't know a DrawingPath (you mean probably; graphics.DrawPath) but a GraphicsPath has the IsVisible method to check if a point is in the path.
bool isInPath = graphicsObj.IsVisible(point)
Using both .IsOutlineVisible and .IsVisible together cover the whole thing, border and within border, for this rectangle example, but as you know GraphicsPath can works for different shapes.
bool b = gp.IsVisible(point) || gp.IsOutlineVisible(point, pen);
For it in code
Rectangle r = new Rectangle(new Point(50, 100), new Size(500, 100));
bool b;
// say Point p is set.
// say Pen pen is set.
using (var gp = new GraphicsPath())
using (var pen = new Pen(Color.Black, 44)) {
gp.AddRectangle(r);
bool b = gp.IsVisible(point) || gp.IsOutlineVisible(point, pen);
}
I've looked everywhere and googled everything and couldn't find anything good.
What I need is a class that is able to draw an image (graphics) with rounded corners (different on each corner is a plus) with a border and gradient fill.
All the examples I find have some flaws (like bad quality, missing functionality etc).
I will use this with a ashx that will draw the image and then show it to the user.
Thanks!
The GraphicsPath allows you to draw relatively free form shapes which you can then fill with a gradient brush. The below example code will create a rectangle with two differntly rounded corners and a gradient fill.
GraphicsPath gp = new GraphicsPath();
gp.AddLine(new Point(10, 10), new Point(75, 10));
gp.AddArc(50, 10, 50, 50, 270, 90);
gp.AddLine(new Point(100, 35), new Point(100, 100));
gp.AddArc(80, 90, 20, 20, 0, 90);
gp.AddLine(new Point(90, 110), new Point(10, 110));
gp.AddLine(new Point(10, 110), new Point(10, 10));
Bitmap bm = new Bitmap(110, 120);
LinearGradientBrush brush = new LinearGradientBrush(new Point(0, 0), new Point(100, 110), Color.Red, Color.Yellow);
using (Graphics g = Graphics.FromImage(bm))
{
g.FillPath(brush, gp);
g.DrawPath(new Pen(Color.Black, 1), gp);
g.Save();
}
bm.Save(#"c:\bitmap.bmp");
This result in the following image:
I think you'll need to create your own method, using a graphics object and "manually" (read "with code") create the image. Easiest way would be to create a single graphics object, add a circle, then in each quadrant of the image add the extras you need, then split the object into fourths. Or return the whole thing as one image then use CSS sprites to place the image in the right spots with the right coordinates (probably the better solution as it uses less calls to the graphics library and returns just one file, so less calls to the web server).