Самое простое решение здесь - использовать shapely
.
Если у вас есть массив формы Nx2 , содержащий набор вершин (xy
), тогда тривиально создать соответствующий объект shapely.geometry.polygon
и проверить, является ли произвольная точка или набор точек (points
) содержится в пределах -
import shapely.geometry as geom
ellipse = geom.Polygon(xy)
for p in points:
if ellipse.contains(geom.Point(p)):
# ...
В качестве альтернативы, если эллипсы определяются их параметрами (т. е. углом поворота, большой полуосью и полуминорной осью), то массив, содержащий вершины, должен быть построен и затем применяется тот же процесс. Я бы порекомендовал использовать полярную форму относительно центра , так как это наиболее совместимо с тем, как стройно строятся полигоны.
import shapely.geometry as geom
from shapely import affinity
n = 360
a = 2
b = 1
angle = 45
theta = np.linspace(0, np.pi*2, n)
r = a * b / np.sqrt((b * np.cos(theta))**2 + (a * np.sin(theta))**2)
xy = np.stack([r * np.cos(theta), r * np.sin(theta)], 1)
ellipse = affinity.rotate(geom.Polygon(xy), angle, 'center')
for p in points:
if ellipse.contains(geom.Point(p)):
# ...
Этот метод выгоден тем, что поддерживает любые правильно определенные полигоны - не только эллипсы, он не полагается на методы matplotlib для проверки содержимого, и он создает очень читаемый код (который часто важен, когда « распространяет [свое] программное обеспечение среди других людей »).
Вот полный пример (с добавленным графиком, чтобы показать его работоспособность)
import shapely.geometry as geom
from shapely import affinity
import matplotlib.pyplot as plt
import numpy as np
n = 360
theta = np.linspace(0, np.pi*2, n)
a = 2
b = 1
angle = 45.0
r = a * b / np.sqrt((b * np.cos(theta))**2 + (a * np.sin(theta))**2)
xy = np.stack([r * np.cos(theta), r * np.sin(theta)], 1)
ellipse = affinity.rotate(geom.Polygon(xy), angle, 'center')
x, y = ellipse.exterior.xy
# Create a Nx2 array of points at grid coordinates throughout
# the ellipse extent
rnd = np.array([[i,j] for i in np.linspace(min(x),max(x),50)
for j in np.linspace(min(y),max(y),50)])
# Filter for points which are contained in the ellipse
res = np.array([p for p in rnd if ellipse.contains(geom.Point(p))])
plt.plot(x, y, lw = 1, color='k')
plt.scatter(rnd[:,0], rnd[:,1], s = 50, color=(0.68, 0.78, 0.91)
plt.scatter(res[:,0], res[:,1], s = 15, color=(0.12, 0.67, 0.71))
plt.show()