this post was submitted on
139 points (78% like it)
193 up votes 54 down votes
all 46 comments

[–]GoldyOrNugget 46 points47 points ago

Neeaaaaat. I just wrote it recursively and although it doesn't have the same transparency effect, the general black/white regions are preserved. Here's a side-by-side comparison of traditional sierpinski and this: http://i.imgur.com/2FYhL.png (colours inverted for consistency).

CODE:

from turtle import *

ratio = 1 / 1.6180339887
up()
goto(-800,-400)
down()

tracer(1000)

def sierpinski(length):
    if length >= 3:
        sierpinski(length * ratio)

        left(60)
        forward(length * ratio)
        right(60)
        sierpinski(length * ratio)

        right(60)
        forward(length * ratio)
        left(60)
        sierpinski(length * ratio)

        backward(length * ratio)


sierpinski(500)

ratio = 0.5
up()
goto(0, -400)
down()

sierpinski(800)

raw_input()

[–]VerilyAMonkey 10 points11 points ago

Random note, instead of ratio = 1 / 1.6180339887, you can just do ratio = 0.6180339887. phi ^ -1 = phi -1, phi 2 = phi+1.

[–]SierpinskisTriangle 13 points14 points ago

I like how few lines of code this is! What programming language is it?

Disclaimer: I know nothing about programming.

[–]ReallyGoodAdvice 22 points23 points ago

It's Python

[–]whiteandnerdy1729 20 points21 points ago

Python has turtle? BRB - revisiting my youth.

[–]Haiavaha 17 points18 points ago

Python has everything.

[–]gramathy 10 points11 points ago

Also:

    import soul

[–]jmau5 2 points3 points ago

Personally, I was always a fan of:

import __future__

[–]GoldyOrNugget 1 point2 points ago

This isn't an easter egg though. future is a module for features that will be fully implemented in later versions of Python, but can still be used in the current version version. For example,

from __future__ import division

in Python 2.x makes the division operator perform float division regardless of whether its operands are integers or floats, just like in Python 3.x.

[–]jmau5 1 point2 points ago

Aware of this, I am. Still like the idea of importing the future, I do.

[–]woodyb 1 point2 points ago

My favorite is:

from __future__ import braces

[–]nickem 2 points3 points ago

Curious, is Python being used to make printable 3D fractal objects?

[–]adelie42 0 points1 point ago

I would guess not because despite the conceptual idea of plotting a point, in reality that leaves a lot to the imagination. 3D printers like models that it can actually create in reality. Unlike a path for an arm to move across, 3D printers duplicate what they are given. If the model couldn't really exist as designed, you tend to get strange and undesirable results.

Arguably, this is a missing feature of the driver. Consider how new 3D printing is; at present the software just gets you from A to B.

TL;DR Computers do what you say, not what you mean.

[–]GnarlinBrando 4 points5 points ago

The world would be a very scary places if computers did what we mean and not what we say.

[–]m1ss1ontomars2k4 1 point2 points ago

It's not very many lines in a lot of programming languages, actually.

[–]whatatwit 0 points1 point ago

You can learn easily here.

[–]sigstoat 5 points6 points ago

looks like a sierpinski carpet made out of a triangle, instead of a square.

[–]shaggorama 2 points3 points ago

goto? turtle? wow...that takes me back

[–]Horatorobor 1 point2 points ago

So I started learning Python last week, how long till I'm able to stuff like that? Or if you could give some indications about this kind of stuff I'd be happy.

[–]GoldyOrNugget 8 points9 points ago

You mean how long will it take to draw pretty pictures? All you really need is functions, loops and if-statements, so in terms of syntax it won't take long at all to learn. I used the turtle module to draw those pictures -- it's intended for Python beginners, but you can do some pretty cool stuff in it.

When making fractals themselves, the hardest part is translating the image of the fractal you have in your head into a recursive definition. I recommend starting with something like the Koch curve and moving on from there. There are also many fractals which can be generated easily without recursion, such as the dragon curve or the Sierpinksi triangle as OP was doing it (using the chaos game).

Here's the Koch curve:

from turtle import *

def koch(dist):
    for angle in (60, -120, 60, 0):
        # 10 is the break case. 3.0 is the line:subline ratio
        if dist <= 10:  
            forward(dist / 3.0)
        else: 
            koch(dist / 3.0)
        left(angle)

koch(400)

Here's a fern I made using the same principles.

[–]Horatorobor 2 points3 points ago

How cool is that, it started drawing cool stuff. Many thanks.

[–]theroc1217 1 point2 points ago

Oh wow, this is much more helpful. It's essentially a Sierpinski triangle, with this small change: every black triangle in the original is filled with a regular Sierpinski triangle.

[–]13_0_0_0_0 0 points1 point ago

Holy shit I haven't seen turtle since the early 80s! I know how I'm going to waste time tomorrow.

[–]harrisonbeaker 43 points44 points ago*

What you've done is built an iterated function system and let it run. It's a nice and relatively easy fact to prove that as long as each individual function is a contraction (it brings points closer together), the system will result in an attractor with some self-similarity.

Many times this will end up ugly or boring, but occasionally you can hit on some nice patterns.

There isn't such a thing as an 'established' fractal. There are the handful of famous ones, but then there are also the thousands of other beautiful images produced by hordes of comp sci and math students every semester.

To get a better intuitive idea of why yours looks like that, note that a chaos game is really just a way to approximate a standard iterated function system. Your system has 3 functions:

f1(x,y) = (1/phi * x, 1/phi * y)

f2(x,y) = (1/phi * x + (1-1/phi), 1/phi * y)

f3(x,y) = (1/phi * x + (1/2 * 1/phi), 1/phi * y +sqrt(3) * 1/phi)

Now start with an equilateral triangle T0 with one corner at the origin and side lengths one. Each of these functions shrinks the triangle (by a factor of phi in your case) and shifts it to re-approximate the original triangle. We say that F(T0) = T1 is the union of each of these three 'images' of T0. Now we do the same thing, using T1 as our starting point.

Since these triangles overlap you end up with your transparency and if you play through the first few iterates you start to see your pattern develop. Note that if you replace phi by 2, you get the sierpinski triangle.

EDIT: I think I messed up the functions a bit. Rather than do all the algebra to correct them, it's easier and more informative to describe what they do. f1 shrinks the entire triangle by the desired factor (in this case 1/phi) and leaves the bottom left corner on the origin. f2 shrinks, then scoots small triangle over so that the right corner is the point (1,0). And finally f3 shrinks and scoots the small triangle up and over so the top is at (1/2,1). The reason for these translations is to keep the iterations bounded inside the original triangle. Since you're using a factor larger than 1/2, there will be plenty of overlapping.

[–]shaggorama 6 points7 points ago

Back in elementary school (the 80's) our "computer teacher" used to have us play with turtles in LOGO. She didn't really teach us anything useful unfortunately, but I remember figuring out that if I gave the turtle a handful of simple but random directions that sent the turtle whizzing long lines all over the screen (generally random values longer than the canvas), sometimes I'd get junk, but sometimes I'd get things that looked almost like 3D wireframe landscapes. I felt pretty badass.

[–]lycium 2 points3 points ago

came here to write this, you did an excellent job :)

[–]coveritwithgas 13 points14 points ago

What did 1/3 and 1/5 yield? Without them, I'm on the fence as to whether this is something or not.

[–]aurath[S] 4 points5 points ago

Wow! Thanks for the feedback guys, interesting stuff. I thought I'd post the processing code as it currently stands in case anyone wants to screw with it. Keep in mind processing isn't the fastest thing in the world and it will take a while to run. Press any key to save a screenshot.

int s = 800; //Size of one side of the triangle in pixels
float[][] mp = new float[3][2]; // The triangles main points
float[] p = new float[2];

void setup(){
  int w = s; int h = round(.866 * w); //Sets the width and height based on the triangle edge length
  size(w, h);
  background(0);
  stroke(255);
  frameRate(3000);

  //Set the main points of the triangle
  mp[0][0] = w / 2; mp[0][1] = 0;
  mp[1][0] = 0;     mp[1][1] = h;
  mp[2][0] = w;     mp[2][1] = h;

  p[0] = random(w); p[1] = random(h); //picks a starting point  
}

void draw(){
  int rp = floor(random(mp.length)); //picks an index for a random main point to jump towards.

  //Interpolate between the two points
  float xdiff = p[0] - mp[rp][0];
  float ydiff = p[1] - mp[rp][1];
  p[0] -= xdiff * 0.381966;
  p[1] -= ydiff * 0.381966;

  //Draw the new point
  int x = int(p[0]); int y = int(p[1]);
  color c = get(x, y);
  c = lerpColor(c, color(255), 0.03);
  set(x, y, c);
}

void keyPressed(){
  saveFrame();
}

[–]VousEtMoi 2 points3 points ago*

It takes a while to run because there is a limit to the framerate you can achieve. Processing doesn't allow 3000 fps. Put a for loop in there, and it becomes much, MUCH faster. Like so:

void draw(){
      for(int i=0; i<2000; ++i) {
        int rp = floor(random(mp.length));
        float xdiff = p[0] - mp[rp][0];
        float ydiff = p[1] - mp[rp][1];
        p[0] -= xdiff * 0.381966;
        p[1] -= ydiff * 0.381966;
        int x = int(p[0]); int y = int(p[1]);
        color c = get(x, y);
        c = lerpColor(c, color(255), 0.03);
        set(x, y, c);
    }
}

You can thank me later ;)

[–][deleted] 2 points3 points ago

r/fractalporn would like this.

[–]calabazasupremo 1 point2 points ago

mmm… dat self similarity

[–]ScallopPusher 4 points5 points ago

There is a post here in r/math that should help you: http://www.reddit.com/r/math/comments/p2297/interactive_chaos_game_path_plotter/ or direkt: http://koozdra.ca/chaosgame/pathPlotter5.html

try the Triangle fixed 1.618 setting (Golden Ratio)

[–]koozdra 4 points5 points ago

If you use a hexagon, the magnitudes 0.5 and 1.5 draw the same image: Hexagon chaos game inner zoom

[–]FarDareisMai 2 points3 points ago

I'm not much of a programmer, but I do have a lot of experience with fractal art, so I opened up Apophysis and ran with the idea until I made this. Sorry I can't answer any of your questions but I thought you might be interested nonetheless.

[–]zserf 2 points3 points ago

You will get fractals like this if you do anything in the correct range. Anything larger than 1/2 gets you overlapping triangles, and anything smaller than 2/3 gets you empty space. It just so happens that phi is in the right range to have both of these properties be easily observable. Values between .6 and .63 look the best to me.

I'm having trouble with imgur, but if you have java you can play around with this code, which goes quite quickly.

public class Serpenski{  
public static void main(String[] args){  
    double x=Double.parseDouble (args [0]);  
    double y=Double.parseDouble (args [1]);  
    double a=Double.parseDouble (args [2]);  
    double b=Double.parseDouble (args [3]);  
    double point1x=0;  
    double point1y=0;  
    double point2x=1;  
    double point2y=0;  
    double point3x=.5;  
    double point3y=.86603;  
    StdDraw.setXscale(0.0, 1.0);  
    StdDraw.setYscale(0.0, 1.0);  
    StdDraw.show (0);  
    for (double i=1.0; i<=100000; i++){  
        double r=Math.random();  
        if (r<(.333)){                   
            StdDraw.point(((a*point1x+b*x)/(a+b)),((a*point1y+b*y)/(a+b)));  
            x=(a*point1x+b*x)/(a+b);  
            y=(a*point1y+b*y)/(a+b);  
        }  
        else if (r<(.667)){  
            StdDraw.point(((a*point2x+b*x)/(a+b)),((a*point2y+b*y)/(a+b)));  
            x=(a*point2x+b*x)/(a+b);  
            y=(a*point2y+b*y)/(a+b);}  
        else {  
            StdDraw.point(((a*point3x+b*x)/(a+b)),((a*point3y+b*y)/(a+b)));  
            x=(a*point3x+b*x)/(a+b);  
            y=(a*point3y+b*y)/(a+b);}  
    }  
    StdDraw.show (0);  
}  

}

Change all the &lt to < . I'm not sure why reddit is switching that.

[–]Scorcherr 1 point2 points ago

I did fool around with this as a kid (hahh.. TurboPascal, good times, good times!). Try 4 or more vertices (don't remember if I stayed at 1/2 jumps), arranged as a cross, a star, ... funny things will happen. :)

[–]Platz 1 point2 points ago

Also, works nicely as my smartphone wallpaper. Thanks!

[–]de_la_Seoul 1 point2 points ago

greatest triforce ever.

[–]newton1996 0 points1 point ago

First, a question: Have you tried starting from all three vertices with ratio 1/4 or 1/5 and overlaying the results?

Now, comments: Serpinski gasket can be considered as the following set:

Every point in the triangle has 3 barycentric coordinates between 0 and 1, with sum equal to 1, see http://en.wikipedia.org/wiki/Barycentric_coordinate_system_%28mathematics%29 We write this [a,b,c] (with a+b+c=1).

Now write those in binary. What can the first bits of the three coordinates be? Well, the coordinates add up to 1=1/2+1/4+1/8+.., which means that the most significant digits have to add up to 1. If there is a carry from the second most significant digit, then the first bits are (0,0,0) - with the carry providing the 1. If there is no carry then the first bits are (1,0,0) or (0,1,0) or (0,0,1). So we get 4 possibilities. These options divide the triangle into 4 smaller pieces - one for each possibility. The first one is the middle triangle of teh Serpinski construction, that we take out at the first stage, and the other 3 are the three "corner" triangle that remain. Now let's assume we are in one of the 3 later cases, and let's consider the second most significant bits (the quarters). Sine we know we get no carry, we again have to have those add up to 0 if there is a carry from the eights, and to 1 if there is no such carry. So each of our three triangles is again divided into 4 parts, and 3 that remain in Serpinski construction are the ones that have exactly one non-zero bit in the 1/4's place. And so on. The conclusion is that Serpinski gasket is the set of those points in th triangle, for which the binary expansion of the barycentric coordinates has exactly one 1 in each position (i.e. out of 3 bits in each 1/2k place exactly one is 1).

The plotting construction starts with [1, 0, 0] which has 1=.11111111..., 0=.000000...., 0=.0000000 which indeed has exactly one 1 in each position. At each stage the barycentric coordinates [a, b, c] go to [a/2, b/2, c/2+1] (if we move towards the third vertex). In binary, all coordinates are shifted once to the right and the .1 is added to the third coordinate. This clearly preserves the property of having exactly one 1 in each position. And, i fact, you can see that you can get to any triple of coordinates with this property by repeating these moves. That's why the program plots the serpinsky gasket.

Now for the other ratios you could write the barycentric coordinates in base 3 or 5 and do similar analysis to see which sets you would get. I think you still get nice sets if you seed from all three vertices.

For the golden ratio, I think you could use the golden-ratio based number system http://en.wikipedia.org/wiki/Golden_ratio_base to see what the map does....

[–]dietaryfiber0 0 points1 point ago

I was messing around with this after this post and wrote a Java program for a Sieprinski Hexagon (same thing, but with a hexagon, as you probably could have guessed).

You can do the same thing with one over the golden ratio, and you get this: http://i.imgur.com/nI0Ge.png As opposed to the standard 2/3 ratio, which gives: http://i.imgur.com/GTU0m.png

I don't know much about fractals to understand the difference, but it's certainly cool!

[–]WarzoneOfDefecation -1 points0 points ago

mid point from a random point within the triangle to its closest vertex. We did this in highschool, its a neat little fractal.

[–][deleted] ago

[deleted]