Как нарисовать снежинку с n лучей и n1 ярусов
Есть фрагмент кода, он рисует что-то наподобии снежинки
public void snowflake(PaintEventArgs e,float x0,float y0,float xn,float yn,float r,int n,int n1)
{
Pen pen = new Pen(Pens.Black, 2);
int i = 1;
int i2 = 0;
float xc = x + r;
float yc = y + r;
float ncur = 0;
e.Graphics.DrawEllipse(pen, x, y, 2 * r, 2 * r);
e.Graphics.DrawEllipse(pen, x - r, y - r, 4 * r, 4 * r);
for (; i < n1 + 1; i++)
{
for (; i2 < n; i2++)
{
float il = i2 - (n - 1) / 2;
//float rl = r / n1 * i;
ncur = n * (ncur + il);
xn = x0 + r * (float)Math.Cos((ncur + il) * 2 * (float)Math.PI / n);
yn = y0 + r * (float)Math.Sin((ncur + il) * 2 * (float)Math.PI / n);
e.Graphics.DrawLine(pen, xc, yc, xn, yn);
}
}
}
Как сделать так, чтобы можно было выводить разное кол-во ярусов, по желанию? Сейчас всегда рисует только один ярус. X,y-координаты центра, r-радиус одного яруса
Есть также код на паскале, полностью рабочий
procedure drawsnowflake(x0, y0, x, y, r, n, k, kcur: integer; ncur, angle: real; color: system.drawing.color);
begin
if kcur <= k then
begin
for var i := 0 to n - 1 do
begin
var i1 := i - (n - 1) / 2;
var r1 := round(r / k * kcur);
var x1 := round(x0 + r1 * cos((ncur + i1) * angle));
var y1 := round(y0 + r1 * sin((ncur + i1) * angle));
line(x, y, x1, y1, color);
drawsnowflake(x0, y0, x1, y1, r, n, k, kcur + 1, n * (ncur + i1), angle / n, color);
end;
end;
end;
var
x, y, r, n, k, answer: integer;
color: system.drawing.color;
begin
while true do
begin
textout(0, 0, 'X = ');
read(x);
clearwindow;
textout(0, 0, 'X = ');
textout(25, 0, x);
textout(0, 20, 'Y = ');
read(y);
textout(25, 20, y);
textout(0, 40, 'R = ');
read(r);
textout(25, 40, r);
textout(0, 60, 'Ветвлений = ');
read(n);
textout(80, 60, n);
textout(0, 80, 'Ярусов = ');
read(k);
textout(60, 80, k);
textout(0, 100, 'BorderColor = ');
textout(0, 120, '0 - Black');
textout(0, 140, '1 - Red');
textout(0, 160, '2 - Green');
textout(0, 180, '3 - Blue');
textout(0, 200, '4 - Yellow');
read(answer);
fillrect(0, 120, 100, 220);
case answer of
1: begin color := clred; textout(90, 100, 'Red'); end;
2: begin color := clgreen; textout(90, 100, 'Green'); end;
3: begin color := clblue; textout(90, 100, 'Blue'); end;
4: begin color := clyellow; textout(90, 100, 'Yellow'); end;
else begin color := clblack; textout(90, 100, 'Black'); end;
end;
textout(25, 40, r);
drawsnowflake(x, y, x, y, r, n, k, 1, 0, 2 * pi / n, color)
end;
end.
Ответы (2 шт):
Автор решения: KuzCode
→ Ссылка
Вот мой вариант кода (назвал все аргументы по-человечески):
public static double ConvertDegreesToRadians(double degrees) =>
Math.PI / 180 * degrees;
private void DrawSnowflake(Graphics graphics, Point center, Point localCenter, int radius,
int forksCount, int layersCount, int layer, float forkIndex, float angle, Color color)
{
for (int localForkIndex = 0; localForkIndex < forksCount; localForkIndex++)
{
var forksIndex1 = localForkIndex - (forksCount - 1) / 2;
var radius1 = (int)((float)radius / layersCount * layer);
var center1X = (int)(center.X + radius1 * Math.Cos((forkIndex + forksIndex1) * angle));
var center1Y = (int)(center.Y + radius1 * Math.Sin((forkIndex + forksIndex1) * angle));
var center1 = new Point(center1X, center1Y);
graphics.DrawLine(new Pen(color), localCenter.X, localCenter.Y, center1.X, center1.Y);
if (layer != layersCount)
{
DrawSnowflake(
graphics: graphics,
center: center,
localCenter: center1,
radius: radius,
forksCount: forksCount,
layersCount: layersCount,
layer: layer + 1,
forkIndex: forksCount * (forkIndex + forksIndex1),
angle: angle / forksCount,
color: color);
}
}
}
/// <summary>
/// Нарисовать снежинку
/// </summary>
/// <param name="graphics">Графика</param>
/// <param name="center">Центральная точка</param>
/// <param name="radius">Радиус</param>
/// <param name="forksCount">Количество ветвлений</param>
/// <param name="layersCount">Количество ярусов</param>
/// <param name="angle">Угол</param>
/// <param name="color">Цвет</param>
public void DrawSnowflake(Graphics graphics, Point center, int radius,
int forksCount, int layersCount, float angle, Color color)
{
if (layersCount <= 0)
throw new Exception($"{nameof(layersCount)} <= 0");
if (forksCount < 0)
throw new Exception($"{nameof(forksCount)} < 0");
DrawSnowflake(
graphics: graphics,
center: center,
localCenter: center,
radius: radius,
forksCount: forksCount,
layersCount: layersCount,
layer: 1,
forkIndex: 0,
angle: angle / forksCount,
color: color);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
DrawSnowflake(
graphics: e.Graphics,
center: new Point(e.ClipRectangle.Width / 2, e.ClipRectangle.Height / 2),
radius: 200,
forksCount: 6,
layersCount: 3,
angle: (float)ConvertDegreesToRadians(360),
color: Color.Black);
}
Если убрать деление угла angle / n (python), angle / forksCount (c#), получится так:
if (layer != layersCount)
{
DrawSnowflake(
...
angle: angle,// / forksCount,
color: color);
}
И картинка выйдет такая:
UPD:
Я посидел и переделал метод, так что бы он рисовал настоящую снежинку, вот что получилось:
private void DrawSnowflake(Graphics graphics, Point center, int radius, float radiusScale, int forksCount, int layersCount, int layer, float angle, Color color)
{
for (int localForkIndex = 0; localForkIndex < forksCount; localForkIndex++)
{
var forkCenter = new Point(
(int)(center.X + radius * Math.Cos(localForkIndex * angle)),
(int)(center.Y + radius * Math.Sin(localForkIndex * angle)));
graphics.DrawLine(new Pen(color), center.X, center.Y, forkCenter.X, forkCenter.Y);
if (layer != layersCount)
{
DrawSnowflake(
graphics: graphics,
center: forkCenter,
radius: (int)(radius * radiusScale),
radiusScale: radiusScale,
forksCount: forksCount,
layersCount: layersCount,
layer: layer + 1,
angle: angle,
color: color);
}
}
}
/// <summary>
/// Нарисовать снежинку
/// </summary>
/// <param name="graphics">Графика</param>
/// <param name="center">Центральная точка</param>
/// <param name="radius">Радиус</param>
/// <param name="forksCount">Количество ветвлений</param>
/// <param name="layersCount">Количество ярусов</param>
/// <param name="angle">Угол</param>
/// <param name="color">Цвет</param>
public void DrawSnowflake(Graphics graphics, Point center, int radius, float radiusScale,
int forksCount, int layersCount, float angle, Color color)
{
if (layersCount <= 0)
throw new Exception($"{nameof(layersCount)} <= 0");
if (forksCount < 0)
throw new Exception($"{nameof(forksCount)} < 0");
DrawSnowflake(
graphics: graphics,
center: center,
radius: radius,
radiusScale: radiusScale,
forksCount: forksCount,
layersCount: layersCount,
layer: 1,
angle: angle,
color: color);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var forksCount = 6;
DrawSnowflake(
graphics: e.Graphics,
center: new Point(e.ClipRectangle.Width / 2, e.ClipRectangle.Height / 2),
radius: 150,
radiusScale: 1f / 3,
forksCount: forksCount,
layersCount: 5,
angle: (float)ConvertDegreesToRadians(360 / forksCount),
color: Color.Black);
}
Автор решения: Sergey
→ Ссылка
Спасибо за помощь, немного посидел и получилось это:
private void pic1_Paint(object sender, PaintEventArgs e)
{
draw(e, x+r, y+r ,x+r ,y+r , n, n1, 1, 0, (float)Math.PI*2/n);
}
public void draw(PaintEventArgs e,float x0, float y0,float x, float y,float n,float n1,int n1cur,float ncur,float ang)
{
Pen pen = new Pen(Color.FromArgb(br, bg, bb), 2);
if (n1cur <= n1)
{
for(int i = 0; i < n;i++)
{
float i1 = i - (n - 1) / 2;
float r1 = r / n1 * n1cur;
float x1 = x0 + r1 * (float)Math.Cos(ang * (ncur + i1));
float y1 = y0 + r1 * (float)Math.Sin(ang * (ncur + i1));
e.Graphics.DrawLine(pen, x, y, x1, y1);
draw(e, x0, y0, x1, y1, n ,n1 ,n1cur + 1 ,n*(ncur + i1) ,ang / n);
}
}
}
Вроде как работает, как и запланировано, оставлю это здесь, вдруг кому потом пригодится.


