-
Notifications
You must be signed in to change notification settings - Fork 4
/
path2d_circle_3p.lua
35 lines (30 loc) · 1.46 KB
/
path2d_circle_3p.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
--math for 2d circles defined as passing though 3 points (x1, y1, x2, y2, x3, y3).
local distance = require'path2d_point'.distance
local function to_circle(x1, y1, x2, y2, x3, y3)
--if the points are on a vertical line, we can't make a circle.
if x1 == x2 and x2 == x3 then return end
--if p2 forms a vertical line with any other point, switch it with the third point to avoid an infinite slope.
if x2 == x1 then
x2, y2, x3, y3 = x3, y3, x2, y2
elseif x2 == x3 then
x2, y2, x1, y1 = x1, y1, x2, y2
end
--compute the slopes of p2-p1 and p3-p2.
local mr = (y2 - y1) / (x2 - x1)
local mt = (y3 - y2) / (x3 - x2)
--solve for x the equation for the intersection point between the perpendiculars that pass through
--the mid points of p2-p1 and p3-p2.
local cx = (mr * mt * (y3 - y1) + mr * (x2 + x3) - mt * (x1 + x2)) / (2 * (mr - mt))
--if lines are parallel enough, the center will be further away than what a number can hold giving us inf or -inf.
--cx can also result in nan if the numerator is also zero (what's the geometric significance of this?)
if cx ~= cx or cx == 1/0 or cx == -1/0 then return end
--solve for y one of the ecuations of the perpendiculars (pick the one that avoids an infinite result).
local cy = mt == 0 and
-1 / mr * (cx - (x1 + x2) / 2) + (y1 + y2) / 2 or
-1 / mt * (cx - (x2 + x3) / 2) + (y2 + y3) / 2
return cx, cy, distance(cx, cy, x1, y1)
end
if not ... then require'path2d_circle_3p_demo' end
return {
to_circle = to_circle,
}