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

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

874

Translate

Translate

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 guidelines

correct answers 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 

 

femkeblanco_0-1694381993493.png

 

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

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

Votes

Translate

Translate
Adobe
Community Expert ,
Sep 08, 2023 Sep 08, 2023

Copy link to clipboard

Copied

they are called Fractals

 

the first is called Apollonian Gasket

https://www.wikihow.com/Create-an-Apollonian-Gasket

 

the second is called Sierpinski Triangle

https://www.youtube.com/watch?v=j6WYSdHuWgY

 

Votes

Translate

Translate

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 guidelines
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

Screen Hex 01.pngScreen Hex 02.pngScreen Hex 03.png

Votes

Translate

Translate

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 guidelines
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. 

Votes

Translate

Translate

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 guidelines
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. 

Votes

Translate

Translate

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 guidelines
Community Expert ,
Sep 09, 2023 Sep 09, 2023

Copy link to clipboard

Copied

usually these images are generated programmatically to place items precisely

Votes

Translate

Translate

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 guidelines
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.

Votes

Translate

Translate

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 guidelines
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 

 

femkeblanco_0-1694381993493.png

 

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();

 

Votes

Translate

Translate

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 guidelines
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! 

Votes

Translate

Translate

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 guidelines
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.

 

Votes

Translate

Translate

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 guidelines
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).

Votes

Translate

Translate

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 guidelines
Guide ,
Sep 12, 2023 Sep 12, 2023

Copy link to clipboard

Copied

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

Votes

Translate

Translate

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 guidelines
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!

Votes

Translate

Translate

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 guidelines
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 of course be manually scaled.

 

(NB.  All credit to the original creator; I just rewrote it for Illustrator.)

 

femkeblanco_0-1695835513434.png

 

// 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 s = k1.add(k2).add(k3);
    var k12 = k1.mul(k2);
    var k13 = k1.mul(k3);
    var k23 = k2.mul(k3);
    var ksum = k12.add(k13).add(k23);
    return ksum.sqrt().mul(2).add(s);
};

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;
    var center = c1.bc.add(c2.bc).add(c3.bc).mul(2).sub(c4.bc).div(bend);
    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) {
        addCircle(cn2);
        recurse(cn2, c1, c3, c4, depth + 1);
    }
    if (cn3.r > MIN_R) {
        addCircle(cn3);
        recurse(cn3, c1, c2, c4, depth + 1);
    }
    if (cn4.r > MIN_R) {
        addCircle(cn4);
        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)
    addCircle(c1);
    addCircle(c2);
    addCircle(c3);
    addCircle(c4);
    addCircle(c5);
    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 = doc.groupItems.add();
    group.name = selectedSet;
    var set = sets[selectedSet];
    for (var i = 0; i < set.length; i++) {
        var gasket = set[i];
        drawGasket(gasket[0], gasket[1], gasket[2]);
    }
    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();

 

Votes

Translate

Translate

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 guidelines
Community Expert ,
Sep 27, 2023 Sep 27, 2023

Copy link to clipboard

Copied

Perfectly wonderful, Femke.

 

Thanks for sharing.

 

Votes

Translate

Translate

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 guidelines
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! 

Votes

Translate

Translate

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 guidelines
Community Expert ,
Sep 27, 2023 Sep 27, 2023

Copy link to clipboard

Copied

LATEST

Thanks Femke, I am impressed again.

Votes

Translate

Translate

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 guidelines