Каким образом можно построить на C# изображение шара как многогранника?
Формулировка задачи:
Какие средства можно использовать в Visual Studio? И как можно это реализовать?
Должно выйти нечто из разряда трёхмерных объектов!!!
Решение задачи: «Каким образом можно построить на C# изображение шара как многогранника?»
textual
Листинг программы
class Triangle
{
public IList<Vector3> Vertices = new Vector3[3];
public IList<Triangle> ApplyBisection()
{
var middles = Vertices.Select((v, i) => (v + Vertices[(i + 1) % 3]) / 2).ToList();
var res = new List<Triangle>();
for (int i = 0; i < 3; i++)
{
var triangle = new Triangle();
triangle.Vertices[0] = Vertices[i];
triangle.Vertices[1] = middles[i];
triangle.Vertices[2] = middles[(i - 1 + 3) % 3];
res.Add(triangle);
}
res.Add(new Triangle { Vertices = middles });
return res;
}
public Vector3 Middle => Vertices.Aggregate((r, v) => r + v) / 3;
}
static class FloatExtentions
{
public static float ToDegrees(this float radians)
{
return (float)(radians * 180 / Math.PI);
}
public static float ToRadians(this float degrees)
{
return (float)(degrees * Math.PI / 180);
}
}
class IcosahedronBuilder
{
private IList<Vector3> _topRing = new List<Vector3>();
private IList<Vector3> _bottomRing = new List<Vector3>();
private Vector3 _top = new Vector3(0, 1, 0);
private Vector3 _bottom = new Vector3(0, -1, 0);
private IList<Vector3> BuildTopRing()
{
var result = new List<Vector3>();
var basis = new Vector3(0, 0, -1);
float pitch = 30f.ToRadians();
for (int i = 0; i < 5; i++)
{
float yaw = -(360f / 5f * i).ToRadians();
var transform = Matrix4x4.CreateFromYawPitchRoll(yaw, pitch, 0);
result.Add(Vector3.Transform(basis, transform));
}
return result;
}
private IList<Vector3> BuildBottomRing(IList<Vector3> topRing)
{
var transform = Matrix4x4.CreateFromYawPitchRoll((360f / 10f).ToRadians(), 0, 0f.ToRadians());
transform = transform * Matrix4x4.CreateScale(1, -1, 1);
return topRing.Select(p => Vector3.Transform(p, transform)).ToList();
}
public List<Triangle> Build()
{
_topRing = BuildTopRing();
_bottomRing = BuildBottomRing(_topRing);
var result = new List<Triangle>();
for (int i = 0; i < _topRing.Count; i++)
{
var triangle = new Triangle();
triangle.Vertices[0] = _top;
triangle.Vertices[1] = _topRing[i];
triangle.Vertices[2] = _topRing[(i + 1) % _topRing.Count];
result.Add(triangle);
}
for (int i = 0; i < _topRing.Count; i++)
{
var triangle = new Triangle();
triangle.Vertices[0] = _topRing[i];
triangle.Vertices[1] = _bottomRing[i];
triangle.Vertices[2] = _bottomRing[(i + 1) % _bottomRing.Count];
result.Add(triangle);
}
for (int i = 0; i < _bottomRing.Count; i++)
{
var triangle = new Triangle();
triangle.Vertices[0] = _bottomRing[i];
triangle.Vertices[1] = _topRing[i];
triangle.Vertices[2] = _topRing[(i - 1 + _topRing.Count) % _topRing.Count];
result.Add(triangle);
}
for (int i = 0; i < _bottomRing.Count; i++)
{
var triangle = new Triangle();
triangle.Vertices[0] = _bottom;
triangle.Vertices[1] = _bottomRing[i];
triangle.Vertices[2] = _bottomRing[(i - 1 + _bottomRing.Count) % _bottomRing.Count];
result.Add(triangle);
}
return result;
}
}
class Model
{
public IList<Triangle> Triangles = new List<Triangle>();
}
class MainForm : Form
{
private Model _model = new Model();
public MainForm()
{
base.DoubleBuffered = true;
base.WindowState = FormWindowState.Maximized;
_model.Triangles = new IcosahedronBuilder().Build();
for (int i = 0; i < 2; i++)
{
_model.Triangles = _model.Triangles.SelectMany(t =>
{
IList<Triangle> derivatives = t.ApplyBisection();
foreach (var triangle in derivatives)
{
triangle.Vertices = triangle.Vertices.Select(v => Vector3.Normalize(v)).ToList();
}
return derivatives;
}).ToList();
}
var scale = Matrix4x4.CreateScale(200, -200, 200);
var translate = Matrix4x4.CreateTranslation(500, 500, 0);
var transform = scale * translate;
foreach (var triangle in _model.Triangles)
triangle.Vertices = triangle.Vertices.Select(v => Vector3.Transform(v, transform)).ToList();
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
using (var gp = new GraphicsPath())
using (var brush = new SolidBrush(Color.Black))
{
foreach (var triangle in _model.Triangles.OrderByDescending(t => t.Middle.Z))
{
gp.AddPolygon(triangle.Vertices.Select(v => new PointF(v.X, v.Y)).ToArray());
var n = Vector3.Cross(triangle.Vertices[2] - triangle.Vertices[1], triangle.Vertices[1] - triangle.Vertices[0]);
n = 10 * Vector3.Normalize(n);
var light = 1 - 0.8f * new Vector3(n.X, n.Y, 0).Length()/n.Length();//1 - cos(a)
int gray = (int)(light * 255);
brush.Color = Color.FromArgb(gray, gray, gray);
g.FillPath(brush, gp);
//g.DrawPath(Pens.Red, gp);
gp.Reset();
}
}
}
}
void Main()
{
Application.Run(new MainForm());
}