«Я не без ума от реальности, но это единственное место, где можно нормально поесть».
— Граучо Маркс
Что такое треугольник Серпинского, также называемый прокладкой Серпинского?
Треугольник Серпинского берет треугольник, делит его на четверти, удаляет центральную четверть и делает то же самое с оставшимися треугольниками. В итоге мы получаем фрактал, показанный выше. Например, если бы вам нужно было подсчитать количество прямостоячих треугольников в ряду, в каждом ряду было бы количество прямостоячих треугольников, равное определенной степени числа 2. Кроме того, общее количество прямостоячих треугольников во всем треугольнике Серпинского будет равно 3^n или 3 в степени количества итераций (обозначено здесь как «n»). В приведенном выше треугольнике количество итераций равно 10, поэтому количество прямых треугольников равно 3¹⁰. Вот закономерность количества прямостоячих треугольников:
0 итераций: 1 три
1 эт: 3 трис
2 итер: 9 трис
3 эт: 27 трис
4 итер: 81 трис
5 итер: 243 трис
6 итер: 729 трис
10 итер: 59049 трис (ЧТО?!)
niter: 3^n tris
Один из способов создания фрактала — многократное повторение одной и той же функции в разных масштабах с относительным размещением. Мы сделали 3 треугольника снова и снова, каждый раз уменьшая их наполовину, и поместили их в угол текущего треугольника, который «фрактализируется».
Фракталы обладают свойством, называемым масштабной инвариантностью. Это означает, что фрактальный узор останется прежним, даже если вы измените уровень масштабирования. Треугольник Серпинского — это фрактал, в котором вы можете увеличивать его до бесконечности, и вы все равно получите один и тот же узор из треугольников. Все фракталы такие. (См. определение фрактала здесь.)
Вот что мы сделали, чтобы сделать треугольник Серпинского: мы создали объекты под названием Point и Triangle. Для пояснений см. комментарии ниже в коде.
class Point { float x, y; Point (float x, float y) { // makes the coordinates for the point this.x = x; this.y = y; } } class Triangle { Point[] vertices = new Point[3]; Triangle(Point p1, Point p2, Point p3) { // makes the vertices for the triangle vertices[0] = p1; vertices[1] = p2; vertices[2] = p3; } void draw() { line(vertices[0].x, vertices[0].y, vertices[1].x, vertices[1].y); line(vertices[2].x, vertices[2].y, vertices[1].x, vertices[1].y); line(vertices[0].x, vertices[0].y, vertices[2].x, vertices[2].y); // creates the lines for the triangle by manipulating the x and y coordinates from the vertices } }
(Они в верхнем регистре, потому что объект или класс в коде в верхнем регистре.) Каждая точка состояла из набора координат x-y, а каждый треугольник состоял из массива из 3 строк.
В каждой итерации мы делали 3 вертикальных «дочерних» треугольника в углах «родительского» треугольника, чтобы оперировать вертикальными треугольниками вместо одного прямого треугольника. Каждый дочерний треугольник находился в углу родительского треугольника, и каждый дочерний треугольник был масштабирован до половины размера родительского треугольника. Мы сделали это, взяв координаты x-y каждой вершины родительского треугольника. Затем мы взяли половину X и Y каждой пары вершин и создали 3 новых дочерних треугольника, используя вершины родительских треугольников, создав новые точки, используя центр координат X и Y.
Triangle[] findChildren(Triangle s){ Triangle[] c = {}; // specifies an array of triangles. float x1 = s.vertices[0].x; float y1 = s.vertices[0].y; float x2 = s.vertices[1].x; float y2 = s.vertices[1].y; float x3 = s.vertices[2].x; float y3 = s.vertices[2].y; //calculates the x and y of each point on the triangle. float xc1 = (x1 + x2) / 2.0; float yc1 = (y1 + y2) /2.0; float xc2 = (x2 + x3) /2.0; float yc2 = (y2 + y3) /2.0; float xc3 = (x3 + x1)/2.0; float yc3 = (y3 + y1)/2.0; //calculates the center of the X and Y of each pair of vertices. c = (Triangle[])append(c,new Triangle(new Point (x1, y1), new Point (xc1, yc1), new Point(xc3, yc3))); c = (Triangle[])append(c,new Triangle(new Point (xc1, yc1), new Point (x2, y2), new Point(xc2, yc2))); c = (Triangle[])append(c,new Triangle(new Point (xc3, yc3), new Point (xc2, yc2), new Point(x3, y3))); // uses the vertices and the centers to make 3 child triangles. // append means to add to a specified array return c; }
В каждой итерации мы брали бы то, что изначально было дочерним треугольником в последней итерации, и делали его родительским треугольником в текущей итерации.
Мы сделали то же самое со всеми дочерними треугольниками для 10 итераций. Чтобы изменить количество итераций, измените значение переменной count
.
int count = 0; void setup(){ size(700, 700); t = new Triangle (new Point (350, 50), new Point (50,650), new Point (650, 650)); //we use noLoop() so we can control number of iterations noLoop(); } void drawTriangles(Triangle[] tris) { // declares an array of tris while (count < 10) { //determines the amount of iterations count++; //increases count Triangle[] ctris = new Triangle[0]; //creates a fresh array for(Triangle tri : tris) { tri.draw(); Triangle[] cs = findChildren(tri); for (Triangle increase : cs) { ctris = (Triangle[])append(ctris, increase); } } drawTriangles(ctris); } }
Полный код с использованием обработки смотрите на GitHub.
Подписание «до следующего раза,
Ави