static class BezierSurface { private const int n = 3;// размерность массива private const int m = 4;// mBezierSurface (3 на 4) private static Point3D[,] mBezierSurface = new Point3D[n, m]{//Второго порядка // можно сделать 9, ставь m = 3 и подбирай координаты. { new Point3D(0, 0, 0), new Point3D(0, 0, 0.5), new Point3D(0, 0.5, 0), new Point3D(0, 0.5, 0.5) }, { new Point3D(1, 0, 0), new Point3D(1, 0, 1), new Point3D(1, 1, 0), new Point3D(1, 1, 1) }, { new Point3D(1, 0, 0), new Point3D(1, 0, 1), new Point3D(1, 1, 0), new Point3D(1, 2, 3) }, }; public class BSplineSurface { private double size; private const int m = 4;// ненужный аппендикс, в топку его private Point3D start = new Point3D(400, 220, 0); private double psi;// огорчаешь: углы обзора private double phi;// на поверхность public BSplineSurface(double size, double psi, double phi)//конструктор класса { this.size = size; this.psi = psi; this.phi = phi; } Point3D[][] mBSplineSurface = new Point3D[][] { new Point3D[] { new Point3D(0, 0, 0), new Point3D(0, 0, 0.5), new Point3D(0, 0.5, 0), new Point3D(0, 0.5, 0.5) }, new Point3D[] { new Point3D(0.5, 0, 0), new Point3D(0.5, 0, 0.5), new Point3D(0.5, 0.5, 0), new Point3D(0.5, 0.5, 0.5) }, new Point3D[] { new Point3D(2, 0, 0), new Point3D(2, 0, 2), new Point3D(2, 2, 0), new Point3D(2, 2, 2) } }; private PointF Project(Point3D p)// метод проецирования трехмерной точки на двумерную плоскость { Point3D a1 = new Point3D(Math.Cos(phi), Math.Sin(phi), 0); Point3D a2 = new Point3D(-1 * Math.Sin(phi) * Math.Sin(psi), Math.Cos(phi) * Math.Sin(psi), Math.Cos(psi)); double x = p.X - start.X;//? double y = p.Y - start.Y; double z = p.Z - start.Z; return new PointF((float)(a1.scalyar(new Point3D(x, y, z)) * size), (float)(a2.scalyar(new Point3D(x, y, z)) * size)); } public void Show(Graphics g, Pen pen) { List polygon = new List();// Лист для точек на сетке for (double u = 0; u <= 1.0; u += 0.01) { for (double v = 0; v <= 1.0; v += 0.01) { var pList = new List();// Лист, в котором лежат точки сплайна. for (int i = 0; i < mBSplineSurface.Length; i++) { for (int j = 0; j < mBSplineSurface.Length - 2; j++) { pList.Add(new Point3D((float)(0.5f * (1f - v) * (1f - v) * mBSplineSurface[i][j].X + (0.75f - (v - 0.5f) * (v - 0.5f)) * mBSplineSurface[i][j + 1].X + 0.5f * v * v * mBSplineSurface[i][j + 2].X), (float)(0.5f * (1f - v) * (1f - v) * mBSplineSurface[i][j].Y + (0.75f - (v - 0.5f) * (v - 0.5f)) * mBSplineSurface[i][j + 1].Y + 0.5f * v * v * mBSplineSurface[i][j + 2].Y), (float)(0.5f * (1f - v) * (1f - v) * mBSplineSurface[i][j].Z + (0.75f - (v - 0.5f) * (v - 0.5f)) * mBSplineSurface[i][j + 1].Z + 0.5f * v * v * mBSplineSurface[i][j + 2].Z))); } } for (int j = 0; j < pList.Count - 2; j++) { polygon.Add(new Point3D((float)(0.5f * (1f - u) * (1f - u) * pList[j].X + (0.75f - (u - 0.5f) * (u - 0.5f)) * pList[j + 1].X + 0.5f * u * u * pList[j + 2].X), (float)(0.5f * (1f - u) * (1f - u) * pList[j].Y + (0.75f - (u - 0.5f) * (u - 0.5f)) * pList[j + 1].Y + 0.5f * u * u * pList[j + 2].Y), (float)(0.5f * (1f - u) * (1f - u) * pList[j].Z + (0.75f - (u - 0.5f) * (u - 0.5f)) * pList[j + 1].Z + 0.5f * u * u * pList[j + 2].Z))); polygon.Last().X = (float)(polygon.Last().X + start.X); polygon.Last().Y = (float)(polygon.Last().Y + start.Y); polygon.Last().Z = (float)(polygon.Last().Z + start.Z); } } var sub = polygon.Select(x => Project(x)).ToList();// создаем новый лист, в него кладем двухмерные точки. // .Select(x => Project(x)) эта штука берет каждую точку из листа polygon и прогоняет в методе Project for (int i = 0; i < sub.Count - 1; i++) { if (g.ClipBounds.Contains(sub[i]) && g.ClipBounds.Contains(sub[i + 1])) { g.DrawLine(pen, sub[i], sub[i + 1]); } } polygon.Clear(); } for (double v = 0; v <= 1.0; v += 0.01) { for (double u = 0; u <= 1.0; u += 0.01) { var pList = new List(); for (int i = 0; i < mBSplineSurface.Length; i++) { for (int j = 0; j < mBSplineSurface.Length - 2; j++) { pList.Add(new Point3D((float)(0.5f * (1f - v) * (1f - v) * mBSplineSurface[i][j].X + (0.75f - (v - 0.5f) * (v - 0.5f)) * mBSplineSurface[i][j + 1].X + 0.5f * v * v * mBSplineSurface[i][j + 2].X), (float)(0.5f * (1f - v) * (1f - v) * mBSplineSurface[i][j].Y + (0.75f - (v - 0.5f) * (v - 0.5f)) * mBSplineSurface[i][j + 1].Y + 0.5f * v * v * mBSplineSurface[i][j + 2].Y), (float)(0.5f * (1f - v) * (1f - v) * mBSplineSurface[i][j].Z + (0.75f - (v - 0.5f) * (v - 0.5f)) * mBSplineSurface[i][j + 1].Z + 0.5f * v * v * mBSplineSurface[i][j + 2].Z))); } } for (int j = 0; j < pList.Count - 2; j++) { polygon.Add(new Point3D((float)(0.5f * (1f - u) * (1f - u) * pList[j].X + (0.75f - (u - 0.5f) * (u - 0.5f)) * pList[j + 1].X + 0.5f * u * u * pList[j + 2].X), (float)(0.5f * (1f - u) * (1f - u) * pList[j].Y + (0.75f - (u - 0.5f) * (u - 0.5f)) * pList[j + 1].Y + 0.5f * u * u * pList[j + 2].Y), (float)(0.5f * (1f - u) * (1f - u) * pList[j].Z + (0.75f - (u - 0.5f) * (u - 0.5f)) * pList[j + 1].Z + 0.5f * u * u * pList[j + 2].Z))); polygon.Last().X = (float)(polygon.Last().X + start.X); polygon.Last().Y = (float)(polygon.Last().Y + start.Y); polygon.Last().Z = (float)(polygon.Last().Z + start.Z); } } var sub = polygon.Select(x => Project(x)).ToList();// то же самое, что было выше for (int i = 0; i < sub.Count - 1; i++) { if (g.ClipBounds.Contains(sub[i]) && g.ClipBounds.Contains(sub[i + 1])) { g.DrawLine(pen, sub[i], sub[i + 1]); } } polygon.Clear(); } } } } class DrawSurface { private Graphics e; private double a, b, c, d, phi, psi, Sx, Sy;// a,b,c,d - прямоугольник, ограничивающий поверхность. phi/psi - угол обзора, Sx, Sy - масштаб private int Picture_CODE, BEGINX, BEGINY;//Picture_CODE - номер поверхность для отрисовки, BEGINX, BEGINY - точка, с которой будем рисовать public DrawSurface(Graphics e, double a1, double b1, double c1, double d1, double phi, double psi, double Sx, double Sy, int Picture_CODE, int BEGINX, int BEGINY) { this.e = e; a = a1; b = b1; c = c1; d = d1; this.phi = phi; this.psi = psi; this.Picture_CODE = Picture_CODE; this.Sx = Sx; this.Sy = Sy; this.BEGINX = BEGINX; this.BEGINY = BEGINY; } public void Draw() { List list = new List(); Point3D p = new Point3D(); Point3D a1 = new Point3D(Math.Cos(phi), Math.Sin(phi), 0); Point3D a2 = new Point3D(-1 * Math.Sin(phi) * Math.Sin(psi), Math.Cos(phi) * Math.Sin(psi), Math.Cos(psi)); double u, v, du, dv, Nu = 20, Nv = 20;//u, v - точки на сетке, du,dv - шаг, Nu, Nv - разбиение du = Math.Abs((b - a) / Nu); dv = Math.Abs((d - c) / Nv); Point temp = new Point(0, 0); Point3D beg = new Point3D(0, 0, 0), cur = new Point3D(0, 0, 0);// точки на сетке int u0, v0, v1, u1;// спроецированные точки for (u = a; u <= b; u += du) // рисование по горизонтали { v = c; beg = Function(u, v, Picture_CODE); u0 = ((int)(Sx * scalyar(beg, a1))); v0 = ((int)(Sy * scalyar(beg, a2))); temp.X = BEGINX + u0; temp.Y = BEGINY + v0; for (v = c + dv; v <= d; v += dv)// рисование по горизонтали { cur = Function(u, v, Picture_CODE); u1 = ((int)(Sx * scalyar(cur, a1))); v1 = ((int)(Sy * scalyar(cur, a2))); e.DrawLine(new Pen(Color.Black), BEGINX + u1, BEGINY + v1, temp.X, temp.Y); temp.X = BEGINX + u1; temp.Y = BEGINY + v1; } } for (v = c; v <= d; v += dv)//// рисование по вертикали { u = a; beg = Function(u, v, Picture_CODE); u0 = ((int)(Sx * scalyar(beg, a1))); v0 = ((int)(Sy * scalyar(beg, a2))); temp.X = BEGINX + u0; temp.Y = BEGINY + v0; for (u = a + du; u <= b; u += du) { cur = Function(u, v, Picture_CODE); u1 = ((int)(Sx * scalyar(cur, a1))); v1 = ((int)(Sy * scalyar(cur, a2))); e.DrawLine(new Pen(Color.Black), BEGINX + u1, BEGINY + v1, temp.X, temp.Y); temp.X = BEGINX + u1; temp.Y = BEGINY + v1; } } } private double scalyar(Point3D a, Point3D b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } public Point3D Function(double u, double v, int code)//Функция, которая возвращает значение для построения поверхности { // u, v положение на сетке(точка), code - номер фигуры, которую хочешь вывести. Дашь 0 - будешь поверхность Безье switch (code) { case 0: return BezierSurface.drawBezierSurface(u, v); case 1: return new Point3D(5 * Math.Cos(u) * Math.Atan(v), 5 * Math.Sin(u) * Math.Tanh(v), 5 * Math.Tanh(u * v)); case 2: return new Point3D((5 + Math.Cos(u)) * Math.Cos(v), (5 + Math.Cos(u)) * Math.Sin(v), 5 * Math.Sin(u)); default: return new Point3D(0, 0, 0); } } } }