Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active November 28, 2015 10:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/0e1c471d27ac4fa47cd4 to your computer and use it in GitHub Desktop.
Save JoshCheek/0e1c471d27ac4fa47cd4 to your computer and use it in GitHub Desktop.
Drawing planets with chunky.png
# initial inspiration https://twitter.com/thereaIbanksy/status/670406732066111488
# pictures of output https://twitter.com/josh_cheek/status/670460393681256448
require 'chunky_png'
Point = Struct.new :x, :y do
def +(point)
self.class.new x+point.x, y+point.y
end
def *(n)
self.class.new x*n, y*n
end
end
Edge = Struct.new :from, :to do
def x0; from.x; end
def y0; from.y; end
def x1; to.x; end
def y1; to.y; end
def draw_on(png, colour=WHITE)
png.line from.x,from.y, to.x,to.y, colour
end
end
BROWN = ChunkyPNG::Color.rgba 0x2A, 0x21, 0x1c, 255
WHITE = ChunkyPNG::Color.rgba 0xFF, 0xFF, 0xFF, 255
class Planet
TWO_PI = Math::PI*2
attr_reader :radius, :speed, :angle
def initialize(radius:, speed:1, angle:0, center_x:, center_y:)
@radius, @speed, @angle, @locations, @center_x, @center_y = radius, speed, angle, {}, center_x, center_y
end
def align_with(planet)
@angle = planet.angle
end
def orbit!(duration=1)
@angle += duration*speed
@angle -= 360 while angle > 360
self
end
def location
@locations[angle] ||= Point.new(x.to_i, y.to_i)
end
def x
@center_x + Math.cos(rad(angle))*radius
end
def y
@center_y + Math.sin(rad(angle))*radius
end
end
def rad(a)
a*Math::PI/180
end
width = height = 1000
colours = [BROWN, WHITE]
png = ChunkyPNG::Image.new width, height, BROWN
p1 = Planet.new(radius: 200, speed: 5, center_x:width/2, center_y:height/2)
p2 = Planet.new(radius: 400, speed: 0, center_x:width/2, center_y:height/2)
p3 = Planet.new(radius: 450, speed: 13, center_x:width/2, center_y:height/2)
# To allow it to vary elegantly across the colour space, use (math.sin(angle)*127.5+128).to_i
# This will move as a sine wave, along an axis that splits it evenly
# (if you use 127 or 128, it will go out of bounds and one of the lines will be conspicuously out of place
# 361.times.map { |i|
# r = i*Math::PI/180
# (Math.sin(r)*127.5+128).to_i
# }.minmax # => [0, 255]
alignment = [p1,p3]
720.times do |i|
loc = p2.location
if i%30 == 0
alignment.rotate! 1
p2.align_with alignment.first
end
r = rad(i)
colour1 = ChunkyPNG::Color.rgb (Math.sin(r)*127.5+128).to_i, 0, 0xFF
colour2 = ChunkyPNG::Color.rgb 0xFF, (Math.sin(r)*127.5+128).to_i, 0
Edge.new(p1.location, p2.location).draw_on(png, colour1)
Edge.new(p3.location, p2.location).draw_on(png, colour2)
p1.orbit!
p2.orbit!
p3.orbit!
end
num = Dir['orbits*.png'].map { |name| name[/\d+/].to_i }.max.next
name = "orbits#{num}.png"
png.save name, interlace: true
`which open && open #{name}`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment