Программа вычисляет линию пересечения плоскостей, проходящих через два прямоугольника.Затем программа ищет пересечения между этой линией и краями одного из прямоугольников.Возвращает две точки пересечения, такие две найденные точки найдены.Я не собираюсь спорить, разумно ли это делать, поскольку я не знаю контекста программы.
Давайте рассмотрим код и поищем вещи, которые могут быть неправильными.
Программа вычисляет линию, проходящую через две плоскости, следующим образом:
Vector3 LineDirection = Normal.Cross(SecondOne.Normal);
float d1 = this.GetDistance(LineDirection);
float d2 = SecondOne.GetDistance(LineDirection);
temp = (LineDirection - (this.Normal * d1) - (SecondOne.Normal * d2));
temp.x = Math.Abs((float)Math.Round((decimal)FirstPoint.x, 2));
temp.y = Math.Abs((float)Math.Round((decimal)FirstPoint.y, 2));
Line line;
line.direction = LineDirection;
line.point = temp;
Вычисление направления линии в порядке, но вычисление point
неверно, как вы, вероятно, знаете.Но я буду притворяться, что у нас есть правильная точка и направление, и продолжить с остальной частью программы.
Программа вызывает AreLinesParallel()
, чтобы избавиться от ребер, параллельных прямой через плоскости.Код выглядит следующим образом:
Vector3 vector = (first.secondPoint - first.firstPoint);
vector.Normalize();
float kl = 0, km = 0, kn = 0;
if (vector.x != aSecondLine.direction.x)
{
if (vector.x != 0 && aSecondLine.direction.x != 0)
{
kl = vector.x / aSecondLine.direction.x;
}
}
if (vector.y != aSecondLine.direction.y)
{
if (vector.y != 0 && aSecondLine.direction.y != 0)
{
km = vector.y / aSecondLine.direction.y;
}
}
if (vector.z != aSecondLine.direction.z)
{
if (vector.z != 0 && aSecondLine.direction.z != 0)
{
kn = vector.z / aSecondLine.direction.z;
}
}
// both if all are null or all are equal, the lines are parallel
return ((kl == km && km == kn));
Код более или менее проверяет, что все элементы направления ребра, разделенные на элементы направления линии, равны друг другу.Это опасная процедура, на которую можно положиться.Из-за ошибок округления более поздние процедуры могут, скажем, делиться на ноль, даже если AreLinesParallel()
утверждает, что линии на самом деле не параллельны.Эту процедуру лучше вообще не использовать.
Теперь идет основа кода, тест на пересечение между краем и линией:
float d = 0, dt = 0, dk = 0;
float t = 0, k = 0;
if (Math.Abs(n1.x * n2.y - n2.x * n1.y) > float.Epsilon)
{
d = n1.x * (-n2.y) - (-n2.x) * n1.y;
dt = (p2.x - p1.x) * (-n2.y) - (p2.y - p1.y) * (-n2.x);
dk = n1.x * (p2.x - p1.x) - n1.y * (p2.y - p1.y);
}
else if (Math.Abs(n1.z * n2.y - n2.z * n1.y) > float.Epsilon)
{
d = n1.z * (-n2.y) - (-n2.z) * n1.y;
dt = (p2.z - p1.z) * (-n2.y) - (p2.y - p1.y) * (-n2.z);
dk = n1.z * (p2.z - p1.z) - n1.y * (p2.y - p1.y);
}
else if (Math.Abs(n1.x * n2.z - n2.x * n1.z) > float.Epsilon)
{
d = n1.x * (-n2.z) - (-n2.x) * n1.z;
dt = (p2.x - p1.x) * (-n2.z) - (p2.z - p1.z) * (-n2.x);
dk = n1.x * (p2.x - p1.x) - n1.z * (p2.z - p1.z);
}
t = dt / d;
k = dk / d;
result = n1 * t + p1;
Ошибка этого кодаявляется отсутствие комментария, который объясняет происхождение алгоритма.Если нет документированного алгоритма, на который можно ссылаться, комментарий может содержать вывод, приводящий к формулам.Первая ветвь имеет дело с (x, y)
, вторая с (y, z)
, а третья с (z, x)
, поэтому я предполагаю, что ветви решают пересечение в 2D и поднимают эти результаты в 3D.Он вычисляет детерминанты для проверки параллельных линий для каждой 2D проекции.Я не должен был делать этот вид реверс-инжиниринга.
В любом случае, это код, который выдает значения NaN
.Ни одна из трех ветвей не сработала, поэтому в итоге d = 0
, что дает деление на ноль.Вместо того, чтобы полагаться на AreLinesParallel()
, чтобы избежать деления на ноль, лучше проверить значение, которое действительно имеет значение, а именно d
.
Конечно, код все еще нуждается в доработке, потому что мы еще не знаем, пересекаются ли линии и в 3D.Также точка находится на краю, только если 0 <= t && t <= 1
.И, вероятно, по мере исправления более ранних ошибок будет отображаться больше ошибок.