Last active
November 28, 2015 10:53
-
-
Save JoshCheek/0e1c471d27ac4fa47cd4 to your computer and use it in GitHub Desktop.
Drawing planets with chunky.png
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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