/** Create the vtkStructuredGrid from the provided workspace @param progressUpdating: Reporting object to pass progress information up the stack. @return fully constructed vtkDataSet. */ vtkDataSet* vtkMDQuadFactory::create(ProgressAction& progressUpdating) const { vtkDataSet* product = tryDelegatingCreation<IMDEventWorkspace, 2>(m_workspace, progressUpdating); if(product != NULL) { return product; } else { IMDEventWorkspace_sptr imdws = this->castAndCheck<IMDEventWorkspace, 2>(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. */ bool* masks = new 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(imdws->createIterator()); // Create 4 points per box. vtkPoints *points = vtkPoints::New(); points->SetNumberOfPoints(it->getDataSize() * 4); // One scalar per box vtkFloatArray * signals = vtkFloatArray::New(); signals->Allocate(it->getDataSize()); signals->SetName(m_scalarName.c_str()); signals->SetNumberOfComponents(1); size_t nVertexes; vtkUnstructuredGrid *visualDataSet = vtkUnstructuredGrid::New(); visualDataSet->Allocate(it->getDataSize()); vtkIdList * quadPointList = vtkIdList::New(); quadPointList->SetNumberOfIds(4); Mantid::API::CoordTransform* transform = NULL; if (m_useTransform) { transform = imdws->getTransformToOriginal(); } Mantid::coord_t out[2]; bool* useBox = new bool[it->getDataSize()]; double progressFactor = 0.5/double(it->getDataSize()); double progressOffset = 0.5; size_t iBox = 0; do { progressUpdating.eventRaised(progressFactor * double(iBox)); Mantid::signal_t signal_normalized= it->getNormalizedSignal(); if (!isSpecial( signal_normalized ) && m_thresholdRange->inRange(signal_normalized)) { useBox[iBox] = true; signals->InsertNextValue(static_cast<float>(signal_normalized)); coord_t* coords = it->getVertexesArray(nVertexes, nNonIntegrated, masks); delete [] coords; coords = it->getVertexesArray(nVertexes, nNonIntegrated, masks); //Iterate through all coordinates. Candidate for speed improvement. for(size_t v = 0; v < nVertexes; ++v) { coord_t * coord = coords + v*2; size_t id = iBox*4 + v; if(m_useTransform) { transform->apply(coord, out); points->SetPoint(id, out[0], out[1], 0); } else { points->SetPoint(id, coord[0], coord[1], 0); } } // Free memory delete [] coords; } // valid number of vertexes returned else { useBox[iBox] = false; } ++iBox; } while (it->next()); delete[] masks; for(size_t ii = 0; ii < it->getDataSize() ; ++ii) { progressUpdating.eventRaised((progressFactor * double(ii)) + progressOffset); if (useBox[ii] == true) { vtkIdType pointIds = vtkIdType(ii * 4); quadPointList->SetId(0, pointIds + 0); //xyx quadPointList->SetId(1, pointIds + 1); //dxyz quadPointList->SetId(2, pointIds + 3); //dxdyz quadPointList->SetId(3, pointIds + 2); //xdyz visualDataSet->InsertNextCell(VTK_QUAD, quadPointList); } // valid number of vertexes returned } delete[] useBox; signals->Squeeze(); points->Squeeze(); visualDataSet->SetPoints(points); visualDataSet->GetCellData()->SetScalars(signals); visualDataSet->Squeeze(); signals->Delete(); points->Delete(); quadPointList->Delete(); return visualDataSet; } }
/** 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 do4D :: if true, create a 4D dataset, else to 3D * @param progressUpdate: Progress updating. passes progress information up the stack. * @return the vtkDataSet created */ vtkDataSet* vtkMDHistoHexFactory::create3Dor4D(size_t timestep, bool do4D, ProgressAction & progressUpdate) const { // Acquire a scoped read-only lock to the workspace (prevent segfault from algos modifying ws) ReadLock lock(*m_workspace); 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 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(); coord_t incrementX = (maxX - minX) / static_cast<coord_t>(nBinsX); coord_t incrementY = (maxY - minY) / static_cast<coord_t>(nBinsY); coord_t incrementZ = (maxZ - minZ) / static_cast<coord_t>(nBinsZ); const int imageSize = (nBinsX ) * (nBinsY ) * (nBinsZ ); vtkPoints *points = vtkPoints::New(); points->Allocate(static_cast<int>(imageSize)); vtkFloatArray * signal = vtkFloatArray::New(); signal->Allocate(imageSize); signal->SetName(m_scalarName.c_str()); signal->SetNumberOfComponents(1); double signalScalar; const int nPointsX = nBinsX+1; const int nPointsY = nBinsY+1; const int nPointsZ = nBinsZ+1; CPUTimer tim; /* 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*nPointsZ]; memset(pointNeeded, 0, nPointsX*nPointsY*nPointsZ*sizeof(bool)); // Array with true where the voxel should be shown bool * voxelShown = new bool[nBinsX*nBinsY*nBinsZ]; double progressFactor = 0.5/double(nBinsZ); double progressOffset = 0.5; size_t index = 0; for (int z = 0; z < nBinsZ; z++) { //Report progress updates for the first 50% progressUpdate.eventRaised(double(z)*progressFactor); for (int y = 0; y < nBinsY; y++) { for (int x = 0; x < nBinsX; x++) { /* NOTE: It is very important to match the ordering of the two arrays * (the one used in MDHistoWorkspace and voxelShown/pointNeeded). * If you access the array in the wrong way and can't cache it on L1/L2 cache, I got a factor of 8x slowdown. */ //index = x + (nBinsX * y) + (nBinsX*nBinsY*z); if (do4D) signalScalar = m_workspace->getSignalNormalizedAt(x,y,z, timestep); else signalScalar = m_workspace->getSignalNormalizedAt(x,y,z); 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 8 neighboring points are set to true size_t pointIndex = x + (nPointsX * y) + (nPointsX*nPointsY*z); //(Note this index is different then the other one) pointNeeded[pointIndex] = true; pointIndex++; pointNeeded[pointIndex] = true; pointIndex += nPointsX-1; pointNeeded[pointIndex] = true; pointIndex++; pointNeeded[pointIndex] = true; pointIndex += nPointsX*nPointsY - nPointsX - 1; pointNeeded[pointIndex] = true; pointIndex++; pointNeeded[pointIndex] = true; pointIndex += nPointsX-1; pointNeeded[pointIndex] = true; pointIndex++; pointNeeded[pointIndex] = true; } index++; } } } 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* transform = NULL; if (m_useTransform) transform = m_workspace->getTransformToOriginal(); Mantid::coord_t in[3]; Mantid::coord_t out[3]; // Array with the point IDs (only set where needed) vtkIdType * pointIDs = new vtkIdType[nPointsX*nPointsY*nPointsZ]; index = 0; progressFactor = 0.5/static_cast<double>(nPointsZ); for (int z = 0; z < nPointsZ; z++) { //Report progress updates for the last 50% progressUpdate.eventRaised(double(z)*progressFactor + progressOffset); in[2] = (minZ + (static_cast<coord_t>(z) * incrementZ)); //Calculate increment in z; for (int y = 0; y < nPointsY; y++) { in[1] = (minY + (static_cast<coord_t>(y) * incrementY)); //Calculate increment in y; for (int x = 0; x < nPointsX; x++) { // Create the point only when needed if (pointNeeded[index]) { in[0] = (minX + (static_cast<coord_t>(x) * incrementX)); //Calculate increment in x; 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); // ------ Hexahedron creation ---------------- // It is approx. 40 x faster to create the hexadron only once, and reuse it for each voxel. vtkHexahedron *theHex = vtkHexahedron::New(); index = 0; for (int z = 0; z < nBinsZ; z++) { for (int y = 0; y < nBinsY; y++) { for (int x = 0; x < nBinsX; x++) { if (voxelShown[index]) { //Only create topologies for those cells which are not sparse. // create a hexahedron topology vtkIdType id_xyz = pointIDs[(x) + (y)*nPointsX + z*nPointsX*nPointsY]; vtkIdType id_dxyz = pointIDs[(x+1) + (y)*nPointsX + z*nPointsX*nPointsY]; vtkIdType id_dxdyz = pointIDs[(x+1) + (y+1)*nPointsX + z*nPointsX*nPointsY]; vtkIdType id_xdyz = pointIDs[(x) + (y+1)*nPointsX + z*nPointsX*nPointsY]; vtkIdType id_xydz = pointIDs[(x) + (y)*nPointsX + (z+1)*nPointsX*nPointsY]; vtkIdType id_dxydz = pointIDs[(x+1) + (y)*nPointsX + (z+1)*nPointsX*nPointsY]; vtkIdType id_dxdydz = pointIDs[(x+1) + (y+1)*nPointsX + (z+1)*nPointsX*nPointsY]; vtkIdType id_xdydz = pointIDs[(x) + (y+1)*nPointsX + (z+1)*nPointsX*nPointsY]; //create the hexahedron theHex->GetPointIds()->SetId(0, id_xyz); theHex->GetPointIds()->SetId(1, id_dxyz); theHex->GetPointIds()->SetId(2, id_dxdyz); theHex->GetPointIds()->SetId(3, id_xdyz); theHex->GetPointIds()->SetId(4, id_xydz); theHex->GetPointIds()->SetId(5, id_dxydz); theHex->GetPointIds()->SetId(6, id_dxdydz); theHex->GetPointIds()->SetId(7, id_xdydz); visualDataSet->InsertNextCell(VTK_HEXAHEDRON, theHex->GetPointIds()); } index++; } } } theHex->Delete(); std::cout << tim << " to create and add the hexadrons." << std::endl; points->Delete(); signal->Delete(); visualDataSet->Squeeze(); delete [] pointIDs; delete [] voxelShown; delete [] pointNeeded; return visualDataSet; }