I've done the following, but the problem that the entire panel double borders are not getting filled correctly. The right and down line for //Inner Border is not Painted.
The target control is Panel
protected override void OnPaint(PaintEventArgs pe)
{
using (SolidBrush brush = new SolidBrush(BackColor))
pe.Graphics.FillRectangle(brush, this.Bounds);
// Inner Border
pe.Graphics.DrawRectangle(new Pen(Color.FromArgb(_InnerBorderColor.R, _InnerBorderColor.B, _InnerBorderColor.G), 1.0f), 1, 1, ClientSize.Width - 1, ClientSize.Height - 1);
using (SolidBrush brush = new SolidBrush(BackColor))
pe.Graphics.FillRectangle(brush, this.Bounds);
// Main Border
pe.Graphics.DrawRectangle(new Pen(Color.FromArgb(_BorderColor.R, _BorderColor.B, _BorderColor.G), 1.0f), 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
}
This is What I got
This is What I need
Edited
You should use this coordinates:
e.Graphics.DrawRectangle(pen1,
this.ClientRectangle.Left, this.ClientRectangle.Top,
this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);
e.Graphics.DrawRectangle(pen2,
this.ClientRectangle.Left + 1, this.ClientRectangle.Top + 1,
this.ClientRectangle.Width - 3, this.ClientRectangle.Height - 3);
Note:
For outer rectangle, you should subtract -1 from original width and height to be visible
To draw inner rectangle, you should draw from 1,1 so the width and height will be 2 point less than outer width and height and since the outer width and height are original width and height -1, so you need subtract -3 from original width and height.
You have multiple bugs. Using Bounds is wrong, that is in parent coordinates, use DisplayRectangle instead. You draw the background twice, neither is necessary, the second one overpaints the inner rectangle. You draw the inner rectangle two pixels too big. You forget to dispose the pens, you tend to get away with it but very ugly bug to diagnose when you don't. And last but not least, this should be done in OnPaintBackground so it doesn't flicker like a cheap motel.
Painting bugs are not that easy to diagnose, best way to go about it is incrementally, one piece at a time.
Corrected code looks like:
protected override void OnPaintBackground(PaintEventArgs pe) {
base.OnPaintBackground(pe);
// Inner Border
using (var pen = new Pen(_InnerBorderColor))
pe.Graphics.DrawRectangle(pen, 1, 1, ClientSize.Width - 3, ClientSize.Height - 3);
// Main Border
using (var pen = new Pen(_BorderColor))
pe.Graphics.DrawRectangle(pen, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
}
You need to subtract 2 from Client.Width/Height
pe.Graphics.DrawRectangle(new Pen(Color.FromArgb(_InnerBorderColor.R, _InnerBorderColor.B, _InnerBorderColor.G), 1.0f), 1, 1, ClientSize.Width - 2, ClientSize.Height - 2);
Related
I need to draw a string in a panel perfectly centered, horizontally and vertically.
Centering horizontally is not a big deal using the MeasureString function.
Bug, the MeasureString function returns a height that takes care of every possible char (like P and p), but not the real height of the actual string.
Here is the sample code I'm using :
using (Graphics gr = Graphics.FromImage(mBackImage))
{
gr.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
gr.FillRectangle(new SolidBrush(BackColor), new Rectangle(0, 0, this.Width, this.Height));
var f = new Font(Font.FontFamily, this.ClientSize.Height, FontStyle.Bold, GraphicsUnit.Pixel);
var sz = gr.MeasureString(Label, f);
var pt = new PointF((this.ClientSize.Width - sz.Width) / 2, (this.ClientSize.Height - sz.Height) / 2);
gr.DrawString(Label, f, new SolidBrush(ForeColor), pt);
}
My target is to draw numbers, and the result is that numbers are drawn a little bit too high.
Even if I change the text from "10" to "P", to "p", and I see that the text stays aligned on a "base line".
I really would like to center the text, depending on the real footprint.
How can I achieve this?
Note: this question is absolutely not duplicate of "Center text for receipt printing", because I'm talking about vertical centering, not horizontal centering.
MeasureString or MeasureCharacterRanges are returning sizes taller than the real printed chars, causing vertical alignment issues.
I would like to draw a vertical line along x=0. I've tried the code below, but instead of all the points being drawn with x=0, they are drawn with x values of 1, 2, 3, 4, 5, respectively. I am able to draw a vertical line at what appears to be any x value other than 0.
The code below also sort of works if I change the x value of any of the points to something other than 0. Is this some sort of bug with the Chart in .NET? Is there a way to draw a vertical line along x=0?
chart1.Series["Series1"].ChartType =
System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
chart1.Series["Series1"].Points.AddXY(0, 0);
chart1.Series["Series1"].Points.AddXY(0, 2.5);
chart1.Series["Series1"].Points.AddXY(0, 5);
chart1.Series["Series1"].Points.AddXY(0, 10);
chart1.Series["Series1"].Points.AddXY(0, 20);
Chart displays incorrectly when all x values are zero
Given a list of x,y coordinates and a known width & height how can the NUMBER of the enclosed areas be determined (in C#)?
For Example:
In this image 5 ENCLOSED AREAS are defined:
Face (1)
Eyes (2)
Nose (1)
Right of face (1)
The list of x,y points would be any pixel in black, including the mouth.
You can use this simple algorithm, based on idea of flood fill with helper bitmap:
// backColor is an INT representation of color at fillPoint in the beginning.
// result in pixels of enclosed shape.
private int GetFillSize(Bitmap b, Point fillPoint)
{
int count = 0;
Point p;
Stack pixels = new Stack();
var backColor = b.GetPixel(fillPoint.X, fillPoint.Y);
pixels.Push(fillPoint);
while (pixels.Count != 0)
{
count++;
p = (Point)pixels.Pop();
b.SetPixel(p.X, p.Y, backColor);
if (b.GetPixel(p.X - 1, p.Y).ToArgb() == backColor)
pixels.Push(new Point(p.X - 1, p.Y));
if (b.GetPixel(p.X, p.Y - 1).ToArgb() == backColor)
pixels.Push(new Point(p.X, p.Y - 1));
if (b.GetPixel(p.X + 1, p.Y).ToArgb() == backColor)
pixels.Push(new Point(p.X + 1, p.Y));
if (b.GetPixel(p.X, p.Y + 1).ToArgb() == backColor)
pixels.Push(new Point(p.X, p.Y + 1));
}
return count;
}
UPDATE
The code above works only this quadruply-linked enclosed areas. The following code works with octuply-linked enclosed areas.
// offset points initialization.
Point[] Offsets = new Point[]
{
new Point(-1, -1),
new Point(-0, -1),
new Point(+1, -1),
new Point(+1, -0),
new Point(+1, +1),
new Point(+0, +1),
new Point(-1, +1),
new Point(-1, +0),
};
...
private int Fill(Bitmap b, Point fillPoint)
{
int count = 0;
Point p;
Stack<Point> pixels = new Stack<Point>();
var backColor = b.GetPixel(fillPoint.X, fillPoint.Y).ToArgb();
pixels.Push(fillPoint);
while (pixels.Count != 0)
{
count++;
p = (Point)pixels.Pop();
b.SetPixel(p.X, p.Y, Color.FromArgb(backColor));
foreach (var offset in Offsets)
if (b.GetPixel(p.X + offset.X, p.Y + offset.Y).ToArgb() == backColor)
pixels.Push(new Point(p.X + offset.X, p.Y + offset.Y));
}
return count;
}
The picture below clearly demonstates what I mean. Also one could add more far points to offset array in order to able to fill areas with gaps.
I've had great success using OpenCV. There is a library for .net called Emgu CV
Here is a question covering alternatives to Emgu CV: .Net (dotNet) wrappers for OpenCV?
That library contains functions for identifying contours and finding properties about them. You can search for cvContourArea to find more information.
If you are looking for a quick solution to this specific problem and want to write your own code rather than reusing others, I do not have an algorithm I could give that does that. Sorry.
There are a couple special cases in the sample image. You would have to decide how to deal with them.
Generally you will start by converting the raster image into a series of polygons. Then it is a fairly trivial matter to calculate area (See Servy's comment)
The special cases would be the side of the face and the mouth. Both are open shapes, not closed. You need to figure out how to close them.
I think this comes down to counting the number of (non-black) pixels in each region. If you choose one pixel that is not black, add it to a HashSet<>, see if the pixels over, under, to the left of and to the right of your chosen pixel, are also non-black.
Everytime you find new non-black pixels (by going up/down/left/right), add them to your set. When you have found them all, count them.
Your region's area is count / (pixelWidthOfTotalDrawing * pixelHeightOfTotalDrawing) multiplied by the area of the full rectangle (depending on the units you want).
Comment: I don't think this looks like a polygon. That's why I was having the "fill with paint" function of simple drawing software on my mind.
I am trying to draw a top view of an IC package, which should look like this (sorry I couldnt even draw it good enough using windows's paint!)
I am using a path obeject, but the result of my path object is no where near what I expect. Atleast the complete rectangle itself draws fine but I have problem to make that top arc you see in my example picture. Would be nice if you can point me to the right place. Here is my code:
private GraphicsPath DrawDilBounds(Size size)
{
var p = new GraphicsPath(FillMode.Alternate);
p.StartFigure();
p.AddLine(0, 0, 0, size.Height);
p.AddLine(0, size.Height, size.Width, size.Height);
p.AddLine(size.Width, size.Height, size.Width, 0);
p.AddLine(size.Width, 0, (size.Width/2) - 10, 0);
p.AddArc(size.Width/2 - 10, 0, 10, 10, 10, 10); //This arc looks like no arc!
p.AddLine((size.Width/2) + 10, 0, 0, 0);
p.CloseFigure();
return p;
}
So what I am doing here is starting some lines from top left corner , to bottom left corner, to right bottom corner and finaly to top right corner, then I added a line from top right corner to the middle of the top , minus 10 pixels then I want to add the arc with width of 20 pixels and then finish the drawing back to the top left corner.
You specify the arc by its bounding box. Using 10 as the radius gives a box of 20 x 20 (you used 10 x 10) whose upper left corner is located at (-10, -10) from the center of the arc (you used (-10, 0)). The last two arguments must be degrees, the starting and ending angle. Since you draw it from left-to-right that will be 0 and 180 degrees (you used 10 and 10). You also fumbled the lengths of the 2 lines at the top, they should be half the width -10 (you used +10). Fix:
p.AddLine(size.Width, 0, (size.Width / 2) + 10, 0);
p.AddArc(size.Width / 2 - 10, -10, 20, 20, 0, 180);
p.AddLine((size.Width / 2) - 10, 0, 0, 0);
Which gets you:
I want to visually join two circles that are overlapping so that
becomes
I already have methods for partial circles, but now I need to know how large the overlapping angle for earch circle is, and I don't know how to do that.
Anyone got an Idea?
Phi= ArcTan[ Sqrt[4 * R^2 - d^2] /d ]
HTH!
Edit
For two different radii:
Simplifying a little:
Phi= ArcTan[Sqrt[-d^4 -(R1^2 - R2^2)^2 + 2*d^2*(R1^2 + R2^2)]/(d^2 +R1^2 -R2^2)]
Edit
If you want the angle viewed from the other circle center, just exchange R1 by R2 in the last equation.
Here is a sample implementation in Mathematica:
f[center1_, d_, R1_, R2_] := Module[{Phi, Theta},
Phi= ArcTan[Sqrt[-d^4-(R1^2-R2^2)^2 + 2*d^2*(R1^2 + R2^2)]/(d^2 +R1^2 -R2^2)]
Theta=ArcTan[Sqrt[-d^4-(R1^2-R2^2)^2 + 2*d^2*(R1^2 + R2^2)]/(d^2 -R1^2 +R2^2)]
{Circle[{center1, 0}, R1, {2 Pi - Phi, Phi}],
Circle[{d, 0}, R2, {Pi - Theta, -Pi + Theta}]}
];
Graphics[f[0, 1.5, 1, 1]]
Graphics[f[0, 1.5, 1, 3/4]]
And...
ImageMultiply[
Binarize#FillingTransform[#],
ImageResize[Import#
"http://i305.photobucket.com/albums/nn235/greeneyedgirlox/blondebabybunny.jpg",
ImageDimensions##]] &#
Rasterize#Graphics[f[0, 1.5, 1, 1], Background -> Black]
:)
Now this will work 100% for you even the figure is ellipse and any number of figures
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen p = new Pen(Color.Red, 2);
Rectangle Fig1 = new Rectangle(50, 50, 100, 50); //dimensions of Fig1
Rectangle Fig2 = new Rectangle(100, 50, 100, 50); //dimensions of Fig2
. . .
DrawFigure(e.Graphics, p, Fig1);
DrawFigure(e.Graphics, p, Fig2);
. . .
//remember to call FillFigure after drawing all figures.
FillFigure(e.Graphics, p, Fig1);
FillFigure(e.Graphics, p, Fig2);
. . .
}
private void DrawFigure(Graphics g, Pen p, Rectangle r)
{
g.DrawEllipse(p, r.X, r.Y, r.Width, r.Height);
}
private void FillFigure(Graphics g, Pen p, Rectangle r)
{
g.FillEllipse(new SolidBrush(this.BackColor), r.X + p.Width, r.Y + p.Width, r.Width - 2 * +p.Width, r.Height - 2 * +p.Width); //Adjusting Color so that it will leave border and fill
}
Don't have the time to solve it right now. But I'll give you what you need to work it out:
http://en.wikipedia.org/wiki/Triangle#The_sine.2C_cosine_and_tangent_rules
In the picture on wikipedia you see the triangle A,B,C. Let A be the center of the left circle, B the center of the right circle. And AC the radius of the left circle and BC the radius of the right circle.
Then point C would be the top intersection point. The corner in A, α, is half the angle in the left circle.The corner in b, β, half the angle in the right circle. These are the angles you need, right?
Wikipedia explains further: 'If the lengths of all three sides of any triangle are known the three angles can be calculated.'
Pseudocode:
a=radius_a
b=radius_b
c=b_x - a_x
alpha=arccos((b^2 + c^2 - a^2) / (2*b*c)) //from wikipedia
left_angle=2*alpha
Good luck :)