Я искал далеко и широко, но пока не нашел подходящего ответа на эту проблему. Учитывая две линии на сфере, каждая из которых определяется их начальной и конечной точками, определяют, пересекаются или нет. Я нашел этот сайт (http://mathforum.org/library/drmath/view/62205.html), который проходит через хороший алгоритм для пересечений двух больших кругов, хотя я застрял на определении того, лежит ли данная точка вдоль конечного участка больших кругов.Пересечения между геодезическими (кратчайшими дорожками) на поверхности сферы
Я нашел несколько сайтов, которые утверждают, что они внедрили это, включая некоторые вопросы здесь и на stackexchange, но они всегда, похоже, возвращаются к пересечениям двух больших кругов.
Класс питон Я пишу это так и кажется, что почти работа:
class Geodesic(Boundary):
def _SecondaryInitialization(self):
self.theta_1 = self.point1.theta
self.theta_2 = self.point2.theta
self.phi_1 = self.point1.phi
self.phi_2 = self.point2.phi
sines = math.sin(self.phi_1) * math.sin(self.phi_2)
cosines = math.cos(self.phi_1) * math.cos(self.phi_2)
self.d = math.acos(sines - cosines * math.cos(self.theta_2 - self.theta_1))
self.x_1 = math.cos(self.theta_1) * math.cos(self.phi_1)
self.x_2 = math.cos(self.theta_2) * math.cos(self.phi_2)
self.y_1 = math.sin(self.theta_1) * math.cos(self.phi_1)
self.y_2 = math.sin(self.theta_2) * math.cos(self.phi_2)
self.z_1 = math.sin(self.phi_1)
self.z_2 = math.sin(self.phi_2)
self.theta_wraps = (self.theta_2 - self.theta_1 > PI)
self.phi_wraps = ((self.phi_1 < self.GetParametrizedCoords(0.01).phi and
self.phi_2 < self.GetParametrizedCoords(0.99).phi) or (
self.phi_1 > self.GetParametrizedCoords(0.01).phi) and
self.phi_2 > self.GetParametrizedCoords(0.99))
def Intersects(self, boundary):
A = self.y_1 * self.z_2 - self.z_1 * self.y_2
B = self.z_1 * self.x_2 - self.x_1 * self.z_2
C = self.x_1 * self.y_2 - self.y_1 * self.x_2
D = boundary.y_1 * boundary.z_2 - boundary.z_1 * boundary.y_2
E = boundary.z_1 * boundary.x_2 - boundary.x_1 * boundary.z_2
F = boundary.x_1 * boundary.y_2 - boundary.y_1 * boundary.x_2
try:
z = 1/math.sqrt(((B * F - C * E) ** 2/(A * E - B * D) ** 2)
+ ((A * F - C * D) ** 2/(B * D - A * E) ** 2) + 1)
except ZeroDivisionError:
return self._DealWithZeroZ(A, B, C, D, E, F, boundary)
x = ((B * F - C * E)/(A * E - B * D)) * z
y = ((A * F - C * D)/(B * D - A * E)) * z
theta = math.atan2(y, x)
phi = math.atan2(z, math.sqrt(x ** 2 + y ** 2))
if self._Contains(theta, phi):
return point.SPoint(theta, phi)
theta = (theta + 2* PI) % (2 * PI) - PI
phi = -phi
if self._Contains(theta, phi):
return spoint.SPoint(theta, phi)
return None
def _Contains(self, theta, phi):
contains_theta = False
contains_phi = False
if self.theta_wraps:
contains_theta = theta > self.theta_2 or theta < self.theta_1
else:
contains_theta = theta > self.theta_1 and theta < self.theta_2
phi_wrap_param = self._PhiWrapParam()
if phi_wrap_param <= 1.0 and phi_wrap_param >= 0.0:
extreme_phi = self.GetParametrizedCoords(phi_wrap_param).phi
if extreme_phi < self.phi_1:
contains_phi = (phi < max(self.phi_1, self.phi_2) and
phi > extreme_phi)
else:
contains_phi = (phi > min(self.phi_1, self.phi_2) and
phi < extreme_phi)
else:
contains_phi = (phi > min(self.phi_1, self.phi_2) and
phi < max(self.phi_1, self.phi_2))
return contains_phi and contains_theta
def _PhiWrapParam(self):
a = math.sin(self.d)
b = math.cos(self.d)
c = math.sin(self.phi_2)/math.sin(self.phi_1)
param = math.atan2(c - b, a)/self.d
return param
def _DealWithZeroZ(self, A, B, C, D, E, F, boundary):
if (A - D) is 0:
y = 0
x = 1
elif (E - B) is 0:
y = 1
x = 0
else:
y = 1/math.sqrt(((E - B)/(A - D)) ** 2 + 1)
x = ((E - B)/(A - D)) * y
theta = (math.atan2(y, x) + PI) % (2 * PI) - PI
return point.SPoint(theta, 0)
def GetParametrizedCoords(self, param_value):
A = math.sin((1 - param_value) * self.d)/math.sin(self.d)
B = math.sin(param_value * self.d)/math.sin(self.d)
x = A * math.cos(self.phi_1) * math.cos(self.theta_1) + (
B * math.cos(self.phi_2) * math.cos(self.theta_2))
y = A * math.cos(self.phi_1) * math.sin(self.theta_1) + (
B * math.cos(self.phi_2) * math.sin(self.theta_2))
z = A * math.sin(self.phi_1) + B * math.sin(self.phi_2)
new_phi = math.atan2(z, math.sqrt(x**2 + y**2))
new_theta = math.atan2(y, x)
return point.SPoint(new_theta, new_phi)
EDIT: я забыл указать, что если две кривые настроены пересекаются, я тогда нужно иметь точку пересечение.
Это фантастическое и элегантное решение для пересечения двух линий. Я забыл указать, что в случае пересечения двух пересечений мне также нужна точка пересечения. Например, мой метод Intersects выше работает, но имеет множественность, поскольку он вычисляет пересечения большого круга, характеризуемого сегментом, что сводится к моим недостаточным проверкам того, существует ли найденная точка пересечения на сегменте. – Jordan
Точка пересечения лежит на обеих плоскостях, поэтому она должна быть некоторой вещественной кратной вектору 'm = cross (cross (a.v1, a.v2), cross (b.v1, b.v2)). Вопрос только в том, является ли точка пересечения нормализацией 'm' или' -m'. Я думаю, вы можете получить это, вычислив знак детерминанта любых трех точек, таких как 'det (a.v1, b.v1, b.v2)'. –
Ничего себе, так изящно! – ZpaceZombor