|
| 1 | +#!/usr/bin/env jruby |
| 2 | +# coding: utf-8 |
| 3 | +require 'propane' |
| 4 | + |
| 5 | +## Circles by Bárbara Almeida |
| 6 | +## A fork of Circle through 3 points by Bárbara Almeida. |
| 7 | +## Draw circles from 3 points moving on smooth random trajectories. |
| 8 | +## https://www.openprocessing.org/sketch/211167 |
| 9 | + |
| 10 | +## Propane version by Jérémy Laviole - @poqudrof |
| 11 | + |
| 12 | +class Circles < Propane::App |
| 13 | + |
| 14 | + def settings |
| 15 | + size(800, 600, P3D) |
| 16 | + end |
| 17 | + |
| 18 | + ## To be overriden by the Presentation Code. |
| 19 | + def setup |
| 20 | + colorMode(HSB, 360, 100, 100, 100); |
| 21 | + @c = random(360); |
| 22 | + |
| 23 | + @points = [] |
| 24 | + 3.times { @points << Points.new(random(width),random(height)) } |
| 25 | + |
| 26 | + background 0 |
| 27 | + @setup_done = true |
| 28 | + end |
| 29 | + |
| 30 | + def draw |
| 31 | + fill(0, 0, 0); |
| 32 | + noStroke |
| 33 | + |
| 34 | + if (frameCount % 8000 == 0) |
| 35 | + rect(0, 0, width, height); |
| 36 | + end |
| 37 | + |
| 38 | + @points.each do |point| |
| 39 | + ##change direction sometimes |
| 40 | + point.setDir random(-Propane::PConstants::PI, Propane::PConstants::PI) if (random(1) > 0.96) |
| 41 | + point.update |
| 42 | + point.checkEdges |
| 43 | + end |
| 44 | + |
| 45 | + ## set the style of the circle |
| 46 | + @dc = Propane::PApplet::map(millis(), 0, 150000, 0, 360) ## slowly changes hue |
| 47 | + stroke((@c + @dc) % 360, 50, 100, 5) |
| 48 | + noFill |
| 49 | + |
| 50 | + ## verifies if there is a circle and draw it |
| 51 | + |
| 52 | + det = (@points[0].p.x * @points[1].p.y) + (@points[1].p.x * @points[2].p.y) + (@points[2].p.x * @points[0].p.y); |
| 53 | + |
| 54 | + det -= (@points[0].p.y * @points[1].p.x) + (@points[1].p.y * @points[2].p.x) + (@points[2].p.y * @points[0].p.x); |
| 55 | + |
| 56 | + |
| 57 | + draw_circle @points if Propane::PApplet::abs(det) > 50 |
| 58 | + end |
| 59 | + |
| 60 | + |
| 61 | + def draw_circle(pts) |
| 62 | + |
| 63 | + ## find the midpoints of 2 sides |
| 64 | + mp = [] |
| 65 | + mp[0] = midpoint(pts[0].p, pts[1].p); |
| 66 | + mp[1] = midpoint(pts[1].p, pts[2].p); |
| 67 | + |
| 68 | + center_point = center(mp); ## find the center of the circle |
| 69 | + r = dist(center_point.x, center_point.y, pts[2].p.x, pts[2].p.y); ##calculate the radius |
| 70 | + |
| 71 | + ellipse(center_point.x, center_point.y, 2*r, 2*r); ## if not collinear display circle |
| 72 | + end |
| 73 | + |
| 74 | + def midpoint(a, b) |
| 75 | + d = dist(a.x, a.y, b.x, b.y); ## distance AB |
| 76 | + theta = atan2(b.y - a.y, b.x - a.x); ## inclination of AB |
| 77 | + p = Propane::PVector.new(a.x + d/2* Propane::PApplet::cos(theta), |
| 78 | + a.y + d/2* Propane::PApplet::sin(theta), # midpoint |
| 79 | + theta - Propane::PConstants::HALF_PI); #inclination of the bissecteur |
| 80 | + return p |
| 81 | + end |
| 82 | + |
| 83 | + def center(mid_point) |
| 84 | + eq = [] |
| 85 | + |
| 86 | + ## equation of the first bissector (ax - y = -b) |
| 87 | + mid_point.each do |mp| |
| 88 | + a = tan mp.z |
| 89 | + eq << Propane::PVector.new(a, |
| 90 | + -1, |
| 91 | + -1*(mp.y - mp.x*a)) |
| 92 | + end |
| 93 | + |
| 94 | + ## calculate x and y coordinates of the center of the circle |
| 95 | + ox = (eq[1].y * eq[0].z - eq[0].y * eq[1].z) / |
| 96 | + (eq[0].x * eq[1].y - eq[1].x * eq[0].y); |
| 97 | + oy = (eq[0].x * eq[1].z - eq[1].x * eq[0].z) / |
| 98 | + (eq[0].x * eq[1].y - eq[1].x * eq[0].y); |
| 99 | + return Propane::PVector.new(ox,oy); |
| 100 | + end |
| 101 | +end |
| 102 | + |
| 103 | + |
| 104 | +class Points |
| 105 | + |
| 106 | + include Propane::Proxy |
| 107 | + attr_accessor :p, :velocity, :acceleration |
| 108 | + |
| 109 | + def initialize(x, y) |
| 110 | + @p = Propane::PVector.new(x, y, 1) |
| 111 | + @velocity = Propane::PVector.new(0, 0, 0); |
| 112 | + @acceleration = Propane::PVector.new($app.random(1), $app.random(1), 0) |
| 113 | + end |
| 114 | + |
| 115 | + # change direction |
| 116 | + def setDir(angle) |
| 117 | + ## direction of the acceleration is defined by the new angle |
| 118 | + acceleration.set(Propane::PApplet::cos(angle), Propane::PApplet::sin(angle), 0); |
| 119 | + |
| 120 | + ## magnitude of the acceleration is proportional to the angle between acceleration and velocity |
| 121 | + acceleration.normalize |
| 122 | + dif = Propane::PVector::angleBetween(acceleration, velocity) |
| 123 | + dif = Propane::PApplet::map(dif, 0, Propane::PConstants::PI, 0.1, 0.001) |
| 124 | + acceleration.mult(dif); |
| 125 | + end |
| 126 | + |
| 127 | + ## update position |
| 128 | + def update |
| 129 | + velocity.add(acceleration); |
| 130 | + velocity.limit(1.5); |
| 131 | + p.add(velocity); |
| 132 | + end |
| 133 | + |
| 134 | + def checkEdges |
| 135 | + p.x = constrain(p.x, 0, $app.width) |
| 136 | + p.y = constrain(p.y, 0, $app.height) |
| 137 | + end |
| 138 | +end |
| 139 | + |
| 140 | +Circles.new |
0 commit comments