Page 1 of 4
Boolean function for intersection between circular segment and circle
Posted: Fri Aug 06, 2021 1:58 pm
by Starnub
Hey guys, I've been trying to figure out how to find out if a segment and another circle intersect given the following:
Circle X, Y
Circle radius
Sector X, Y
Sector radius
Sector angle 1
Sector angle 2
From a bit of Googling I found this but my stupid dumb brain can't figure out which language this is written in.
https://math.stackexchange.com/question ... tersection
Any help would be greatly appreciated!
EDIT: I just realised I said segment instead of sector, sorry!
Re: Boolean function for intersection between circular segment and circle
Posted: Fri Aug 06, 2021 8:09 pm
by darkfrei
Can you draw the situation?
Why not just intersection of two circles?
Re: Boolean function for intersection between circular segment and circle
Posted: Fri Aug 06, 2021 10:29 pm
by pgimeno
Do they intersect if the sector is contained within the circle, or did you mean a circumference rather than a circle?
Re: Boolean function for intersection between circular segment and circle
Posted: Fri Aug 06, 2021 11:54 pm
by Starnub
darkfrei wrote: ↑Fri Aug 06, 2021 8:09 pm
Can you draw the situation?
Why not just intersection of two circles?
This is for a simple game I'm making, basically I need to figure out if the red circle lies within the circle sector here.
Re: Boolean function for intersection between circular segment and circle
Posted: Fri Aug 06, 2021 11:55 pm
by Starnub
pgimeno wrote: ↑Fri Aug 06, 2021 10:29 pm
Do they intersect if the sector is contained within the circle, or did you mean a circumference rather than a circle?
There wouldn't be a situation where the sector lies within the circle, here's an image of what I'm working with.
Re: Boolean function for intersection between circular segment and circle
Posted: Sat Aug 07, 2021 12:24 am
by BrotSagtMist
Might be easier to see it as triangle instead.
Given a point, a range and an angle you can calculate another point.
With two points you can calculate the function of a line.
Having two lines you need to resolve booth using your balls x position.
In other words: if we resolve the lower line using the balls x and the result is greater than the balls y and the result of the upper line is lower we are inside. And for the front we just use a distance check.
Re: Boolean function for intersection between circular segment and circle
Posted: Sat Aug 07, 2021 12:30 am
by Starnub
BrotSagtMist wrote: ↑Sat Aug 07, 2021 12:24 am
Might be easier to see it as triangle instead.
Given a point, a range and an angle you can calculate another point.
With two points you can calculate the function of a line.
Having two lines you need to resolve booth using your balls x position.
In other words: if we resolve the lower line using the balls x and the result is greater than the balls y and the result of the upper line is lower we are inside. And for the front we just use a distance check.
How would I find the end point of the sector lines? Sorry I haven't done math in years and I've never been good at it.
Re: Boolean function for intersection between circular segment and circle
Posted: Sat Aug 07, 2021 12:32 am
by BrotSagtMist
What end point? Lines are infinitive.
Re: Boolean function for intersection between circular segment and circle
Posted: Sat Aug 07, 2021 12:36 am
by Starnub
BrotSagtMist wrote: ↑Sat Aug 07, 2021 12:32 am
What end point? Lines are infinitive.
OH right I forgot about the distance check, this is great. Thank you very much!
Re: Boolean function for intersection between circular segment and circle
Posted: Sat Aug 07, 2021 4:03 pm
by pgimeno
Ok, the diagram helped. It's tricky because there are some corner cases (literally) that need to be handled. Here's a function:
Code: Select all
local sin, cos, sqrt = math.sin, math.cos, math.sqrt
local function withinSector(tx, ty, tr, sx, sy, ar, a1, a2)
-- First filter is the easiest and fastest - a square of radius vr+tr
if tx <= sx-(ar+tr)
or tx >= sx+(ar+tr)
or ty <= sy-(ar+tr)
or ty >= sy+(ar+tr)
then
return false
end
-- Second filter is by distance - a circle of radius vr+tr
local stx = tx-sx
local sty = ty-sy
local dist = sqrt(stx*stx + sty*sty)
if dist >= ar + tr then
return false
end
-- Now for the gist of it.
local vertex1x, vertex1y, vertex2x, vertex2y
local normal1x, normal1y, normal2x, normal2y
local vsx, vsy
local dot1, dot2
vertex1x, vertex1y = cos(a1), sin(a1)
normal1x, normal1y = -vertex1y, vertex1x
-- To account for the target radius, we displace the sentry by the normal
-- times the radius of the target, giving a "virtual sentry" position
vsx, vsy = sx - normal1x * tr, sy - normal1y * tr
-- Calculate the dot product of the vector VV->Target and the normal
dot1 = (tx - vsx) * normal1x + (ty - vsy) * normal1y
-- Repeat with the other line; the normal is the opposite
vertex2x, vertex2y = cos(a2), sin(a2)
normal2x, normal2y = vertex2y, -vertex2x
vsx, vsy = sx - normal2x * tr, sy - normal2y * tr
dot2 = (tx - vsx) * normal2x + (ty - vsy) * normal2y
-- We can now reject many cases
-- This would benefit from having the funnel angle instead of calculating it
local span = a2 - a1
if span < 0 then span = span + 6.283185307179586 end
if span >= 3.141592653589793 then
-- the area covers >= 180 degrees; we can discard if both dot products
-- are negative
if dot1 < 0 and dot2 < 0 then return false end
else
-- the area covers < 180 degrees; we can discard if either dot product is
-- negative
if dot1 < 0 or dot2 < 0 then return false end
-- In this case, the corner at the sentry's position needs to be checked.
-- If the target and both segments' endpoints are at opposite sides of
-- the normal, the previously calculated result is invalid and needs to be
-- evaluated based on distance to the corner (the sentry's position).
dot1 = vertex1x * (tx - sx) + vertex1y * (ty - sy)
dot2 = vertex2x * (tx - sx) + vertex2y * (ty - sy)
if dot1 < 0 and dot2 < 0 then
-- The result depends entirely on the distance to the sentry
return dist < tr
end
end
-- Now for the corners at the ends of the segments. First, if the distance
-- is less than the arc's radius, the result is already accurate and we have
-- a collision.
if dist < ar then
return true
end
-- Now, check which side of the segments the centre of the target is with
-- respect to the normal. If either is on the arc's side, the result is
-- already correct; return true.
dot1 = (tx - sx) * normal1x + (ty - sy) * normal1y
dot2 = (tx - sx) * normal2x + (ty - sy) * normal2y
if dot1 >= 0 and dot2 >= 0 or span >= 3.141592653589793 and (dot1 >= 0 or dot2 >= 0) then return true end
-- The collision is now solely determined by the distance to either corner
dist = sqrt((vertex1x * ar + sx - tx)^2 + (vertex1y * ar + sy - ty)^2)
if dist < tr then return true end
dist = sqrt((vertex2x * ar + sx - tx)^2 + (vertex2y * ar + sy - ty)^2)
return dist < tr
end
Example attached. Control with the mouse: no button = move the sentry; hold LMB to adjust view direction using mouse horizontal movement; hold RMB to adjust how wide the view is using mouse horizontal movement.