Я пытаюсь подогнать плоскость к набору точек в трехмерном пространстве. Первоначально я пробовал исчерпывающую подгонку методом наименьших квадратов, но это оказалось слишком медленным. Я читал, что наиболее эффективным решением было бы выполнить разложение по сингулярным значениям.
Математика для этого мне не по силам, но я нашел кучу ресурсов, чтобы попытаться заставить это работать.
Согласно ответу в этом сообщении, мне нужно чтобы вычислить центроид точек, вычтите центроид из всех точек, поместите их в матрицу 3xN и выполните SVD. Затем я беру левый сингулярный вектор в качестве нормали к плоскости.
Все идет нормально.
Я нашел математическую библиотеку C# под названием alglib, в которой есть функция для SVD. Определение алгоритма можно найти здесь. Здесь у меня возникают проблемы, так как для этого требуются еще две матрицы в качестве входных данных в дополнение к матрице точек данных, и я действительно не понимаю, что в них помещать. Я запустил этот код независимо:
Vector3 centroid = getCentroid(planeVerts);
double[,] dataMat = substractCentroid(planeVerts, centroid);
double[] w = new double[3];
double[,] u = new double[1,1];
double[,] t = new double[1, 1];
bool a = alglib.svd.rmatrixsvd(dataMat, 3, planeVerts.Length, 0, 0, 2, ref w, ref u, ref t);
Vector3 planeNorm = new Vector3((float) w[0], (float) w[1], (float) w[2]);
Итак, теоретически я думал, что «w» будет содержать нормаль моей плоскости, но, к сожалению, это не так (я визуализировал ее в Unity3D, и она была под неправильным углом). Матрицы «u» и «t» — это те, которые меня смущают, и я действительно не знаю, на что мне их устанавливать.
Подробный API для функции rmatrixsvd можно найти здесь.
Есть ли ветераны математики или алгоритмов, которые могли бы поделиться своими знаниями по этому вопросу? Мне нужно использовать C#, так как мой проект находится в Unity3D. Я буду рад предоставить дополнительную информацию, если это необходимо.