示例#1
0
/**
 * createOneDetectorInstrument, creates the most simple possible definition of an instrument in which we can extract a valid L1 and L2 distance for unit calculations.
 *
 * Beam direction is along X,
 * Up direction is Y
 *
 * @param sourcePos : V3D position
 * @param samplePos : V3D sample position
 * @param detectorPos : V3D detector position
 * @return Instrument generated.
 */
Geometry::Instrument_sptr createMinimalInstrument(const Mantid::Kernel::V3D& sourcePos, const Mantid::Kernel::V3D& samplePos, const Mantid::Kernel::V3D& detectorPos )
{
    Instrument_sptr instrument = boost::make_shared<Instrument>();
    instrument->setReferenceFrame(
        boost::make_shared<ReferenceFrame>(Mantid::Geometry::Y /*up*/, Mantid::Geometry::X /*along*/, Left, "0,0,0"));

    // A source
    ObjComponent *source = new ObjComponent("source");
    source->setPos(sourcePos);
    source->setShape(createSphere(0.01 /*1cm*/, V3D(0,0,0), "1"));
    instrument->add(source);
    instrument->markAsSource(source);

    // A sample
    ObjComponent *sample = new ObjComponent("some-surface-holder");
    sample->setPos(samplePos);
    sample->setShape(createSphere(0.01 /*1cm*/, V3D(0,0,0), "1"));
    instrument->add(sample);
    instrument->markAsSamplePos(sample);

    // A detector
    Detector *det = new Detector("point-detector", 1 /*detector id*/, NULL);
    det->setPos(detectorPos);
    det->setShape(createSphere(0.01 /*1cm*/, V3D(0,0,0), "1"));
    instrument->add(det);
    instrument->markAsDetector(det);

    return instrument;
}
示例#2
0
/** Returns the position of the center of the pixel at x,y, relative to the
 * center
 * of the RectangularDetector, in the plain X,Y coordinates of the
 * pixels (i.e. unrotated).
 * @param x :: x pixel integer
 * @param y :: y pixel integer
 * @return a V3D vector of the relative position
 */
V3D RectangularDetector::getRelativePosAtXY(int x, int y) const {
  if (m_map) {
    double scalex = 1.0;
    if (m_map->contains(m_rectBase, "scalex"))
      scalex = m_map->get(m_rectBase, "scalex")->value<double>();
    double scaley = 1.0;
    if (m_map->contains(m_rectBase, "scaley"))
      scaley = m_map->get(m_rectBase, "scaley")->value<double>();
    return m_rectBase->getRelativePosAtXY(x, y) * V3D(scalex, scaley, 1.0);
  } else
    return V3D(m_xstart + m_xstep * x, m_ystart + m_ystep * y, 0);
}
示例#3
0
 /** Set the position of the Component
 *  The position is with respect to the parent Component
 *  @param x :: x position
 *  @param y :: y position
 *   @param z :: z position
 */
 void Component::setPos(double x, double y, double z) {
   if (!m_map)
     m_pos = V3D(x, y, z);
   else
     throw Kernel::Exception::NotImplementedError(
     "Component::setPos (for Parametrized Component)");
 }
示例#4
0
 /** Get ScaleFactor of detector.  Looks at the "sca" parameter in the parameter
 *map.
 *
 * @returns A vector of the scale factors (1,1,1) if not set
 */
 V3D Component::getScaleFactor() const {
   if (m_map) {
     Parameter_sptr par = m_map->get(m_base, "sca");
     if (par) {
       return par->value<V3D>();
     }
   }
   return V3D(1, 1, 1);
 }
示例#5
0
/** Get ScaleFactor of detector.  Looks at the "sca" parameter in the parameter
*map.
*
* @returns A vector of the scale factors (1,1,1) if not set
*/
V3D Component::getScaleFactor() const {
  if (m_map) {
    if (hasComponentInfo()) {
      return m_map->componentInfo().scaleFactor(index());
    } else {
      Parameter_sptr par = m_map->get(m_base, ParameterMap::scale());
      if (par) {
        return par->value<V3D>();
      }
    }
  }
  return V3D(1, 1, 1);
}
示例#6
0
Geometry::Instrument_sptr
createVirtualInstrument(Kernel::V3D sourcePos, Kernel::V3D samplePos,
                        const std::vector<Kernel::V3D> &vecdetpos,
                        const std::vector<detid_t> &vecdetid) {
    Instrument_sptr instrument = boost::make_shared<Instrument>();
    instrument->setReferenceFrame(
        boost::make_shared<ReferenceFrame>(Mantid::Geometry::Y /*up*/, Mantid::Geometry::Z /*along*/, Right, "0,0,0"));

    // A source
    ObjComponent *source = new ObjComponent("source");
    source->setPos(sourcePos);
    source->setShape(createSphere(0.01 /*1cm*/, V3D(0,0,0), "1"));
    instrument->add(source);
    instrument->markAsSource(source);

    // A sample
    ObjComponent *sample = new ObjComponent("some-surface-holder");
    sample->setPos(samplePos);
    sample->setShape(createSphere(0.01 /*1cm*/, V3D(0,0,0), "1"));
    instrument->add(sample);
    instrument->markAsSamplePos(sample);

    // A detector
    size_t numdets = vecdetpos.size();
    for (size_t i = 0; i < numdets; ++i)
    {
        Detector *det = new Detector("point-detector", vecdetid[i] /*detector id*/, NULL);
        det->setPos(vecdetpos[i]);
        // FIXME - should be cubi... pixel
        det->setShape(createSphere(0.01 /*1cm*/, V3D(0,0,0), "1"));
        instrument->add(det);
        instrument->markAsDetector(det);
    }

    return instrument;

}
示例#7
0
/**
 * Enlarges this bounding box so that it encompasses that given.
 * @param other :: The bounding box that should be encompassed
 */
void BoundingBox::grow(const BoundingBox &other) {
  m_null = false;
  // If the current box is empty then we definitely need to grow
  if (minPoint() == V3D() && maxPoint() == V3D()) {
    m_minPoint = other.minPoint();
    m_maxPoint = other.maxPoint();
    return;
  }

  // Simply checks if an of the points in the given box are outside this one and
  // changes the coordinate appropriately
  V3D otherPoint = other.minPoint();
  for (size_t i = 0; i < 3; ++i) {
    if (otherPoint[i] < m_minPoint[i]) {
      m_minPoint[i] = otherPoint[i];
    }
  }
  otherPoint = other.maxPoint();
  for (size_t i = 0; i < 3; ++i) {
    if (otherPoint[i] > m_maxPoint[i]) {
      m_maxPoint[i] = otherPoint[i];
    }
  }
}
示例#8
0
/**Add an additional axis to the goniometer, closer to the sample
  @param name :: GoniometerAxis name
  @param axisx :: the x component of the rotation axis
  @param axisy :: the y component of the rotation axis
  @param axisz :: the z component of the rotation axis
  @param angle :: rotation angle, 0 by default
  @param sense :: rotation sense (CW or CCW), CCW by default
  @param angUnit :: units for angle of type#AngleUnit, angDegrees by default
*/
void Goniometer::pushAxis(std::string name, double axisx, double axisy,
                          double axisz, double angle, int sense, int angUnit) {
  if (initFromR == true) {
    throw std::runtime_error(
        "Initialized from a rotation matrix, so no axes can be pushed.");
  } else {
    std::vector<GoniometerAxis>::iterator it;
    // check if such axis is already defined
    for (it = motors.begin(); it < motors.end(); ++it) {
      if (name.compare((*it).name) == 0)
        throw std::invalid_argument("Motor name already defined");
    }
    GoniometerAxis a(name, V3D(axisx, axisy, axisz), angle, sense, angUnit);
    motors.push_back(a);
  }
  recalculateR();
}
/** Finds the approximate solid angle covered by the component when viewed from
* the point given
*  @param observer :: The position from which the component is being viewed
*  @returns The solid angle in steradians
*  @throw NullPointerException if the underlying geometrical Object has not been
* set
*/
double ObjComponent::solidAngle(const V3D &observer) const {
  // If the form of this component is not defined, throw NullPointerException
  if (!shape())
    throw Kernel::Exception::NullPointerException("ObjComponent::solidAngle",
                                                  "shape");
  // Otherwise pass through the shifted point to the Object::solidAngle method
  V3D scaleFactor = this->getScaleFactor();
  if ((scaleFactor - V3D(1.0, 1.0, 1.0)).norm() < 1e-12)
    return shape()->solidAngle(factorOutComponentPosition(observer));
  else {
    // This is the observer position in the shape's coordinate system.
    V3D relativeObserver = factorOutComponentPosition(observer);
    // This function will scale the object shape when calculating the solid
    // angle.
    return shape()->solidAngle(relativeObserver, scaleFactor);
  }
}
示例#10
0
//----------------------------------------------------------------------------------------------
///< Render Object or ObjComponent
void BitmapGeometryHandler::Render() {
  // std::cout << "BitmapGeometryHandler::Render() called\n";
  V3D pos;

  // Wait for no error
  while (glGetError() != GL_NO_ERROR)
    ;

  // Because texture colours are combined with the geometry colour
  // make sure the current colour is white
  glColor3f(1.0f, 1.0f, 1.0f);

  // Nearest-neighbor scaling
  GLint texParam = GL_NEAREST;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texParam);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texParam);

  glEnable(GL_TEXTURE_2D); // enable texture mapping

  int texx, texy;
  m_rectDet->getTextureSize(texx, texy);
  double tex_frac_x = (1.0 * m_rectDet->xpixels()) / (texx);
  double tex_frac_y = (1.0 * m_rectDet->ypixels()) / (texy);

  // Point to the ID of the texture that was created before - in
  // RectangularDetectorActor.
  // int texture_id = m_rectDet->getTextureID();
  // glBindTexture (GL_TEXTURE_2D, texture_id);
  // if (glGetError()>0) std::cout << "OpenGL error in glBindTexture \n";

  glBegin(GL_QUADS);

  glTexCoord2f(0.0, 0.0);
  pos = m_rectDet->getRelativePosAtXY(0, 0);
  pos += V3D(m_rectDet->xstep() * (-0.5), m_rectDet->ystep() * (-0.5),
             0.0); // Adjust to account for the size of a pixel
  glVertex3f((GLfloat)pos.X(), (GLfloat)pos.Y(), (GLfloat)pos.Z());

  glTexCoord2f((GLfloat)tex_frac_x, 0.0);
  pos = m_rectDet->getRelativePosAtXY(m_rectDet->xpixels() - 1, 0);
  pos += V3D(m_rectDet->xstep() * (+0.5), m_rectDet->ystep() * (-0.5),
             0.0); // Adjust to account for the size of a pixel
  glVertex3f((GLfloat)pos.X(), (GLfloat)pos.Y(), (GLfloat)pos.Z());

  glTexCoord2f((GLfloat)tex_frac_x, (GLfloat)tex_frac_y);
  pos = m_rectDet->getRelativePosAtXY(m_rectDet->xpixels() - 1,
                                      m_rectDet->ypixels() - 1);
  pos += V3D(m_rectDet->xstep() * (+0.5), m_rectDet->ystep() * (+0.5),
             0.0); // Adjust to account for the size of a pixel
  glVertex3f((GLfloat)pos.X(), (GLfloat)pos.Y(), (GLfloat)pos.Z());

  glTexCoord2f(0.0, (GLfloat)tex_frac_y);
  pos = m_rectDet->getRelativePosAtXY(0, m_rectDet->ypixels() - 1);
  pos += V3D(m_rectDet->xstep() * (-0.5), m_rectDet->ystep() * (+0.5),
             0.0); // Adjust to account for the size of a pixel
  glVertex3f((GLfloat)pos.X(), (GLfloat)pos.Y(), (GLfloat)pos.Z());

  glEnd();
  if (glGetError() > 0)
    std::cout << "OpenGL error in BitmapGeometryHandler::Render \n";

  glDisable(
      GL_TEXTURE_2D); // stop texture mapping - not sure if this is necessary.
}
示例#11
0
/** Set the outline of the assembly. Creates an Object and sets m_shape point to
 * it.
 *  All child components must be detectors and positioned along a straight line
 * and have the same shape.
 *  The shape can be either a box or a cylinder.
 *  @return The shape of the outline: "cylinder", "box", ...
 */
boost::shared_ptr<Object> ObjCompAssembly::createOutline() {
  if (group.empty()) {
    throw Kernel::Exception::InstrumentDefinitionError("Empty ObjCompAssembly");
  }

  if (nelements() < 2) {
    g_log.warning("Creating outline with fewer than 2 elements. The outline displayed may be inaccurate.");
  }

  // Get information about the shape and size of a detector
  std::string type;
  int otype;
  std::vector<Kernel::V3D> vectors;
  double radius, height;
  boost::shared_ptr<const Object> obj = group.front()->shape();
  if (!obj) {
    throw Kernel::Exception::InstrumentDefinitionError(
        "Found ObjComponent without shape");
  }
  obj->GetObjectGeom(otype, vectors, radius, height);
  if (otype == 1) {
    type = "box";
  } else if (otype == 3) {
    type = "cylinder";
  } else {
    throw std::runtime_error(
        "IDF \"outline\" option is only allowed for assemblies containing "
        "components of types \"box\" or \"cylinder\".");
  }

  // Calculate the dimensions of the outline object

  // find the 'moments of inertia' of the assembly
  double Ixx = 0, Iyy = 0, Izz = 0, Ixy = 0, Ixz = 0, Iyz = 0;
  V3D Cmass; // 'center of mass' of the assembly
  for (const_comp_it it = group.begin(); it != group.end(); it++) {
    V3D p = (**it).getRelativePos();
    Cmass += p;
  }
  Cmass /= nelements();
  for (const_comp_it it = group.begin(); it != group.end(); it++) {
    V3D p = (**it).getRelativePos();
    double x = p.X() - Cmass.X(), x2 = x * x;
    double y = p.Y() - Cmass.Y(), y2 = y * y;
    double z = p.Z() - Cmass.Z(), z2 = z * z;
    Ixx += y2 + z2;
    Iyy += x2 + z2;
    Izz += y2 + x2;
    Ixy -= x * y;
    Ixz -= x * z;
    Iyz -= y * z;
  }
  // principal axes of the outline shape
  // vz defines the line through all pixel centres
  V3D vx, vy, vz;

  if (Ixx == 0) // pixels along x axis
  {
    vx = V3D(0, 1, 0);
    vy = V3D(0, 0, 1);
    vz = V3D(1, 0, 0);
  } else if (Iyy == 0) // pixels along y axis
  {
    vx = V3D(0, 0, 1);
    vy = V3D(1, 0, 0);
    vz = V3D(0, 1, 0);
  } else if (Izz == 0) // pixels along z axis
  {
    vx = V3D(1, 0, 0);
    vy = V3D(0, 1, 0);
    vz = V3D(0, 0, 1);
  } else {
    // Either the detectors are not perfectrly aligned or
    // vz is parallel to neither of the 3 axis x,y,z
    // This code is unfinished
    DblMatrix II(3, 3), Vec(3, 3), D(3, 3);
    II[0][0] = Ixx;
    II[0][1] = Ixy;
    II[0][2] = Ixz;
    II[1][0] = Ixy;
    II[1][1] = Iyy;
    II[1][2] = Iyz;
    II[2][0] = Ixz;
    II[2][1] = Iyz;
    II[2][2] = Izz;
    std::cerr << "Inertia matrix: " << II << II.determinant() << '\n';
    II.Diagonalise(Vec, D);
    std::cerr << "Vectors: " << Vec << '\n';
    std::cerr << "Moments: " << D << '\n';
    vx = V3D(Vec[0][0], Vec[1][0], Vec[2][0]);
    vy = V3D(Vec[0][1], Vec[1][1], Vec[2][1]);
    vz = V3D(Vec[0][2], Vec[1][2], Vec[2][2]);
  }

  // find assembly sizes along the principal axes
  double hx, hy, hz; // sizes along x,y, and z axis

  // maximum displacements from the mass centre along axis vx,vy, and vz
  // in positive (p) and negative (n) directions.
  // positive displacements are positive numbers and negative ones are negative
  double hxn = 0, hyn = 0, hzn = 0;
  double hxp = 0, hyp = 0, hzp = 0;
  for (const_comp_it it = group.begin(); it != group.end(); it++) {
    // displacement vector of a detector
    V3D p = (**it).getRelativePos() - Cmass;
    // its projection on the vx axis
    double h = p.scalar_prod(vx);
    if (h > hxp)
      hxp = h;
    if (h < hxn)
      hxn = h;
    // its projection on the vy axis
    h = p.scalar_prod(vy);
    if (h > hyp)
      hyp = h;
    if (h < hyn)
      hyn = h;
    // its projection on the vz axis
    h = p.scalar_prod(vz);
    if (h > hzp)
      hzp = h;
    if (h < hzn)
      hzn = h;
  }

  // calc the assembly sizes
  hx = hxp - hxn;
  hy = hyp - hyn;
  hz = hzp - hzn;
  // hx and hy must be practically zero
  if (hx > 1e-3 || hy > 1e-3) // arbitrary numbers
  {
    throw Kernel::Exception::InstrumentDefinitionError(
        "Detectors of a ObjCompAssembly do not lie on a staraight line");
  }

  // determine the order of the detectors to make sure that the texture
  // coordinates are correct
  bool firstAtBottom; // first detector is at the bottom of the outline shape
  // the bottom end is the one with the negative displacement from the centre
  firstAtBottom =
      ((**group.begin()).getRelativePos() - Cmass).scalar_prod(vz) < 0;

  // form the input string for the ShapeFactory
  std::ostringstream obj_str;
  if (type == "box") {

    if (hz == 0)
      hz = 0.1;

    hx = hy = 0;
    height = 0;
    V3D p0 = vectors[0];
    for (size_t i = 1; i < vectors.size(); ++i) {
      V3D p = vectors[i] - p0;
      double h = fabs(p.scalar_prod(vx));
      if (h > hx)
        hx = h;
      h = fabs(p.scalar_prod(vy));
      if (h > hy)
        hy = h;
      height = fabs(p.scalar_prod(vz));
      if (h > height)
        height = h;
    }

    vx *= hx / 2;
    vy *= hy / 2;
    vz *= hzp + height / 2;

    if (!firstAtBottom) {
      vz = vz * (-1);
    }

    // define the outline shape as cuboid
    V3D p_lfb = Cmass - vx - vy - vz;
    V3D p_lft = Cmass - vx - vy + vz;
    V3D p_lbb = Cmass - vx + vy - vz;
    V3D p_rfb = Cmass + vx - vy - vz;
    obj_str << "<cuboid id=\"shape\">";
    obj_str << "<left-front-bottom-point ";
    obj_str << "x=\"" << p_lfb.X();
    obj_str << "\" y=\"" << p_lfb.Y();
    obj_str << "\" z=\"" << p_lfb.Z();
    obj_str << "\"  />";
    obj_str << "<left-front-top-point ";
    obj_str << "x=\"" << p_lft.X();
    obj_str << "\" y=\"" << p_lft.Y();
    obj_str << "\" z=\"" << p_lft.Z();
    obj_str << "\"  />";
    obj_str << "<left-back-bottom-point ";
    obj_str << "x=\"" << p_lbb.X();
    obj_str << "\" y=\"" << p_lbb.Y();
    obj_str << "\" z=\"" << p_lbb.Z();
    obj_str << "\"  />";
    obj_str << "<right-front-bottom-point ";
    obj_str << "x=\"" << p_rfb.X();
    obj_str << "\" y=\"" << p_rfb.Y();
    obj_str << "\" z=\"" << p_rfb.Z();
    obj_str << "\"  />";
    obj_str << "</cuboid>";

  } else if (type == "cylinder") {
    // the outline is one detector height short
    hz += height;
    // shift Cmass to the end of the cylinder where the first detector is
    if (firstAtBottom) {
      Cmass += vz * hzn;
    } else {
      hzp += height;
      Cmass += vz * hzp;
      // inverse the vz axis
      vz = vz * (-1);
    }
    obj_str << "<segmented-cylinder id=\"stick\">";
    obj_str << "<centre-of-bottom-base ";
    obj_str << "x=\"" << Cmass.X();
    obj_str << "\" y=\"" << Cmass.Y();
    obj_str << "\" z=\"" << Cmass.Z();
    obj_str << "\" />";
    obj_str << "<axis x=\"" << vz.X() << "\" y=\"" << vz.Y() << "\" z=\""
            << vz.Z() << "\" /> ";
    obj_str << "<radius val=\"" << radius << "\" />";
    obj_str << "<height val=\"" << hz << "\" />";
    obj_str << "</segmented-cylinder>";
  }

  if (!obj_str.str().empty()) {
    boost::shared_ptr<Object> s = ShapeFactory().createShape(obj_str.str());
    setOutline(s);
    return s;
  }
  return boost::shared_ptr<Object>();
}
示例#12
0
/**
 * Builds a map based on the given number of neighbours
 * @param noNeighbours :: The number of nearest neighbours to use to build
 * the graph
 */
void NearestNeighbours::build(const int noNeighbours) {
  std::map<specid_t, IDetector_const_sptr> spectraDets =
      getSpectraDetectors(m_instrument, m_spectraMap);
  if (spectraDets.empty()) {
    throw std::runtime_error(
        "NearestNeighbours::build - Cannot find any spectra");
  }
  const int nspectra =
      static_cast<int>(spectraDets.size()); // ANN only deals with integers
  if (noNeighbours >= nspectra) {
    throw std::invalid_argument(
        "NearestNeighbours::build - Invalid number of neighbours");
  }

  // Clear current
  m_graph.clear();
  m_specToVertex.clear();
  m_noNeighbours = noNeighbours;

  BoundingBox bbox;
  // Base the scaling on the first detector, should be adequate but we can look
  // at this
  IDetector_const_sptr firstDet = (*spectraDets.begin()).second;
  firstDet->getBoundingBox(bbox);
  m_scale.reset(new V3D(bbox.width()));
  ANNpointArray dataPoints = annAllocPts(nspectra, 3);
  MapIV pointNoToVertex;

  std::map<specid_t, IDetector_const_sptr>::const_iterator detIt;
  int pointNo = 0;
  for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) {
    IDetector_const_sptr detector = detIt->second;
    const specid_t spectrum = detIt->first;
    V3D pos = detector->getPos() / (*m_scale);
    dataPoints[pointNo][0] = pos.X();
    dataPoints[pointNo][1] = pos.Y();
    dataPoints[pointNo][2] = pos.Z();
    Vertex vertex = boost::add_vertex(spectrum, m_graph);
    pointNoToVertex[pointNo] = vertex;
    m_specToVertex[spectrum] = vertex;
    ++pointNo;
  }

  ANNkd_tree *annTree = new ANNkd_tree(dataPoints, nspectra, 3);
  pointNo = 0;
  // Run the nearest neighbour search on each detector, reusing the arrays
  ANNidxArray nnIndexList = new ANNidx[m_noNeighbours];
  ANNdistArray nnDistList = new ANNdist[m_noNeighbours];

  for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) {
    ANNpoint scaledPos = dataPoints[pointNo];
    annTree->annkSearch(scaledPos,      // Point to search nearest neighbours of
                        m_noNeighbours, // Number of neighbours to find (8)
                        nnIndexList,    // Index list of results
                        nnDistList,     // List of distances to each of these
                        0.0 // Error bound (?) is this the radius to search in?
                        );
    // The distances that are returned are in our scaled coordinate
    // system. We store the real space ones.
    V3D realPos = V3D(scaledPos[0], scaledPos[1], scaledPos[2]) * (*m_scale);
    for (int i = 0; i < m_noNeighbours; i++) {
      ANNidx index = nnIndexList[i];
      V3D neighbour = V3D(dataPoints[index][0], dataPoints[index][1],
                          dataPoints[index][2]) *
                      (*m_scale);
      V3D distance = neighbour - realPos;
      double separation = distance.norm();
      boost::add_edge(m_specToVertex[detIt->first], // from
                      pointNoToVertex[index],       // to
                      distance, m_graph);
      if (separation > m_cutoff) {
        m_cutoff = separation;
      }
    }
    pointNo++;
  }
  delete[] nnIndexList;
  delete[] nnDistList;
  delete annTree;
  annDeallocPts(dataPoints);
  annClose();
  pointNoToVertex.clear();

  m_vertexID = get(boost::vertex_name, m_graph);
  m_edgeLength = get(boost::edge_name, m_graph);
}