Example #1
0
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;
}
Example #2
0
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;
}