예제 #1
0
    /**
    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;
      }
    }
예제 #2
0
  /** 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;

  }