Skip to content

Animating Sierpinski triangle

kkrmno edited this page Mar 19, 2020 · 1 revision

Generating animated Sierpinski triangle

require "imgrb"

width = 400
height = 400

#Grayscale image of size 400x400 filled with black
image_0 = Imgrb::Image.new(width, height, [0, 255])

#Iterated Sierpinski triangle generates the sequence
#used for the animation.
rng = Random.new(0) #Seeded for reproducibility
frames = 24*8 #Number of frames of animation
points_per_frame = 600 #Number of points to generate per frame

#Vertices of the triangle
p0 = [width/2, 0]
p1 = [width-1, height-1]
p2 = [0, height-1]

#Starting point
new_p = [(p0[0]+p1[0]+p2[0])/3, (p0[1]+p1[1]+p2[1])/3]

#Generating frames
frames.times do
  #Create the next frame in the sequence
  image_i = Imgrb::Image.new(width, height, [0, 0])
  points_per_frame.times do
    move_towards = p0
    vertex_idx = rng.rand(3)
    if vertex_idx == 1
      move_towards = p1
    elsif vertex_idx == 2
      move_towards = p2
    end

    new_p[0] = new_p[0]/2 + move_towards[0]/2
    new_p[1] = new_p[1]/2 + move_towards[1]/2

    image_i.set_pixel(new_p[0], new_p[1], [255, 10])
  end
  #Add new frame data with 0 offset
  x_offset = 0
  y_offset = 0

  #Each frame should display for 1/24 of a second
  delay_numerator = 1
  delay_denominator = 24

  #In this case we can leave the pixels from the last frame and
  #simply blend in the pixels that have been added using alpha
  #compositing. I.e., we do nothing for the dispose step, and
  #use the :over blend option to overlay the pixel data of the
  #next frame. This way we end up with a much smaller file, since
  #the pixel data of each frame consists of mostly 0s.
  dispose_op = :none
  blend_op = :over

  image_0.push_frame(image_i, x_offset, y_offset,
                    delay_numerator, delay_denominator,
                    dispose_op, blend_op)

end

#Add a comment describing the image.
image_0.add_text("Comment", "This is an animated png illustrating an iterated approach to constructing the Sierpinski triangle.")

image_0.save("animated_sierpinski.png")