/** Obtain coordinates for a line plot through a IMDWorkspace. * Cross the workspace from start to end points, recording the signal along the *line. * Sets the x,y vectors to the histogram bin boundaries and counts * * @param start :: coordinates of the start point of the line * @param end :: coordinates of the end point of the line * @param normalize :: how to normalize the signal * @returns :: a LinePlot in which x is set to the boundaries of the bins, * relative to start of the line, y is set to the normalized signal for * each bin with Length = length(x) - 1 and e is set to the normalized * errors for each bin with Length = length(x) - 1. */ IMDWorkspace::LinePlot IMDWorkspace::getLinePlot(const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize) const { // TODO: Don't use a fixed number of points later size_t numPoints = 200; VMD step = (end - start) / double(numPoints); double stepLength = step.norm(); // This will be the curve as plotted LinePlot line; for (size_t i = 0; i < numPoints; i++) { // Coordinate along the line VMD coord = start + step * double(i); // Record the position along the line line.x.push_back(static_cast<coord_t>(stepLength * double(i))); signal_t yVal = this->getSignalAtCoord(coord.getBareArray(), normalize); line.y.push_back(yVal); line.e.push_back(0.0); } // And the last point line.x.push_back((end - start).norm()); return line; }
/** Obtain coordinates for a line plot through a MDWorkspace. * Cross the workspace from start to end points, recording the signal along the *lin at either bin boundaries, or halfway between bin boundaries (which is bin *centres if the line is dimension aligned). If recording halfway values then *omit points in masked bins. * * @param start :: coordinates of the start point of the line * @param end :: coordinates of the end point of the line * @param normalize :: how to normalize the signal * @returns :: LinePlot with x as the boundaries of the bins, relative * to start of the line, y set to the normalized signal for each bin with * Length = length(x) - 1 and e as the error vector for each bin. * @param bin_centres :: if true then record points halfway between bin *boundaries, otherwise record on bin boundaries */ IMDWorkspace::LinePlot MDHistoWorkspace::getLinePoints( const Mantid::Kernel::VMD &start, const Mantid::Kernel::VMD &end, Mantid::API::MDNormalization normalize, const bool bin_centres) const { LinePlot line; size_t nd = this->getNumDims(); if (start.getNumDims() != nd) throw std::runtime_error("Start point must have the same number of " "dimensions as the workspace."); if (end.getNumDims() != nd) throw std::runtime_error( "End point must have the same number of dimensions as the workspace."); // Unit-vector of the direction VMD dir = end - start; const auto length = dir.normalize(); // Vector with +1 where direction is positive, -1 where negative #define sgn(x) ((x < 0) ? -1.0f : ((x > 0.) ? 1.0f : 0.0f)) VMD dirSign(nd); for (size_t d = 0; d < nd; d++) { dirSign[d] = sgn(dir[d]); } const size_t BADINDEX = size_t(-1); // Dimensions of the workspace boost::scoped_array<size_t> index(new size_t[nd]); boost::scoped_array<size_t> numBins(new size_t[nd]); for (size_t d = 0; d < nd; d++) { IMDDimension_const_sptr dim = this->getDimension(d); index[d] = BADINDEX; numBins[d] = dim->getNBins(); } const std::set<coord_t> boundaries = getBinBoundariesOnLine(start, end, nd, dir, length); if (boundaries.empty()) { this->makeSinglePointWithNaN(line.x, line.y, line.e); // Require x.size() = y.size()+1 if recording bin boundaries if (!bin_centres) line.x.push_back(length); return line; } else { // Get the first point std::set<coord_t>::iterator it; it = boundaries.cbegin(); coord_t lastLinePos = *it; VMD lastPos = start + (dir * lastLinePos); if (!bin_centres) { line.x.push_back(lastLinePos); } ++it; coord_t linePos = 0; for (; it != boundaries.cend(); ++it) { // This is our current position along the line linePos = *it; // This is the full position at this boundary VMD pos = start + (dir * linePos); // Position in the middle of the bin VMD middle = (pos + lastPos) * 0.5; // Find the signal in this bin const auto linearIndex = this->getLinearIndexAtCoord(middle.getBareArray()); if (bin_centres && !this->getIsMaskedAt(linearIndex)) { coord_t bin_centrePos = static_cast<coord_t>((linePos + lastLinePos) * 0.5); line.x.push_back(bin_centrePos); } else if (!bin_centres) line.x.push_back(linePos); if (linearIndex < m_length) { auto normalizer = getNormalizationFactor(normalize, linearIndex); // And add the normalized signal/error to the list too auto signal = this->getSignalAt(linearIndex) * normalizer; if (boost::math::isinf(signal)) { // The plotting library (qwt) doesn't like infs. signal = std::numeric_limits<signal_t>::quiet_NaN(); } if (!bin_centres || !this->getIsMaskedAt(linearIndex)) { line.y.push_back(signal); line.e.push_back(this->getErrorAt(linearIndex) * normalizer); } // Save the position for next bin lastPos = pos; } else { // Invalid index. This shouldn't happen line.y.push_back(std::numeric_limits<signal_t>::quiet_NaN()); line.e.push_back(std::numeric_limits<signal_t>::quiet_NaN()); } lastLinePos = linePos; } // for each unique boundary // If all bins were masked if (line.x.size() == 0) { this->makeSinglePointWithNaN(line.x, line.y, line.e); } } return line; }