--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, }