Spirograph
Post by Pi(e)3.14
Time to make some pretty pictures and play around with polar coordinates.



A small circle rolls around the inside of a big circle, and a point on the small circle's interior traces a path around the circle. So let's try to draw this.
The variables:
int bigRadius;
int smRadius; //self-explanatory...
int distance; //distance from center of small circle to point
int centerX;
int centerY;
GraphicsPath path; // These will just help us draw the picture in the right places/size
As you can see in the above pictures, the three numeric sliders contol the three variables, respectively.
Now we have to draw the picture. If you just calculate the coordinates of the points, you will see why this works:
private void Button1.Click(object sender, EventArgs e)
{
int revolutions = 0;
for (revolutions = 1; revolutions < smRadius; revolutions++)
{
if ((revolutions * bigRadius) % smRadius == 0) break;
}
/* Basically, imagine a person standing at the center of our big circle and drawing this with a spraypaint gun, turning counterclockwise in one-degree increments. So how many times does this guy have to spin to draw the whole thing? The answer is that the small circle has to roll back to the same position in which it started. That is (circumference of big circle) = (number of revolutions)(circumference of small circle). */
for (int alpha = 0; alpha < 360 * revolutions; alpha++)
{
int beta = alpha * bigRadius / smRadius;
points[alpha].X = (int)((bigRadius - smRadius) * Math.Cos(alpha / 180.0 * Math.PI) + distance * Math.Cos(beta / 180.0 * Math.PI));
points[alpha].Y = (int)((bigRadius - smRadius) * Math.Sin(alpha / 180.0 * Math.PI) + distance * Math.Sin(beta / 180.0 * Math.PI));
}
/* Since the small circle is smaller than the big one, the angle at which the point rotates relative to the small circle will be faster, in fact, proportional to its circumference. That is, (speed of center of small circle relative to big circle)/(radius of big circle) = (speed of point we are tracing relative to small circle)/(radius of small circle). Thus we get beta. The coordinates follow.*/
}
Now we have to take our set of points, which would look ugly if we just connected them and drew them in the corner, and put them in a GraphicsPath, which will connect the points with a pretty curve.
private void button1_Click(object sender, EventArgs e)
{
bigRadius = (int)bigRadiusBox.Value;
smRadius = (int)smallRadiusBox.Value;
distance = (int)distanceBox.Value; //We read the variables from the slider
int revolutions = 0;
for (revolutions = 1; revolutions < smRadius; revolutions++)
{
if ((revolutions * bigRadius) % smRadius == 0) break;
}
Point[] points = new Point[360 * revolutions+1];
for(int alpha=0;alpha<360*revolutions;alpha++)
{
int beta = alpha * bigRadius / smRadius;
points[alpha].X = (int)((bigRadius - smRadius) * Math.Cos(alpha / 180.0 * Math.PI) + distance * Math.Cos(beta / 180.0 * Math.PI));
points[alpha].Y = (int)((bigRadius - smRadius) * Math.Sin(alpha / 180.0 * Math.PI) + distance * Math.Sin(beta / 180.0 * Math.PI));
}
points[360 * revolutions] = points[0];
path = new GraphicsPath();
path.AddClosedCurve(points);
RectangleF rect = path.GetBounds();
centerX = -(int)(Math.Min(rect.Left, -bigRadius) * 1.2);
centerY = -(int)(Math.Min(rect.Top, -bigRadius) * 1.2);
Matrix shift = new Matrix();
shift.Translate(centerX, centerY);
path.Transform(shift);
if (centerX * 2 > pictureBox1.Height)
{
this.Height += centerX * 2 - pictureBox1.Height;
}
if (centerY * 2 > pictureBox1.Width)
{
this.Width += centerY * 2 - pictureBox1.Width + panel1.Width;
}
pictureBox1.Invalidate();
}
//And now we draw it...
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawEllipse(Pens.Blue, centerX - bigRadius, centerY - bigRadius, bigRadius * 2 + 1, bigRadius * 2 + 1);
if (path != null)
{
e.Graphics.DrawPath(Pens.Black, path);
}
}
And that is the sad story of the spirograph.



A small circle rolls around the inside of a big circle, and a point on the small circle's interior traces a path around the circle. So let's try to draw this.
The variables:
int bigRadius;
int smRadius; //self-explanatory...
int distance; //distance from center of small circle to point
int centerX;
int centerY;
GraphicsPath path; // These will just help us draw the picture in the right places/size
As you can see in the above pictures, the three numeric sliders contol the three variables, respectively.
Now we have to draw the picture. If you just calculate the coordinates of the points, you will see why this works:
private void Button1.Click(object sender, EventArgs e)
{
int revolutions = 0;
for (revolutions = 1; revolutions < smRadius; revolutions++)
{
if ((revolutions * bigRadius) % smRadius == 0) break;
}
/* Basically, imagine a person standing at the center of our big circle and drawing this with a spraypaint gun, turning counterclockwise in one-degree increments. So how many times does this guy have to spin to draw the whole thing? The answer is that the small circle has to roll back to the same position in which it started. That is (circumference of big circle) = (number of revolutions)(circumference of small circle). */
for (int alpha = 0; alpha < 360 * revolutions; alpha++)
{
int beta = alpha * bigRadius / smRadius;
points[alpha].X = (int)((bigRadius - smRadius) * Math.Cos(alpha / 180.0 * Math.PI) + distance * Math.Cos(beta / 180.0 * Math.PI));
points[alpha].Y = (int)((bigRadius - smRadius) * Math.Sin(alpha / 180.0 * Math.PI) + distance * Math.Sin(beta / 180.0 * Math.PI));
}
/* Since the small circle is smaller than the big one, the angle at which the point rotates relative to the small circle will be faster, in fact, proportional to its circumference. That is, (speed of center of small circle relative to big circle)/(radius of big circle) = (speed of point we are tracing relative to small circle)/(radius of small circle). Thus we get beta. The coordinates follow.*/
}
Now we have to take our set of points, which would look ugly if we just connected them and drew them in the corner, and put them in a GraphicsPath, which will connect the points with a pretty curve.
private void button1_Click(object sender, EventArgs e)
{
bigRadius = (int)bigRadiusBox.Value;
smRadius = (int)smallRadiusBox.Value;
distance = (int)distanceBox.Value; //We read the variables from the slider
int revolutions = 0;
for (revolutions = 1; revolutions < smRadius; revolutions++)
{
if ((revolutions * bigRadius) % smRadius == 0) break;
}
Point[] points = new Point[360 * revolutions+1];
for(int alpha=0;alpha<360*revolutions;alpha++)
{
int beta = alpha * bigRadius / smRadius;
points[alpha].X = (int)((bigRadius - smRadius) * Math.Cos(alpha / 180.0 * Math.PI) + distance * Math.Cos(beta / 180.0 * Math.PI));
points[alpha].Y = (int)((bigRadius - smRadius) * Math.Sin(alpha / 180.0 * Math.PI) + distance * Math.Sin(beta / 180.0 * Math.PI));
}
points[360 * revolutions] = points[0];
path = new GraphicsPath();
path.AddClosedCurve(points);
RectangleF rect = path.GetBounds();
centerX = -(int)(Math.Min(rect.Left, -bigRadius) * 1.2);
centerY = -(int)(Math.Min(rect.Top, -bigRadius) * 1.2);
Matrix shift = new Matrix();
shift.Translate(centerX, centerY);
path.Transform(shift);
if (centerX * 2 > pictureBox1.Height)
{
this.Height += centerX * 2 - pictureBox1.Height;
}
if (centerY * 2 > pictureBox1.Width)
{
this.Width += centerY * 2 - pictureBox1.Width + panel1.Width;
}
pictureBox1.Invalidate();
}
//And now we draw it...
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawEllipse(Pens.Blue, centerX - bigRadius, centerY - bigRadius, bigRadius * 2 + 1, bigRadius * 2 + 1);
if (path != null)
{
e.Graphics.DrawPath(Pens.Black, path);
}
}
And that is the sad story of the spirograph.
Tags: C#, spirograph
You must be logged in to post comments.




