## Adobe Support Community

• Global community
• Language:
• Deutsch
• English
• Español
• Français
• Português
• 日本語コミュニティ
Dedicated community for Japanese speakers
• 한국 커뮤니티
Dedicated community for Korean speakers
Exit
• Help With Design Please (Fractals)

# Help With Design Please (Fractals)

Explorer ,
Sep 08, 2023 Sep 08, 2023

Copy link to clipboard

Copied

Hi Everyone,

I have attached two files. Is there a way to recreate these patterns in illustrator?

I tried poking around to find some answers, but I wonder if I'm having trouble finding the right direction because I don't know what to call it.

Any help with this would be greatly appreciated.

Thank you so much

Matt

TOPICS
Draw and design , How-to , Scripting

Views

381

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more

## 1 Correct answer

Guide , Sep 10, 2023 Sep 10, 2023

Here's a script that draws a Sierpinski triangle that fits the open document.  The number of recursions can be changed by changing the number of "levels" in line 2, although it is advised not to go too much above 10, otherwise Illustrator may become unresponsive.  Adapted from:  https://www.youtube.com/watch?v=e3Ll0_oxChU

``````function main() {
var level = 5;
var doc = app.activeDocument;

function drawTriangle(p1, p2, p3) {
var path1 = doc.pathItems.add();
path1.setEnti``````
...

16 Replies 16
Community Expert ,
Sep 08, 2023 Sep 08, 2023

Copy link to clipboard

Copied

they are called Fractals

the first is called Apollonian Gasket

the second is called Sierpinski Triangle

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Sep 09, 2023 Sep 09, 2023

Copy link to clipboard

Copied

Carlos, thank you for the informative links.

Math is not my thing!!!

What I do know is that a hexagon divided into 6 equal segments= 6 equilateral triangles.

So to recreate this Sierpinski triangle, I created a seamless hexagon pattern.

Next Live Paint. I random recolor as I work.

Expand Live Paint. Pathfinder>Unite each unique color.

Recolor as you like.

Here is what it looks like with simple black and white.

K

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 09, 2023 Sep 09, 2023

Copy link to clipboard

Copied

I think your  method is right one. Or we need to draw all possible lines via simple objects and use shape builder tool. The main concept of fractals is that one small element raised in size (for each iteration) and create a whole structure. But we can't do it in Illustrator  as it repeats each unit and keep its original size when we trying to create a pattern.

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Explorer ,
Sep 09, 2023 Sep 09, 2023

Copy link to clipboard

Copied

Thank you so much for the clarity around WHAT they are. That is so helpful.

Creating the Sierpinski Triangle was pretty easy once the math was understood.

The Apollonian Gasket is proving to be a little more challenging with exact placement to reproduce the same results.

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 09, 2023 Sep 09, 2023

Copy link to clipboard

Copied

usually these images are generated programmatically to place items precisely

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 10, 2023 Sep 10, 2023

Copy link to clipboard

Copied

I use some Fractals Application for creating fractals that I use as patterns in my work. Also this G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processin... includs such a filter. Just my 2  cents.

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Sep 10, 2023 Sep 10, 2023

Copy link to clipboard

Copied

Here's a script that draws a Sierpinski triangle that fits the open document.  The number of recursions can be changed by changing the number of "levels" in line 2, although it is advised not to go too much above 10, otherwise Illustrator may become unresponsive.  Adapted from:  https://www.youtube.com/watch?v=e3Ll0_oxChU

``````function main() {
var level = 5;
var doc = app.activeDocument;

function drawTriangle(p1, p2, p3) {
var path1 = doc.pathItems.add();
path1.setEntirePath([p1, p2, p3, p1]);
path1.closed = true;
}

function getMidpoint(p1, p2) {
return [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
}

var Triangle = function(p1, p2, p3) {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.draw = function() {
drawTriangle(this.p1, this.p2, this.p3);
}
}

function drawSierpinskiTriangle(tri, depth) {
if (depth == level) return;

var m1 = getMidpoint(tri.p1, tri.p2);
var m2 = getMidpoint(tri.p2, tri.p3);
var m3 = getMidpoint(tri.p3, tri.p1);

var t0 = new Triangle(m1, m2, m3);
t0.draw();

var t1 = new Triangle(tri.p1, m1, m3);
var t2 = new Triangle(tri.p2, m1, m2);
var t3 = new Triangle(tri.p3, m2, m3);

drawSierpinskiTriangle(t1, depth + 1);
drawSierpinskiTriangle(t2, depth + 1);
drawSierpinskiTriangle(t3, depth + 1);
}

var size = doc.width < doc.height ? doc.width : doc.height;

var t = new Triangle(
[size / 2, 0],
[0, -size],
[size, -size]
);
t.draw();

drawSierpinskiTriangle(t, 0);
}

main();``````

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Explorer ,
Sep 10, 2023 Sep 10, 2023

Copy link to clipboard

Copied

How cool is that. Being able to write code to achieve the look!

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 11, 2023 Sep 11, 2023

Copy link to clipboard

Copied

That's a very good approach, Femke.

I once created an action and a graphic style to create the triangle construction. Of course, it was insanely complicated.

Your script is way better and pretty fast.

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 11, 2023 Sep 11, 2023

Copy link to clipboard

Copied

Yes, I love it, just one remark, it creates open paths (easy to solve with a forth and back to Live Paint).

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Sep 12, 2023 Sep 12, 2023

Copy link to clipboard

Copied

@Ton Frederiks  I've added a line that makes the paths closed.

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 12, 2023 Sep 12, 2023

Copy link to clipboard

Copied

Thanks @femkeblanco  I found that the new code indeed closed the paths, but created triangles with 4 points.

I am not a scripter but tried to change

``path1.setEntirePath([p1, p2, p3, p1]);``

into

``path1.setEntirePath([p1, p2, p3]);``

and to my surprise that worked.

Thanks again!

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Sep 27, 2023 Sep 27, 2023

Copy link to clipboard

Copied

And here's a script that draws three types of Apollonian gaskets.  This is adapted from a browser script that is dependent on the size of the canvas.  I've kept it at the same size (400 pt) so as to show the same results; they can be manually scaled.

``````// part 1: Complex class (manipulates complex numbers)
// abridged from Complex.js by Robert Eisele
// https://rawgit.com/infusion/Complex.js/master/complex.js
var parse = function (a, b) {
var z = {
're': 0,
'im': 0
};
if (a == undefined || a == null) {
z['re'] = z['im'] = 0;
} else if (b != undefined) {
z['re'] = a;
z['im'] = b;
} else
if (typeof a == 'object') {
z['re'] = a['re'];
z['im'] = a['im'];
} else if (typeof a == 'number') {
z['im'] = 0;
z['re'] = a;
}
return z;
};

var Complex = function (a, b) {
if (!(this instanceof Complex)) {
return new Complex(a, b);
}
var z = parse(a, b);
this['re'] = z['re'];
this['im'] = z['im'];
};

Complex.prototype = {
're': 0,
'im': 0,
'add': function(a, b) {
var z = new Complex(a, b);
return new Complex(
this['re'] + z['re'],
this['im'] + z['im']);
},
'sub': function(a, b) {
var z = new Complex(a, b);
return new Complex(
this['re'] - z['re'],
this['im'] - z['im']);
},
'mul': function(a, b) {
var z = new Complex(a, b);
if (z['im'] == 0 && this['im'] == 0) {
return new Complex(this['re'] * z['re'], 0);
}
return new Complex(
this['re'] * z['re'] - this['im'] * z['im'],
this['re'] * z['im'] + this['im'] * z['re']);
},
'div': function(a, b) {
var z = new Complex(a, b);
a = this['re'];
b = this['im'];
var c = z['re'];
var d = z['im'];
var t, x;
if (0 == d) {
return new Complex(a / c, b / c);
}
if (Math.abs(c) < Math.abs(d)) {
x = c / d;
t = c * x + d;
return new Complex(
(a * x + b) / t,
(b * x - a) / t);
} else {
x = d / c;
t = d * x + c;
return new Complex(
(a + b * x) / t,
(b - a * x) / t);
}
},
'sqrt': function() {
var a = this['re'];
var b = this['im'];
var r = this['abs']();
var re, im;
if (a >= 0) {
if (b == 0) {
return new Complex(Math.sqrt(a), 0);
}
re = 0.5 * Math.sqrt(2.0 * (r + a));
} else {
re = Math.abs(b) / Math.sqrt(2 * (r - a));
}
if (a <= 0) {
im = 0.5 * Math.sqrt(2.0 * (r - a));
} else {
im = Math.abs(b) / Math.sqrt(2 * (r + a));
}
return new Complex(re, b < 0 ? -im : im);
},
'abs': function() {
return Math.sqrt(this['re'] * this['re'] + this['im'] * this['im']);
}
};

// part 2: main
// adapted from Apollonian gasket by pimskie
// https://codepen.io/pimskie
var doc = app.activeDocument;
var DIM = 400;
var MID = DIM * 0.5;
var MIN_R = 2;

var Circle = function(r, center) {
this.r = r;
this.b = 1 / this.r;
this.center = center;
this.bc = this.center.mul(this.b);
};

var solveEquation = function(k1, k2, k3) {
var k12 = k1.mul(k2);
var k13 = k1.mul(k3);
var k23 = k2.mul(k3);
};

var getAdjacent = function(c1, c2, c3) {
var b1 = new Complex(c1.b);
var b2 = new Complex(c2.b);
var b3 = new Complex(c3.b);
var b4 = solveEquation(b1, b2, b3);
var r4 = Math.abs(1 / b4.re);
var pos4 = solveEquation(c1.bc, c2.bc, c3.bc).div(b4);
return new Circle(r4, pos4);
};

var flip = function(c4, c1, c2, c3) {
var bend = 2 * (c1.b + c2.b + c3.b) - c4.b;
return new Circle(1 / bend, center);
};

var addCircle = function (circle) {
circles.push(circle);
};

var recurse = function(c1, c2, c3, c4, depth) {
depth = depth || 0;
var cn2 = flip(c2, c1, c3, c4);
var cn3 = flip(c3, c1, c2, c4);
var cn4 = flip(c4, c1, c2, c3);
if (cn2.r > MIN_R) {
recurse(cn2, c1, c3, c4, depth + 1);
}
if (cn3.r > MIN_R) {
recurse(cn3, c1, c2, c4, depth + 1);
}
if (cn4.r > MIN_R) {
recurse(cn4, c1, c2, c3, depth + 1);
}
};

var drawGasket = function(c1, c2, c3) {
var c4 = getAdjacent(c1, c2, c3);
var c5 = flip(c1, c2, c3, c4)
recurse(c1, c2, c3, c4);
recurse(c5, c2, c3, c4);
};

var symmetricSet = function() {
var c1r = -MID;
var c1center = new Complex(MID, MID);
var c1 = new Circle(c1r, c1center);
var c2r = 100;
var c2center = new Complex(c2r, MID);
var c2 = new Circle(c2r, c2center);
var c3r = Math.abs(c1.r) - c2.r;
var c3x = c2.center.re + c2.r + c3r;
var c3y = c2.center.im;
var c3center = new Complex(c3x, c3y);
var c3 = new Circle(c3r, c3center);
return [
[c1, c2, c3]
];
};

var aSymmetricSet = function() {
var c1r = -MID;
var c1center = new Complex(MID, MID);
var c1 = new Circle(c1r, c1center);
var c2r = 160;
var c2center = new Complex(c2r, MID);
var c2 = new Circle(c2r, c2center);
var c3r = Math.abs(c1.r) - c2.r;
var c3x = c2.center.re + c2.r + c3r;
var c3y = c2.center.im;
var c3center = new Complex(c3x, c3y);
var c3 = new Circle(c3r, c3center);
return [
[c1, c2, c3]
];
};

var nestedSet = function() {
var c1r = -MID;
var c1center = new Complex(MID, MID);
var c1 = new Circle(c1r, c1center);
var c2r = 160;
var c2center = new Complex(MID, c2r);
var c2 = new Circle(c2r, c2center);
var c3r = MID - 160;
var c3center = new Complex(MID, DIM - c3r);
var c3 = new Circle(c3r, c3center);
var ci1r = -c2r;
var ci1center = new Complex(MID, Math.abs(ci1r));
var ci1 = new Circle(ci1r, ci1center);
var ci2r = Math.abs(ci1r) / 2;
var ci2center = new Complex(MID, ci2r);
var ci2 = new Circle(ci2r, ci2center);
var ci3r = Math.abs(ci1r) - ci2.r;
var ci3x = ci2.center.re;
var ci3y = ci2r + ci2r + ci3r;
var ci3center = new Complex(ci3x, ci3y);
var ci3 = new Circle(ci3r, ci3center);
return [
[c1, c2, c3],
[ci1, ci2, ci3]
];
};

var sets = {
'Symmetric': symmetricSet(),
'Asymmetric': aSymmetricSet(),
'Nested': nestedSet()
};

var drawCircle = function (c) {
var absR = Math.abs(c.r);
var d = absR * 2;
var dx = (doc.width - DIM) / 2 - d / 2;
var dy = (doc.height - DIM) / 2 - d / 2;
return doc.pathItems.ellipse(
-c.center.im - dy, c.center.re + dx,
d, d);
};

var circles;
var group;

var draw = function(selectedSet) {
circles = [];
group.name = selectedSet;
var set = sets[selectedSet];
for (var i = 0; i < set.length; i++) {
var gasket = set[i];
}
for (var i = 0; i < circles.length; i++) {
drawCircle(circles[i]).moveToBeginning(group);
}
};

draw('Symmetric');
app.redraw();

// part 3: ScriptUI
var w = new Window("dialog");
var g = w.add("group");
var b1 = g.add("button", undefined, "Symmetric");
b1.preferredSize.width = 100;
var b2 = g.add("button", undefined, "Asymmetric");
b2.preferredSize.width = 100;
var b3 = g.add("button", undefined, "Nested");
b3.preferredSize.width = 100;
var b4 = w.add("button", undefined, "OK");
b4.preferredSize.width = 100;
var f1 = function (p1) {
doc.groupItems.removeAll();
draw(p1);
app.redraw();
};
b1.onClick = function () {
f1(b1.text);
};
b2.onClick = function () {
f1(b2.text);
};
b3.onClick = function () {
f1(b3.text);
};
w.show();``````

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 27, 2023 Sep 27, 2023

Copy link to clipboard

Copied

Perfectly wonderful, Femke.

Thanks for sharing.

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Explorer ,
Sep 27, 2023 Sep 27, 2023

Copy link to clipboard

Copied

@femkeblanco holy cow! That is impressive! Still always amazed at the genius of others.

Thank you so much for passing that along!

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Community Expert ,
Sep 27, 2023 Sep 27, 2023

Copy link to clipboard

Copied

LATEST

Thanks Femke, I am impressed again.