/** Create the vtkStructuredGrid from the provided workspace @param progressUpdating: Reporting object to pass progress information up the stack. @return fully constructed vtkDataSet. */ vtkDataSet* vtkMDHistoQuadFactory::create(ProgressAction& progressUpdating) const { vtkDataSet* product = tryDelegatingCreation<MDHistoWorkspace, 2>(m_workspace, progressUpdating); if(product != NULL) { return product; } else { g_log.warning() << "Factory " << this->getFactoryTypeName() << " is being used. You are viewing data with less than three dimensions in the VSI. \n"; Mantid::Kernel::ReadLock lock(*m_workspace); CPUTimer tim; const int nBinsX = static_cast<int>( m_workspace->getXDimension()->getNBins() ); const int nBinsY = static_cast<int>( m_workspace->getYDimension()->getNBins() ); const coord_t maxX = m_workspace-> getXDimension()->getMaximum(); const coord_t minX = m_workspace-> getXDimension()->getMinimum(); const coord_t maxY = m_workspace-> getYDimension()->getMaximum(); const coord_t minY = m_workspace-> getYDimension()->getMinimum(); coord_t incrementX = (maxX - minX) / static_cast<coord_t>(nBinsX); coord_t incrementY = (maxY - minY) / static_cast<coord_t>(nBinsY); boost::scoped_ptr<MDHistoWorkspaceIterator> iterator(dynamic_cast<MDHistoWorkspaceIterator*>(createIteratorWithNormalization(m_normalizationOption, m_workspace.get()))); if (!iterator) { throw std::runtime_error( "Could not convert IMDIterator to a MDHistoWorkspaceIterator"); } const int imageSize = (nBinsX ) * (nBinsY ); vtkPoints *points = vtkPoints::New(); points->Allocate(static_cast<int>(imageSize)); vtkFloatArray * signal = vtkFloatArray::New(); signal->Allocate(imageSize); signal->SetName(vtkDataSetFactory::ScalarName.c_str()); signal->SetNumberOfComponents(1); //The following represent actual calculated positions. float signalScalar; const int nPointsX = nBinsX+1; const int nPointsY = nBinsY+1; /* The idea of the next chunk of code is that you should only create the points that will be needed; so an array of pointNeeded is set so that all required vertices are marked, and created in a second step. */ // Array of the points that should be created, set to false bool * pointNeeded = new bool[nPointsX*nPointsY]; memset(pointNeeded, 0, nPointsX*nPointsY*sizeof(bool)); // Array with true where the voxel should be shown bool * voxelShown = new bool[nBinsX*nBinsY]; double progressFactor = 0.5/double(nBinsX); double progressOffset = 0.5; size_t index = 0; for (int i = 0; i < nBinsX; i++) { progressUpdating.eventRaised(progressFactor*double(i)); for (int j = 0; j < nBinsY; j++) { index = j + nBinsY*i; iterator->jumpTo(index); signalScalar = static_cast<float>(iterator->getNormalizedSignal()); // Get signal normalized as per m_normalizationOption if (isSpecial( signalScalar ) || !m_thresholdRange->inRange(signalScalar)) { // out of range voxelShown[index] = false; } else { // Valid data voxelShown[index] = true; signal->InsertNextValue(static_cast<float>(signalScalar)); // Make sure all 4 neighboring points are set to true size_t pointIndex = i * nPointsY + j; pointNeeded[pointIndex] = true; pointIndex++; pointNeeded[pointIndex] = true; pointIndex += nPointsY-1; pointNeeded[pointIndex] = true; pointIndex++; pointNeeded[pointIndex] = true; } } } std::cout << tim << " to check all the signal values." << std::endl; // Get the transformation that takes the points in the TRANSFORMED space back into the ORIGINAL (not-rotated) space. Mantid::API::CoordTransform const* transform = NULL; if (m_useTransform) transform = m_workspace->getTransformToOriginal(); Mantid::coord_t in[3]; Mantid::coord_t out[3]; in[2] = 0; // Array with the point IDs (only set where needed) vtkIdType * pointIDs = new vtkIdType[nPointsX*nPointsY]; index = 0; for (int i = 0; i < nPointsX; i++) { progressUpdating.eventRaised((progressFactor*double(i)) + progressOffset); in[0] = minX + (static_cast<coord_t>(i) * incrementX); //Calculate increment in x; for (int j = 0; j < nPointsY; j++) { // Create the point only when needed if (pointNeeded[index]) { in[1] = minY + (static_cast<coord_t>(j) * incrementY); //Calculate increment in y; if (transform) { transform->apply(in, out); pointIDs[index] = points->InsertNextPoint(out); } else pointIDs[index] = points->InsertNextPoint(in); } index++; } } std::cout << tim << " to create the needed points." << std::endl; vtkUnstructuredGrid *visualDataSet = vtkUnstructuredGrid::New(); visualDataSet->Allocate(imageSize); visualDataSet->SetPoints(points); visualDataSet->GetCellData()->SetScalars(signal); // ------ Quad creation ---------------- vtkQuad* quad = vtkQuad::New(); // Significant speed increase by creating ONE quad index = 0; for (int i = 0; i < nBinsX; i++) { for (int j = 0; j < nBinsY; j++) { if (voxelShown[index]) { // The quad will be shown quad->GetPointIds()->SetId(0, pointIDs[(i)*nPointsY + j]); quad->GetPointIds()->SetId(1, pointIDs[(i+1)*nPointsY + j]); quad->GetPointIds()->SetId(2, pointIDs[(i+1)*nPointsY + j+1]); quad->GetPointIds()->SetId(3, pointIDs[(i)*nPointsY + j+1]); visualDataSet->InsertNextCell(VTK_QUAD, quad->GetPointIds()); } index++; } } quad->Delete(); std::cout << tim << " to create and add the quads." << std::endl; points->Delete(); signal->Delete(); visualDataSet->Squeeze(); delete [] pointIDs; delete [] voxelShown; delete [] pointNeeded; // Hedge against empty data sets if (visualDataSet->GetNumberOfPoints() <= 0) { visualDataSet->Delete(); vtkNullUnstructuredGrid nullGrid; visualDataSet = nullGrid.createNullData(); } return visualDataSet; } }
/** Create the vtkStructuredGrid from the provided workspace @param progressUpdating: Reporting object to pass progress information up the stack. @return fully constructed vtkDataSet. */ vtkSmartPointer<vtkDataSet> vtkMDLineFactory::create(ProgressAction &progressUpdating) const { auto product = tryDelegatingCreation<IMDEventWorkspace, 1>(m_workspace, progressUpdating); if (product != nullptr) { return product; } else { g_log.warning() << "Factory " << this->getFactoryTypeName() << " is being used. You are viewing data with less than " "three dimensions in the VSI. \n"; IMDEventWorkspace_sptr imdws = doInitialize<IMDEventWorkspace, 1>(m_workspace); // Acquire a scoped read-only lock to the workspace (prevent segfault from // algos modifying ws) Mantid::Kernel::ReadLock lock(*imdws); const size_t nDims = imdws->getNumDims(); size_t nNonIntegrated = imdws->getNonIntegratedDimensions().size(); /* Write mask array with correct order for each internal dimension. */ auto masks = Mantid::Kernel::make_unique<bool[]>(nDims); for (size_t i_dim = 0; i_dim < nDims; ++i_dim) { bool bIntegrated = imdws->getDimension(i_dim)->getIsIntegrated(); masks[i_dim] = !bIntegrated; // TRUE for unmaksed, integrated dimensions are masked. } // Ensure destruction in any event. boost::scoped_ptr<IMDIterator> it( createIteratorWithNormalization(m_normalizationOption, imdws.get())); // Create 2 points per box. vtkNew<vtkPoints> points; points->SetNumberOfPoints(it->getDataSize() * 2); // One scalar per box vtkNew<vtkFloatArray> signals; signals->Allocate(it->getDataSize()); signals->SetName(vtkDataSetFactory::ScalarName.c_str()); signals->SetNumberOfComponents(1); size_t nVertexes; auto visualDataSet = vtkSmartPointer<vtkUnstructuredGrid>::New(); visualDataSet->Allocate(it->getDataSize()); vtkNew<vtkIdList> linePointList; linePointList->SetNumberOfIds(2); Mantid::API::CoordTransform const *transform = NULL; if (m_useTransform) { transform = imdws->getTransformToOriginal(); } Mantid::coord_t out[1]; auto useBox = std::vector<bool>(it->getDataSize()); double progressFactor = 0.5 / double(it->getDataSize()); double progressOffset = 0.5; size_t iBox = 0; do { progressUpdating.eventRaised(double(iBox) * progressFactor); Mantid::signal_t signal_normalized = it->getNormalizedSignal(); if (std::isfinite(signal_normalized) && m_thresholdRange->inRange(signal_normalized)) { useBox[iBox] = true; signals->InsertNextValue(static_cast<float>(signal_normalized)); auto coords = std::unique_ptr<coord_t[]>( it->getVertexesArray(nVertexes, nNonIntegrated, masks.get())); // Iterate through all coordinates. Candidate for speed improvement. for (size_t v = 0; v < nVertexes; ++v) { coord_t *coord = coords.get() + v * 1; size_t id = iBox * 2 + v; if (m_useTransform) { transform->apply(coord, out); points->SetPoint(id, out[0], 0, 0); } else { points->SetPoint(id, coord[0], 0, 0); } } } // valid number of vertexes returned else { useBox[iBox] = false; } ++iBox; } while (it->next()); for (size_t ii = 0; ii < it->getDataSize(); ++ii) { progressUpdating.eventRaised((double(ii) * progressFactor) + progressOffset); if (useBox[ii] == true) { vtkIdType pointIds = ii * 2; linePointList->SetId(0, pointIds + 0); // xyx linePointList->SetId(1, pointIds + 1); // dxyz visualDataSet->InsertNextCell(VTK_LINE, linePointList.GetPointer()); } // valid number of vertexes returned } signals->Squeeze(); points->Squeeze(); visualDataSet->SetPoints(points.GetPointer()); visualDataSet->GetCellData()->SetScalars(signals.GetPointer()); visualDataSet->Squeeze(); // Hedge against empty data sets if (visualDataSet->GetNumberOfPoints() <= 0) { vtkNullUnstructuredGrid nullGrid; visualDataSet = nullGrid.createNullData(); } vtkSmartPointer<vtkDataSet> dataset = visualDataSet; return dataset; } }
/** Method for creating a 3D or 4D data set * * @param timestep :: index of the time step (4th dimension) in the workspace. * Set to 0 for a 3D workspace. * @param progressUpdate: Progress updating. passes progress information up the *stack. * @return the vtkDataSet created */ vtkSmartPointer<vtkDataSet> vtkMDHistoHexFactory::create3Dor4D(size_t timestep, ProgressAction &progressUpdate) const { // Acquire a scoped read-only lock to the workspace (prevent segfault from // algos modifying ws) ReadLock lock(*m_workspace); const size_t nDims = m_workspace->getNonIntegratedDimensions().size(); std::vector<size_t> indexMultiplier(nDims, 0); // For quick indexing, accumulate these values // First multiplier indexMultiplier[0] = m_workspace->getDimension(0)->getNBins(); for (size_t d = 1; d < nDims; d++) { indexMultiplier[d] = indexMultiplier[d - 1] * m_workspace->getDimension(d)->getNBins(); } const int nBinsX = static_cast<int>(m_workspace->getXDimension()->getNBins()); const int nBinsY = static_cast<int>(m_workspace->getYDimension()->getNBins()); const int nBinsZ = static_cast<int>(m_workspace->getZDimension()->getNBins()); const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ); vtkSmartPointer<vtkStructuredGrid> visualDataSet = vtkSmartPointer<vtkStructuredGrid>::New(); visualDataSet->SetDimensions(nBinsX + 1, nBinsY + 1, nBinsZ + 1); // Array with true where the voxel should be shown double progressFactor = 0.5 / double(imageSize); std::size_t offset = 0; if (nDims == 4) { offset = timestep * indexMultiplier[2]; } std::unique_ptr<MDHistoWorkspaceIterator> iterator( dynamic_cast<MDHistoWorkspaceIterator *>(createIteratorWithNormalization( m_normalizationOption, m_workspace.get()))); vtkNew<vtkMDHWSignalArray<double>> signal; signal->SetName(vtkDataSetFactory::ScalarName.c_str()); signal->InitializeArray(std::move(iterator), offset, imageSize); visualDataSet->GetCellData()->SetScalars(signal.GetPointer()); for (vtkIdType index = 0; index < imageSize; ++index) { progressUpdate.eventRaised(double(index) * progressFactor); double signalScalar = signal->GetValue(index); bool maskValue = (!std::isfinite(signalScalar) || !m_thresholdRange->inRange(signalScalar)); if (maskValue) { visualDataSet->BlankCell(index); } } vtkNew<vtkPoints> points; Mantid::coord_t in[2]; const coord_t maxX = m_workspace->getXDimension()->getMaximum(); const coord_t minX = m_workspace->getXDimension()->getMinimum(); const coord_t maxY = m_workspace->getYDimension()->getMaximum(); const coord_t minY = m_workspace->getYDimension()->getMinimum(); const coord_t maxZ = m_workspace->getZDimension()->getMaximum(); const coord_t minZ = m_workspace->getZDimension()->getMinimum(); const coord_t incrementX = (maxX - minX) / static_cast<coord_t>(nBinsX); const coord_t incrementY = (maxY - minY) / static_cast<coord_t>(nBinsY); const coord_t incrementZ = (maxZ - minZ) / static_cast<coord_t>(nBinsZ); const vtkIdType nPointsX = nBinsX + 1; const vtkIdType nPointsY = nBinsY + 1; const vtkIdType nPointsZ = nBinsZ + 1; vtkFloatArray *pointsarray = vtkFloatArray::SafeDownCast(points->GetData()); if (pointsarray == NULL) { throw std::runtime_error("Failed to cast vtkDataArray to vtkFloatArray."); } else if (pointsarray->GetNumberOfComponents() != 3) { throw std::runtime_error("points array must have 3 components."); } float *it = pointsarray->WritePointer(0, nPointsX * nPointsY * nPointsZ * 3); // Array with the point IDs (only set where needed) progressFactor = 0.5 / static_cast<double>(nPointsZ); double progressOffset = 0.5; for (int z = 0; z < nPointsZ; z++) { // Report progress updates for the last 50% progressUpdate.eventRaised(double(z) * progressFactor + progressOffset); in[1] = (minZ + (static_cast<coord_t>(z) * incrementZ)); // Calculate increment in z; for (int y = 0; y < nPointsY; y++) { in[0] = (minY + (static_cast<coord_t>(y) * incrementY)); // Calculate increment in y; for (int x = 0; x < nPointsX; x++) { it[0] = (minX + (static_cast<coord_t>(x) * incrementX)); // Calculate increment in x; it[1] = in[0]; it[2] = in[1]; std::advance(it, 3); } } } visualDataSet->SetPoints(points.GetPointer()); visualDataSet->Register(NULL); visualDataSet->Squeeze(); // Hedge against empty data sets if (visualDataSet->GetNumberOfPoints() <= 0) { vtkNullStructuredGrid nullGrid; visualDataSet = nullGrid.createNullData(); } vtkSmartPointer<vtkDataSet> dataset = visualDataSet; return dataset; }