Skip to content

Instantly share code, notes, and snippets.

@eregon
Created June 21, 2010 11:05
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save eregon/446707 to your computer and use it in GitHub Desktop.
# Ruby Quiz #234 : Random Points within a Circle
# Benoit Daloze
include Math
class Point < Struct.new(:x, :y)
def distance to
hypot(x-to.x, y-to.y)
end
def + other
Point.new(x+other.x, y+other.y)
end
def * n
Point.new(*map { |v| v*n })
end
def inspect
"(#{x},#{y})"
end
alias :to_s :inspect
end
class Circle < Struct.new(:center, :radius)
def include? point
center.distance(point) <= radius
end
def generate_angle
angle = rand * 2*PI
distance = sqrt(rand) * radius # sqrt(rand) is needed for correct distribution
center + Point.new(cos(angle), sin(angle))*distance
end
def generate_square_sample(step = 0.1)
@points_in_circle ||= begin
points_in_circle = []
(center.y-radius..center.y+radius).step(step) { |y|
(center.x-radius..center.x+radius).step(step) { |x|
if include?(p = Point.new(x,y))
points_in_circle << p
end
}
}
points_in_circle
end
point = @points_in_circle.sample
begin
rand_point = Point.new(*point.map { |v| v + rand*(2*step) - step })
end until include? rand_point
rand_point
end
alias :generate :generate_angle
end
circle = Circle.new(Point.new(-2, 4), 5)
generated = []
100_000.times {
generated << g = circle.generate
puts "#{g} not in #{c}" unless circle.include? g
}
stats = generated.each_with_object(Hash.new(0)) { |point, h|
h[Point.new(*point.map { |v| v.round(2) })] += 1
}
def text_stats(stats)
puts "min: #{stats.values.min}, moy, #{stats.values.reduce(:+).to_f/stats.size}, max: #{stats.values.max}"
puts "max Point: #{stats.max_by(&:last).first}"
end
text_stats(stats)
def rmagick_draw(stats, circle, size = 750)
require 'RMagick'
include Magick
image = Image.new(size, size)
max = stats.values.max
Draw.new.instance_exec {
stats.each_pair { |point, value|
# This is heavily convoluted on purpose :)
fill "rgb(#{([255 - (Rational(value*255, max)).round]*3).join(',')})"
point(*point.each_pair.map { |axis, v|
Rational((v-circle.center[axis])*size, circle.radius*2).round + size/2
})
}
draw(image)
}
image.display
end
rmagick_draw(stats, circle)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment