Skip to content

Commit fcfdcc0

Browse files
committed
alternative
1 parent 8bbbe22 commit fcfdcc0

File tree

5 files changed

+172
-0
lines changed

5 files changed

+172
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Loosely based on a sketch by Bárbara Almeida
2+
# https://www.openprocessing.org/sketch/179567
3+
# Here is a sketch that clearly demonstrates some of the most egregious parts of
4+
# vanilla processing:-
5+
# PVector is over complicated and overloads 2D and 3D functionality, cf Vec2D
6+
# JRubyArt and propane which behaves as a 2D vector (cross product is a float)
7+
# and can easily be used in chain calculations.
8+
9+
##################################################
10+
# Usage click on screen with mouse to generate a point, repeat as required
11+
# to create a triangle, and the circumcircle will be drawn unless the points are
12+
# collinear. Additional clicks erase the first point and add a new point. To
13+
# demonstrate the stupid processing coordinate convention press 'c' or 'C', you
14+
# will see the graph is inverted and origin y is top left, also demonstrates
15+
# the collinearity test press space-bar to clear
16+
##################################################
17+
18+
load_library :simple_circle # but does not use math_point
19+
20+
attr_reader :pnt, :points, :circle, :renderer
21+
22+
def settings
23+
size 800, 800, P2D
24+
# pixel_density(2) # for HiDpi screens
25+
# smooth # see https://processing.org/reference/smooth_.html
26+
end
27+
28+
def setup
29+
sketch_title 'Simplified Circumcircle Sketch'
30+
@pnt = Vec2D.new
31+
@points = SimplePoints.new
32+
ellipse_mode RADIUS
33+
@renderer = AppRender.new(self)
34+
end
35+
36+
def draw
37+
graph_paper
38+
stroke_weight 4
39+
stroke 200, 0, 0
40+
point(pnt.x, pnt.y)
41+
points.map { |pt| point(pt.x, pt.y) }
42+
return unless points.full?
43+
return render_triangle if points.collinear? # Renders a straight line
44+
circle = Circumcircle.new(points)
45+
circle.calculate
46+
center = circle.center
47+
point(center.x, center.y)
48+
no_fill
49+
stroke_weight 2
50+
render_triangle
51+
stroke 0, 0, 255, 100
52+
ellipse(center.x, center.y, circle.radius, circle.radius)
53+
end
54+
55+
def mouse_pressed
56+
points << Vec2D.new(mouse_x, mouse_y)
57+
end
58+
59+
def render_triangle
60+
stroke 255, 255, 0, 100
61+
begin_shape
62+
points.each do |point|
63+
point.to_vertex(renderer)
64+
end
65+
end_shape(CLOSE)
66+
end
67+
68+
def key_pressed
69+
case key
70+
when ' '
71+
points.clear
72+
when 'c', 'C'
73+
(0..400).step(200) do |i|
74+
points << Vec2D.new(i, i)
75+
end
76+
puts 'collinear points' if points.collinear?
77+
end
78+
end
79+
80+
def graph_paper
81+
background(180)
82+
cell_size = 20 # size of the grid
83+
(0..width).step(cell_size) do |i|
84+
stroke(75, 135, 155)
85+
line(i, 0, i, height)
86+
end
87+
(0..height).step(cell_size) do |i|
88+
line(0, i, width, i)
89+
end
90+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
### Dealing with processing coordinate system ###
2+
3+
If you want to create Math Sketches in processing, you need to deal with peculiar coordinate systems, where the Y-axis is inverted in theory you should be able to do.
4+
5+
```ruby
6+
scale(1, -1)
7+
translate(0, -height)
8+
```
9+
But that will mess up any text (plus you probably need to `push_matrix` and `pop_matrix`) so it is probably simpler to create a parallel coordinate system for the math, and translate that back to the screen (using the processing `map` function or in `propane` and `JRubyArt` use `map1d`).
10+
11+
We have done this in `circumcircle_sketch.rb` or just accept the processing coordinate system as we have with `basic_cirmcumcircle_sketch.rb` (it is much simpler).
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
PBisector = Struct.new(:vector, :angle) # perpendicular bisector
3+
Vect = Struct.new(:x, :y, :z) # for calculation of center
4+
# Circumcircle from 3 points
5+
class Circumcircle
6+
include Math
7+
attr_reader :center, :radius, :points
8+
def initialize(points)
9+
@points = points
10+
end
11+
12+
def calculate
13+
ab = bisector(points[0], points[1]) # find 2 midpoints
14+
bc = bisector(points[1], points[2])
15+
@center = circumcenter(ab, bc)
16+
@radius = center.dist(points[2]) # points[2] = c
17+
end
18+
19+
def bisector(a, b)
20+
midpoint = (a + b) / 2.0 # middle of ab (or bc)
21+
theta = atan2(b.y - a.y, b.x - a.x) # slope of ab (or bc)
22+
PBisector.new(midpoint, theta - PI / 2)
23+
end
24+
25+
def circumcenter(pb1, pb2)
26+
# equation of the first bisector (ax - y = -b)
27+
a0 = tan pb1.angle
28+
v0 = pb1.vector
29+
a1 = tan pb2.angle
30+
v1 = pb2.vector
31+
eq0 = Vect.new(a0, -1, -1 * (v0.y - v0.x * a0))
32+
eq1 = Vect.new(a1, -1, -1 * (v1.y - v1.x * a1))
33+
# calculate x and y coordinates of the circumcenter
34+
ox = (eq1.y * eq0.z - eq0.y * eq1.z) /
35+
(eq0.x * eq1.y - eq1.x * eq0.y)
36+
oy = (eq0.x * eq1.z - eq1.x * eq0.z) /
37+
(eq0.x * eq1.y - eq1.x * eq0.y)
38+
Vec2D.new(ox, oy)
39+
end
40+
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# frozen_string_literal: true
2+
require 'forwardable'
3+
MAX_POINT = 3
4+
# A collection of a maximum of 3 points in the processing world
5+
# includes a collinearity test using Vec2D
6+
class SimplePoints
7+
extend Forwardable
8+
def_delegators(:@points, :each, :map, :size, :shift, :clear, :[])
9+
include Enumerable
10+
11+
attr_reader :points
12+
13+
def initialize
14+
@points = []
15+
end
16+
17+
def <<(pt)
18+
points << pt
19+
shift if size > MAX_POINT
20+
end
21+
22+
def collinear?
23+
full? ? (points[0] - points[1]).cross(points[1] - points[2]).zero? : false
24+
end
25+
26+
def full?
27+
points.length == MAX_POINT
28+
end
29+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require_relative 'lib/circumcircle'
2+
require_relative 'lib/simple_points'

0 commit comments

Comments
 (0)