Skip to content

Instantly share code, notes, and snippets.

@monkstone
Created December 10, 2016 09:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkstone/14c1f185724c2ed1a67e2e8578abda3f to your computer and use it in GitHub Desktop.
Save monkstone/14c1f185724c2ed1a67e2e8578abda3f to your computer and use it in GitHub Desktop.
Refactored Circles Sketch
# Circles by Bárbara Almeida
# A fork of Circle through 3 points by Bárbara Almeida.
# Draw circles from 3 points moving on smooth random trajectories.
# https://www.openprocessing.org/sketch/211167
# JRubyArt version by Martin Prout
load_library :circles
attr_reader :points
def settings
size(800, 400, P2D)
end
def setup
sketch_title 'Circles From Three Moving Points'
color_mode(HSB, 360, 100, 100, 100)
ellipse_mode RADIUS
hint DISABLE_DEPTH_SORT
reset
end
def draw
no_stroke
reset if (frame_count % 8_000).zero?
points.each(&:update)
# set the style of the circle
@dc = map1d(millis, 0..150_000, 0..360) # slowly changes hue
stroke((@c + @dc) % 360, 50, 100, 5)
no_fill
# verifies if there is a circle and draw it
return if points.collinear?
draw_circle
end
def draw_circle
# find the bisectors of 2 sides
circle = Circumcircle.new(points)
circle.calculate
center_point = circle.center # find the center of the circle
# calculate the radius
radius = circle.radius
# if not collinear display circle
ellipse(center_point.x, center_point.y, radius, radius)
end
def reset
background 0
@c = rand(360)
@points = TPoints.new
(0..2).each { points << TPoint.new(Vec2D.new(rand(width), rand(height)))}
end
# frozen_string_literal: true
PBisector = Struct.new(:vector, :angle) # perpendicular bisector
Vect = Struct.new(:x, :y, :z) # for calculation of center
# Circumcircle from 3 points
class Circumcircle
include Math
attr_reader :center, :radius, :points
def initialize(points)
@points = points.vec
end
def calculate
ab = bisector(points[0], points[1]) # find 2 midpoints
bc = bisector(points[1], points[2])
@center = circumcenter(ab, bc)
@radius = center.dist(points[2]) # points[2] = c
end
def bisector(a, b)
midpoint = (a + b) / 2.0 # middle of ab (or bc)
theta = atan2(b.y - a.y, b.x - a.x) # slope of ab (or bc)
PBisector.new(midpoint, theta - PI / 2)
end
def circumcenter(pb1, pb2)
# equation of the first bisector (ax - y = -b)
a0 = tan pb1.angle
v0 = pb1.vector
a1 = tan pb2.angle
v1 = pb2.vector
eq0 = Vect.new(a0, -1, -1 * (v0.y - v0.x * a0))
eq1 = Vect.new(a1, -1, -1 * (v1.y - v1.x * a1))
# calculate x and y coordinates of the circumcenter
ox = (eq1.y * eq0.z - eq0.y * eq1.z) /
(eq0.x * eq1.y - eq1.x * eq0.y)
oy = (eq0.x * eq1.z - eq1.x * eq0.z) /
(eq0.x * eq1.y - eq1.x * eq0.y)
Vec2D.new(ox, oy)
end
end
# frozen_string_literal: true
require 'forwardable'
MAX_POINT = 3
# A collection of a maximum of 3 points in the processing world
# includes a collinearity test using Vec2D
class TPoints
extend Forwardable
def_delegators(:@points, :each, :map, :size, :shift, :clear, :[])
include Enumerable
attr_reader :points
def initialize
@points = []
end
def <<(pt)
points << pt
shift if size > MAX_POINT
end
def collinear?
full? ? (vec[0] - vec[1]).cross(vec[1] - vec[2]).zero? : false
end
def vec
points.map { |point| point.pos }
end
def full?
points.length == MAX_POINT
end
end
# frozen_string_literal: true
# particle and triangle point
class TPoint
include Processing::Proxy
attr_reader :pos, :vel, :accel, :xbound, :ybound
def initialize(position)
@pos = position
@vel = Vec2D.new
@accel = Vec2D.random
@xbound = Boundary.new(0, width)
@ybound = Boundary.new(0, height)
end
def direction
@accel = Vec2D.random * rand if rand > 0.96
end
def update
@vel += accel
# @vel.set_mag(1.5) { vel.mag > 1.5 }
@pos += vel
check_bounds
direction
end
private
def check_bounds
if xbound.exclude? pos.x
@vel.x = 0
@accel.x *= rand(-0.9..-0.09)
end
if ybound.exclude? pos.y
@vel.y = 0
@accel.y *= rand(-0.9..-0.09)
end
end
end
# we are looking for excluded values
Boundary = Struct.new(:lower, :upper) do
def exclude?(val)
true unless (lower...upper).cover? val
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment