/** Constructor helper method
 * @param min :: nd-sized vector of the minimum edge of the box in each
 * dimension
 * @param max :: nd-sized vector of the maximum edge of the box
 * */
void MDBoxImplicitFunction::construct(const Mantid::Kernel::VMD &min,
                                      const Mantid::Kernel::VMD &max) {
  size_t nd = min.size();
  if (max.size() != nd)
    throw std::invalid_argument(
        "MDBoxImplicitFunction::ctor(): Min and max vector sizes must match!");
  if (nd == 0 || nd > 100)
    throw std::invalid_argument(
        "MDBoxImplicitFunction::ctor(): Invalid number of dimensions!");

  double volume = 1;
  for (size_t d = 0; d < nd; d++) {
    volume *= (max[d] - min[d]);

    // Make two parallel planes per dimension

    // Normal on the min side, so it faces towards +X
    std::vector<coord_t> normal_min(nd, 0);
    normal_min[d] = +1.0;
    // Origin just needs to have its X set to the value. Other coords are
    // irrelevant
    std::vector<coord_t> origin_min(nd, 0);
    origin_min[d] = static_cast<coord_t>(min[d]);
    // Build the plane
    MDPlane p_min(normal_min, origin_min);
    this->addPlane(p_min);

    // Normal on the max side, so it faces towards -X
    std::vector<coord_t> normal_max(nd, 0);
    normal_max[d] = -1.0;
    // Origin just needs to have its X set to the value. Other coords are
    // irrelevant
    std::vector<coord_t> origin_max(nd, 0);
    origin_max[d] = static_cast<coord_t>(max[d]);
    // Build the plane
    MDPlane p_max(normal_max, origin_max);
    this->addPlane(p_max);
  }
  m_volume = volume;
}
Example #2
0
  /** Build a coordinate transformation based on an origin and orthogonal basis vectors.
   * This can reduce the number of dimensions. For example:
   *
   * - The input position is X=(x,y,z)
   * - The origin is X0=(x0,y0,z0)
   * - The basis vectors are U and V (reducing from 3 to 2D)
   * - The output position u = (X-X0).U = X.U - X0.U = x*Ux + y*Uy + z*Uz + (X0.U)
   * - The output position v = (X-X0).V = X.V - X0.V = x*Vx + y*Vy + z*Vz + (X0.V)
   *
   * And this allows us to create the affine matrix:
   *
   * | Ux  Uy  Uz  X0.U | | x |   | u |
   * | Vx  Vy  Vz  X0.V | | y | = | v |
   * | 0   0   0    1   | | z |   | 1 |
   *                      | 1 |
   *
   * @param origin :: origin (in the inDimension), which corresponds to (0,0,...) in outD
   * @param axes :: a list of basis vectors. There must be outD vectors (one for each output dimension)
   *        and each vector must be of length inD (all coordinates in the input dimension).
   *        The vectors must be properly orthogonal: not coplanar or collinear. This is not checked!
   * @param scaling :: a vector of size outD of the scaling to perform in each of the
   *        OUTPUT dimensions.
   * @throw if inconsistent vector sizes are received, or zero-length
   */
  void CoordTransformAffine::buildOrthogonal(const Mantid::Kernel::VMD & origin, const std::vector< Mantid::Kernel::VMD> & axes,
      const Mantid::Kernel::VMD & scaling)
  {
    if (origin.size() != inD)
      throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): the origin must be in the dimensions of the input workspace (length inD).");
    if (axes.size() != outD)
      throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): you must give as many basis vectors as there are dimensions in the output workspace.");
    if (scaling.size() != outD)
      throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): the size of the scaling vector must be the same as the number of dimensions in the output workspace.");

    // Start with identity
    affineMatrix.identityMatrix();

    for (size_t i=0; i<axes.size(); i++)
    {
      if (axes[i].length() == 0.0)
        throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): one of the basis vector was of zero length.");
      if (axes[i].size() != inD)
        throw std::runtime_error("CoordTransformAffine::buildOrthogonal(): one of the basis vectors had the wrong number of dimensions (must be inD).");
      // Normalize each axis to unity
      VMD basis = axes[i];
      basis.normalize();
      // The row of the affine matrix = the unit vector
      for (size_t j=0; j<basis.size(); j++)
        affineMatrix[i][j] = basis[j] * scaling[i];

      // Now account for the translation
      coord_t transl = 0;
      for (size_t j=0; j<basis.size(); j++)
        transl += origin[j] * basis[j]; // dot product of origin * basis aka ( X0 . U )
      // The last column of the matrix = the translation movement
      affineMatrix[i][inD] = -transl * scaling[i];
    }

    // Copy into the raw matrix (for speed)
    copyRawMatrix();
  }