I am trying to spread panels (9 in my example) on a circle that I have drawn.
I am using c# winforms.
I have tried many variations of my code but I'm not getting what I want and started to get confused.
Eventually I want something like that:
I am not really sure how to put the center of my panels on the corresponding points on the circle using the angles.
Here's my code:
public partial class Form1 : Form
{
List<Panel> plist = new List<Panel>();
Rectangle circ_rect = new Rectangle();
const int Num_Screens = 9;
const int margin = 15;
public Form1()
{
InitializeComponent();
WindowState = FormWindowState.Maximized;
}
private void Generate_Panels()
{
for (int i = 0; i < 9; i++)
{
Panel p = new Panel();
p.BackColor = Color.LightSkyBlue;
p.Size = new Size(250, 150);
p.BorderStyle = BorderStyle.FixedSingle;
p.Name = "panel_" + ((i + 1).ToString());
plist.Add(p);
}
}
private void Generate_Circle()
{
//Create panels
Generate_Panels();
//Set circle coord
Point circ_center = new Point(Width / 2, Height / 2);
Size circ_Size = new Size(Height - margin, Height - margin);
circ_center = new Point((circ_center.X - (circ_Size.Width / 2)),
(circ_center.Y - (circ_Size.Height / 2)));
circ_rect = new Rectangle(circ_center, circ_Size);
float radius = circ_Size.Width / 2;
float angle = 0.0f;
Point loc = Point.Empty;
Point rect_center = Point.Empty;
for (int i = 0; i < plist.Count; i++)
{
rect_center = new Point((plist[i].Width / 2), (plist[i].Height / 2));
angle = 360 * ((i + 1f) / 9);
loc.X = (int)(radius * Math.Cos(angle * Math.PI / 180)) + circ_center.X;
loc.Y = (int)(radius * Math.Sin(angle * Math.PI / 180)) + circ_center.Y;
plist[i].Location = new Point(loc.X - (plist[i].Width / 2) + circ_rect.X,
loc.Y - (plist[i].Height / 2) + circ_rect.Y);
this.Controls.Add(plist[i]);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(Pens.Red, circ_rect);
}
private void Form1_Load(object sender, EventArgs e)
{
Generate_Circle();
}
}
Having r as radius of a circle with center of (0,0) in a Cartesian coordinate system, we can calculate coordinate of a on the circle based on the angle:
x = r * cos(degree) and y = r * sin(degree)
In C# Sin and Cos methods, accept radians, so we should convert degree to radians using the following formula.
radians = Math.PI * degree / 180.0
The next step is converting the Cartesian coordinate system values to the form coordinate values:
panel.X = x + center.X - panel.Width/2
panel.Y = center.Y - y - panel.Height/2
The next step is calculating the angles. You can set angles manually or you can calculate them by setting an angle as start angle (like 90) and adding a value (like 40, 360/count) as step to the angles.
Example
public partial class Form1 : Form {
Rectangle circle;
List<Panel> panels;
List<int> angles;
public Form1() {
InitializeComponent();
ResizeRedraw = true;
angles = Enumerable.Range(0, 9).Select(x => 90 + x * 40).ToList();
panels = Enumerable.Range(0, 9).Select(x => new Panel() {
Size = new Size(100, 40),
BackColor = Color.LightSkyBlue
}).ToList();
this.Controls.AddRange(panels.ToArray());
}
protected override void OnLayout(LayoutEventArgs levent) {
base.OnLayout(levent);
int padding = 50;
int radius = Math.Min(ClientSize.Width, ClientSize.Height) / 2 - padding;
Point center = new Point(ClientSize.Width / 2, ClientSize.Height / 2);
circle = new Rectangle(center.X - radius, center.Y - radius,
2 * radius, 2 * radius);
for (int i = 0; i < 9; i++) {
var x = (int)(radius * Math.Cos(Math.PI * angles[i] / 180.0)) + center.X;
var y = center.Y - (int)(radius * Math.Sin(Math.PI * angles[i] / 180.0));
panels[i].Left = x - (panels[i].Width / 2);
panels[i].Top = y - (panels[i].Height / 2);
}
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(Pens.Red, circle);
}
}
Related
I want to draw sin(θ)*cos(θ), but it doesn't work.
I can draw sin or cos,
but I want to draw sin(θ)*cos(θ) together.
Here is my code
private void button1_Click(object sender, EventArgs e)
{
Graphics drw = this.CreateGraphics();
Pen pen = new Pen(Brushes.Black, 7.0f);
float x1 = 0;
float y1 = 0;
float xoy = 200;
float ef = 20;
for (double i=0;i<40;i+=1)
{
double radi = (float)(i * 180 / Math.PI);
float temp = (float)Math.Cos(radi)*(float)Math.Sin(radi);
drw.DrawLine(pen, x1 * ef, y1 * ef + xoy, ef * (float)i, temp * ef + xoy);
x1 = (float)i;
y1 = temp;
}
}
And I want this result:
You may find it easier to look at the corresponding Parametric Equations.
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
double pi = Math.PI;
int n = 100;
var t = Enumerable.Range(0, n).Select(p => p * 2 * pi / n).ToArray();
var x = t.Select(p => Math.Sin(2 * p) * Math.Cos(p)).ToArray();
var y = t.Select(p => Math.Sin(2 * p) * Math.Sin(p)).ToArray();
Pen pen = new Pen(Brushes.Black, 3);
int scale = 100;
int shift = 100;
for (int i = 0; i < n - 1; i++)
{
g.DrawLine(pen, scale*(float)x[i] + shift,
scale*(float)y[i] + shift,
scale*(float)x[i + 1] + shift,
scale*(float)y[i + 1] + shift);
}
}
Actually, the real function you are looking for is a little bit different... see an example here. Looking at this article about polar flowers, I'm sure it will get pointed to the right direction, and it also contains a full working source code.
Just an example, supposing you use a panel in your form on which to draw the polar flower:
panel.OnPaint += Panel_Paint;
private void Panel_Paint(Object sender, PaintEventArgs e)
{
Double scale = ((Panel)sender).Width / 2.0d;
Double repetitions = Math.Round(scale, 0);
Double basis = (2.0d * Math.PI) / scale;
Double petals = 2.0d;
using (Graphics g = e.Graphics)
{
using (Pen pen = new Pen(Brushes.Red, 2.0f))
{
for (Double i = 0.0f; i < (repetitions - 1); ++i)
{
Double t0 = i*basis;
Double t1 = (i + 1)*basis;
Double x0 = Math.Sin(petals * t0) * Math.Cos(t0);
Double x1 = Math.Sin(petals * t1) * Math.Cos(t1);
Double y0 = Math.Sin(petals * t0) * Math.Sin(t0);
Double y1 = Math.Sin(petals * t1) * Math.Sin(t1);
g.DrawLine
(
pen,
(Single) ((scale*x0) + scale),
(Single) ((scale*y0) + scale),
(Single) ((scale*x1) + scale),
(Single) ((scale*y1) + scale)
);
}
}
}
}
The basic formulation states that if the petals variable value is:
even, then it represents half the amount of petals of the polar flower
odd, then it represents the amount of petals of the polar flower
so if you define Double petals = 2.0d;, you will obtain 4 petals... and if you define Double petals = 5.0d;, you will obtain 5 petals.
I've been tried to draw triangles on each edge of regular polygons.
So far I got to make polygons like this:
What I'm trying to make is that small triangle on the each edge of the polygon:
How do I do this?
Code how to draw polygons is below:
int sides = 5;
Graphics g = e.Graphics;
nPoints = CalculateVertices(sides, radius, angle, center);
g.DrawPolygon(navypen, nPoints);
g.FillPolygon(BlueBrush, nPoints);
Point center = new Point(ClientSize.Width / 2, ClientSize.Height / 2);
for(int i = 0; i < sides; i++) {
g.DrawLine(new Pen(Color.Navy), center.X, center.Y, nPoints[i].X, nPoints[i].Y);
}
private PointF[] CalculateVertices(int sides, int radius, float startingAngle, Point center)
{
if (sides < 3) {
sides = 3;
}
//throw new ArgumentException("Polygon must have 3 sides or more.");
List<PointF> points = new List<PointF>();
float step = 360.0f / sides;
float angle = startingAngle; //starting angle
for (double i = startingAngle; i < startingAngle + 360.0; i += step) //go in a circle
{
points.Add(DegreesToXY(angle, radius, center));
angle += step;
}
return points.ToArray();
}
private PointF DegreesToXY(float degrees, float radius, Point origin)
{
PointF xy = new PointF();
double radians = degrees * Math.PI / 180.0;
xy.X = (int)(Math.Cos(radians) * radius + origin.X);
xy.Y = (int)(Math.Sin(-radians) * radius + origin.Y);
return xy;
}
Try this out...instead of calculating absolute points for the triangle, I've instead computed points for a "unit triangle" at the origin (using your function!). Then I simply rotate and move the Graphics surface and draw the unit triangle where I want it:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private PointF[] nPoints;
private PointF[] triangle;
private int sides = 5;
private int angle = 0;
private int radius = 100;
private int triangleLength = 10;
private void Form1_Load(object sender, EventArgs e)
{
triangle = this.CalculateVertices(3, triangleLength, 0, new Point(0, 0)); // this "unit triangle" will get reused!
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Point center = new Point(ClientSize.Width / 2, ClientSize.Height / 2);
nPoints = CalculateVertices(sides, radius, angle, center);
// draw the polygon
g.FillPolygon(Brushes.Blue, nPoints);
g.DrawPolygon(Pens.Black, nPoints);
for (int i = 0; i < sides; i++)
{
g.DrawLine(Pens.Black, center.X, center.Y, nPoints[i].X, nPoints[i].Y);
}
// draw small triangles on each edge:
float step = 360.0f / sides;
float curAngle = angle + step / 2; // start in-between the original angles
for (double i = curAngle; i < angle + (step / 2) + 360.0; i += step) //go in a circle
{
// move to the center and rotate:
g.ResetTransform();
g.TranslateTransform(center.X, center.Y);
g.RotateTransform((float)i);
// move out to where the triangle will be drawn and render it
g.TranslateTransform(radius, 0);
g.FillPolygon(Brushes.LightGreen, triangle);
g.DrawPolygon(Pens.Black, triangle);
}
}
// this is your code unchanged
private PointF[] CalculateVertices(int sides, int radius, float startingAngle, Point center)
{
if (sides < 3)
{
sides = 3;
}
//throw new ArgumentException("Polygon must have 3 sides or more.");
List<PointF> points = new List<PointF>();
float step = 360.0f / sides;
float angle = startingAngle; //starting angle
for (double i = startingAngle; i < startingAngle + 360.0; i += step) //go in a circle
{
points.Add(DegreesToXY(angle, radius, center));
angle += step;
}
return points.ToArray();
}
// this is your code unchanged
private PointF DegreesToXY(float degrees, float radius, Point origin)
{
PointF xy = new PointF();
double radians = degrees * Math.PI / 180.0;
xy.X = (int)(Math.Cos(radians) * radius + origin.X);
xy.Y = (int)(Math.Sin(-radians) * radius + origin.Y);
return xy;
}
}
I want my custom circular progress bar in WinForm. But the result doesnt fit to what I think. How can I draw the shape as the same in this picture?. I uploaded two image to be clear in my problem.
My code to do this:
void Form1_Paint(object sender, PaintEventArgs e)
{
int angle = 120;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
Rectangle outerRect = new Rectangle(50, 50, 100, 100);
Rectangle innerRect = new Rectangle(70, 70, 60, 60);
int innerRadius = innerRect.Width / 2;
int outerRadius = outerRect.Width / 2;
Point innerCenter = new Point(innerRect.X + innerRadius, innerRect.Y + innerRadius);
Point outerCenter = new Point(outerRect.X + outerRadius, outerRect.Y + outerRadius);
GraphicsPath outerCircle = new GraphicsPath();
outerCircle.AddEllipse(outerRect);
GraphicsPath innerCircle = new GraphicsPath();
innerCircle.AddEllipse(innerRect);
GraphicsPath progPath = new GraphicsPath();
Point p1 = new Point(outerRect.X + outerRadius, outerRect.Y);
Point p2 = new Point(innerRect.X + innerRadius, innerRect.Y);
Point inner = new Point((int)(innerRadius * Math.Cos(angle * Math.PI / 180) + innerCenter.X),
(int)(innerRadius * Math.Sin(angle * Math.PI / 180) + innerCenter.Y));
Point outer = new Point((int)(outerRadius * Math.Cos(angle * Math.PI / 180) + outerCenter.X),
(int)(outerRadius * Math.Sin(angle * Math.PI / 180) + outerCenter.Y));
progPath.AddLine(p1, p2);
progPath.AddArc(innerRect, -90, angle);
progPath.AddLine(inner, outer);
progPath.AddArc(outerRect, angle - 90,-angle);
progPath.Widen(Pens.Black);
e.Graphics.DrawPath(Pens.Black, progPath);
}
You can create a GraphicsPath, then add 2 arcs to the path using AddArc method:
Outer arc from start angle 270 and sweep angle 120 degree.
Inner arc in opposite direction, from start angle 270 + 120 and sweep angle -120 degree
Then close the path using GraphicsPath.CloseFigure.
This way the you will have a thick arc as path.
You can fill the path, using Graphics.FillPath method. And also you can draw the borders using GraphicsPath.DrawPath method.
Result
Code
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
var center = new Point(100, 100);
var innerR = 30;
var thickness = 20;
var startAngle = 270;
var arcLength = 120;
var outerR = innerR + thickness;
var outerRect = new Rectangle
(center.X - outerR, center.Y - outerR, 2 * outerR, 2 * outerR);
var innerRect = new Rectangle
(center.X - innerR, center.Y - innerR, 2 * innerR, 2 * innerR);
using (var p = new GraphicsPath())
{
p.AddArc(outerRect, startAngle, arcLength);
p.AddArc(innerRect, startAngle + arcLength, -arcLength);
p.CloseFigure();
e.Graphics.FillPath(Brushes.Green, p);
e.Graphics.DrawPath(Pens.Black, p);
}
}
hey i am trying to build a windows application in .net,i have to draw factorial image inside the panel
private void Canvas_Paint(object sender, PaintEventArgs e)
{
start_x = Canvas.Width / 2;
start_Y = Canvas.Height / 2;
for (int i = 0; i < 400; i++)
draw_T();
}
public void draw_T()
{
mypen = new Pen(Color.Green, 2F);
my_angle = my_angle + (45);
my_length = 100 + (1);
end_x = (int)(start_x + Math.Cos(my_angle * .0174539676) * my_length);
end_Y = (int)(start_Y + Math.Sin(my_angle * .0174539676) * my_length);
Point[] points =
{
new Point (start_x,start_Y),
new Point (end_x,end_Y)
};
Point[] points1 =
{
new Point ((end_x+start_x)/2,(end_Y+start_Y)/2),
new Point (end_x+50,end_Y-100)
};
start_x = end_x;
start_Y = end_Y;
Graphics g = Canvas.CreateGraphics();
g.DrawLines(mypen, points);
g.DrawLines(mypen, points1);
}
drawing T shape line,then i start to draw another T shape from last end points .But problem is diagram is going outside of the panel.How do i fix drawing inside the panel
i am currently try to inscribe diagonals of a decagon inside a circle
like this
in c# my approach would be creating a circle
e.Graphics.DrawEllipse(myPen, 0, 0, 100, 100);
and draw lines inside using
e.Graphics.DrawLine(myPen, 20, 5, 50, 50);
after that i would draw a decagon polygon.
currently im stuck at how to divide the circle into 10 parts/ finding the correct coordiantes of the points on the circumference of the circles because im not good in math,
i want to know how would i know the next point in a circumference of the circle the size of my circle is indicated above.
and also i want also to ask a better approach for my problem.
Thank you :)
Just for grits and shins, here's a generic implementation that will inscribe an X-sided polygon into the Rectangle you pass it. Note that in this approach I'm not actually calculating any absolute points. Instead, I am translating the origin, rotating the surface, and drawing the lines only with respect to the origin using a fixed length and an angle. This is repeated in a loop to achieve the end result below, and is very similar to commanding the Turtle in Logo:
public partial class Form1 : Form
{
PictureBox pb = new PictureBox();
NumericUpDown nud = new NumericUpDown();
public Form1()
{
InitializeComponent();
this.Text = "Inscribed Polygon Demo";
TableLayoutPanel tlp = new TableLayoutPanel();
tlp.RowCount = 2;
tlp.RowStyles.Clear();
tlp.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tlp.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
tlp.ColumnCount = 2;
tlp.ColumnStyles.Clear();
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
tlp.Dock = DockStyle.Fill;
this.Controls.Add(tlp);
Label lbl = new Label();
lbl.Text = "Number of Sides:";
lbl.TextAlign = ContentAlignment.MiddleRight;
tlp.Controls.Add(lbl, 0, 0);
nud.Minimum = 3;
nud.Maximum = 20;
nud.AutoSize = true;
nud.ValueChanged += new EventHandler(nud_ValueChanged);
tlp.Controls.Add(nud, 1, 0);
pb.Dock = DockStyle.Fill;
pb.Paint += new PaintEventHandler(pb_Paint);
pb.SizeChanged += new EventHandler(pb_SizeChanged);
tlp.SetColumnSpan(pb, 2);
tlp.Controls.Add(pb, 0, 1);
}
void nud_ValueChanged(object sender, EventArgs e)
{
pb.Refresh();
}
void pb_SizeChanged(object sender, EventArgs e)
{
pb.Refresh();
}
void pb_Paint(object sender, PaintEventArgs e)
{
// make circle centered and 90% of PictureBox size:
int Radius = (int)((double)Math.Min(pb.ClientRectangle.Width, pb.ClientRectangle.Height) / (double)2.0 * (double).9);
Point Center = new Point((int)((double)pb.ClientRectangle.Width / (double)2.0), (int)((double)pb.ClientRectangle.Height / (double)2.0));
Rectangle rc = new Rectangle(Center, new Size(1, 1));
rc.Inflate(Radius, Radius);
InscribePolygon(e.Graphics, rc, (int)nud.Value);
}
private void InscribePolygon(Graphics G, Rectangle rc, int numSides)
{
if (numSides < 3)
throw new Exception("Number of sides must be greater than or equal to 3!");
float Radius = (float)((double)Math.Min(rc.Width, rc.Height) / 2.0);
PointF Center = new PointF((float)(rc.Location.X + rc.Width / 2.0), (float)(rc.Location.Y + rc.Height / 2.0));
RectangleF rcF = new RectangleF(Center, new SizeF(1, 1));
rcF.Inflate(Radius, Radius);
G.DrawEllipse(Pens.Black, rcF);
float Sides = (float)numSides;
float ExteriorAngle = (float)360 / Sides;
float InteriorAngle = (Sides - (float)2) / Sides * (float)180;
float SideLength = (float)2 * Radius * (float)Math.Sin(Math.PI / (double)Sides);
for (int i = 1; i <= Sides; i++)
{
G.ResetTransform();
G.TranslateTransform(Center.X, Center.Y);
G.RotateTransform((i - 1) * ExteriorAngle);
G.DrawLine(Pens.Black, new PointF(0, 0), new PointF(0, -Radius));
G.TranslateTransform(0, -Radius);
G.RotateTransform(180 - InteriorAngle / 2);
G.DrawLine(Pens.Black, new PointF(0, 0), new PointF(0, -SideLength));
}
}
}
I got the formula for the length of the side here at Regular Polygon Calculator.
One way of dealing with this is using trigonometric functions sin and cos. Pass them the desired angle, in radians, in a loop (you need a multiple of 2*π/10, i.e. a = i*π/5 for i between 0 and 9, inclusive). R*sin(a) will give you the vertical offset from the origin; R*cos(a) will give you the horizontal offset.
Note that sin and cos are in the range from -1 to 1, so you will see both positive and negative results. You will need to add an offset for the center of your circle to make the points appear at the right spots.
Once you've generated a list of points, connect point i to point i+1. When you reach the ninth point, connect it to the initial point to complete the polygon.
I don't test it, but i think it is ok.
#define DegreeToRadian(d) d * (Pi / 180)
float r = 1; // radius
float cX = 0; // centerX
float cY = 0; // centerY
int numSegment = 10;
float angleOffset = 360.0 / numSegment;
float currentAngle = 0;
for (int i = 0; i < numSegment; i++)
{
float startAngle = DegreeToRadian(currentAngle);
float endAngle = DegreeToRadian(fmod(currentAngle + angleOffset, 360));
float x1 = r * cos(startAngle) + cX;
float y1 = r * sin(startAngle) + cY;
float x2 = r * cos(endAngle) + cX;
float y2 = r * sin(endAngle) + cY;
currentAngle += angleOffset;
// [cX, cY][x1, y1][x2, y2]
}
(fmod is c++ function equals to floatNumber % floatNumber)