VMDBase<TYPE> VMDBase<TYPE>::getNormalVector(const std::vector<VMDBase<TYPE>> &vectors) { if (vectors.empty()) throw std::invalid_argument( "VMDBase::getNormalVector: Must give at least 1 vector"); size_t nd = vectors[0].getNumDims(); if (nd < 2) throw std::invalid_argument( "VMDBase::getNormalVector: Must have at least 2 dimensions!"); if (vectors.size() != nd - 1) throw std::invalid_argument("VMDBase::getNormalVector: Must have as many " "N-1 vectors if there are N dimensions."); for (size_t i = 0; i < vectors.size(); i++) if (vectors[i].getNumDims() != nd) throw std::invalid_argument("VMDBase::getNormalVector: Inconsistent " "number of dimensions in the vectors given!"); // Start the normal vector VMDBase normal = VMDBase(nd); TYPE sign = +1.0; for (size_t d = 0; d < nd; d++) { // Make the sub-determinant with the columns of every other dimension. Matrix<TYPE> mat(nd - 1, nd - 1); for (size_t row = 0; row < vectors.size(); row++) { VMDBase vec = vectors[row]; size_t col = 0; for (size_t i = 0; i < nd; i++) { if (i != d) // Skip the column of this dimension { mat[row][col] = vec[i]; col++; } } } // Building the matrix rows TYPE det = mat.determinant(); // The determinant of the sub-matrix = the normal at that dimension normal[d] = sign * det; // Sign flips each time sign *= TYPE(-1.0); } // each dimension of the normal vector // Unity normal is better. double length = normal.normalize(); if (length == 0) throw std::runtime_error("VMDBase::getNormalVector: 0-length normal found. " "Are your vectors collinear?"); return normal; }
std::vector<VMDBase<TYPE>> VMDBase<TYPE>::makeVectorsOrthogonal(std::vector<VMDBase> &vectors) { if (vectors.size() != 2) throw std::runtime_error( "VMDBase::makeVectorsOrthogonal(): Need 2 input vectors."); if (vectors[0].getNumDims() != 3 || vectors[1].getNumDims() != 3) throw std::runtime_error( "VMDBase::makeVectorsOrthogonal(): Need 3D input vectors."); std::vector<V3D> in, out; for (size_t i = 0; i < vectors.size(); i++) in.push_back(V3D(vectors[i][0], vectors[i][1], vectors[i][2])); out = V3D::makeVectorsOrthogonal(in); std::vector<VMDBase> retVal; for (size_t i = 0; i < out.size(); i++) retVal.push_back(VMDBase(out[i])); return retVal; }