Point and ellipse (rotated) position test: algorithm
To deal with ellipses I prefer to transform them to another coordinate system where the ellipse is a unit circle centered at the origin.
If you see the ellipse as a unit circle (radius 1), scaled by (a,b), rotated by phi and transformed by (x,y), then life becomes a lot easier. If you have that transform matrix you can use it to do an easier containment query. If you transform the point to be in the coordinate system where the ellipse is a unit circle, all you have to do is a point-in-unit circle test which is trivial. If "transform" is a matrix that transforms a unit circle into your ellipse as described, then
transformedPoint = transform.Invert().Transform(point);
pointInEllipse = transformedPoint.DistanceTo(0,0) < 1.0;
You can simply feed your data into the formula stated above. Here is a python implementation I made on Ajasja's recommendations:
def pointInEllipse(x,y,xp,yp,d,D,angle):
#tests if a point[xp,yp] is within
#boundaries defined by the ellipse
#of center[x,y], diameter d D, and tilted at angle
cosa=math.cos(angle)
sina=math.sin(angle)
dd=d/2*d/2
DD=D/2*D/2
a =math.pow(cosa*(xp-x)+sina*(yp-y),2)
b =math.pow(sina*(xp-x)-cosa*(yp-y),2)
ellipse=(a/dd)+(b/DD)
if ellipse <= 1:
return True
else:
return False
Another option is just to throw everything into the equation for a 2D rotated ellipse and see if the result is less than one.
So a point is inside the ellipse if the following inequality is true
Where (xp,yp) are the point coordinates and (x0, y0) is the center of the ellipse.
I implemented a small Mathematica program demonstrating that this indeed works:
Here it is in action:
And here is the code:
ellipse[x_, y_, a_, b_, \[Alpha]_, x0_: 0, y0_: 0] :=
(((x - x0)*Cos[\[Alpha]] + (y - y0)*Sin[\[Alpha]])/a)^2
+ (((x - x0)*Sin[\[Alpha]] - (y - y0)*Cos[\[Alpha]])/b)^2;
Manipulate[
RegionPlot[
ellipse[x, y, a, b, \[Alpha] \[Degree], Sequence @@ pos] < 1, {x, -5, 5}, {y, -5, 5},
PlotStyle -> If[ellipse[Sequence @@ p, a, b, \[Alpha] \[Degree], Sequence @@ pos] <= 1, Orange, LightBlue],
PlotPoints -> 25]
, {{a, 2}, 1, 5, Appearance -> "Labeled"}
, {{b, 4}, 2, 5, Appearance -> "Labeled"}
, {\[Alpha], 0, 180, Appearance -> "Labeled"}
, {{p, {3, 1}}, Automatic, ControlType -> Locator}
, {{pos, {0, 0}}, Automatic, ControlType -> Locator}]
Here is the algorithm, I let you develop the code:
- Determine the vector v1 between the center of ellipse and your point
- Determine angle a1 between vector v1 and x axis in world coordinates
- Substract phi from a1 to get a2, our vector angle in local coordinates
- Determine point P2 on ellipse at angle a2 in local coordinates, not offset by (x, y)
- Compute L1 and L2, the vector length of a1 and a2
Evaluation:
- If L1 < L2 the point is inside
- If L1 = L2 (plus/minus a small tolerance) the point is on the ellipse
- If L2 > L2 the point is outside
Ellipse parametric formula:
x = a*cos(u)
y = b*sin(u)
valid for u between -pi and +pi. Add phi to u to rotate your ellipse.
The algorithm above can be simplified and optimized from ellipse equations.
Good luck!