Created
December 10, 2016 09:55
-
-
Save monkstone/14c1f185724c2ed1a67e2e8578abda3f to your computer and use it in GitHub Desktop.
Refactored Circles Sketch
This file contains hidden or 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
# 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 |
This file contains hidden or 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
# 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 |
This file contains hidden or 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
# 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 |
This file contains hidden or 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
# 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