text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    vtkSelectionSource.cxx
  
    Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
    All rights reserved.
    See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
  
       This software is distributed WITHOUT ANY WARRANTY; without even
       the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
       PURPOSE.  See the above copyright notice for more information.
  
  =========================================================================*/
  #include "vtkSelectionSource.h"
  
  #include "vtkCommand.h"
  #include "vtkDoubleArray.h"
  #include "vtkIdTypeArray.h"
  #include "vtkInformation.h"
  #include "vtkInformationVector.h"
  #include "vtkNew.h"
  #include "vtkObjectFactory.h"
  #include "vtkSelection.h"
  #include "vtkSelectionNode.h"
  #include "vtkStreamingDemandDrivenPipeline.h"
  #include "vtkStringArray.h"
  #include "vtkUnsignedIntArray.h"
  
  #include <set>
  #include <vector>
  
  vtkStandardNewMacro(vtkSelectionSource);
  
  class vtkSelectionSourceInternals
  {
  public:
    typedef std::set<vtkIdType> IDSetType;
    typedef std::vector<IDSetType> IDsType;
    IDsType IDs;
  
    typedef std::set<vtkStdString> StringIDSetType;
    typedef std::vector<StringIDSetType> StringIDsType;
    StringIDsType StringIDs;
  
    std::vector<double> Thresholds;
    std::vector<double> Locations;
    IDSetType Blocks;
    double Frustum[32];
  };
  
  //----------------------------------------------------------------------------
  vtkSelectionSource::vtkSelectionSource()
  {
    this->SetNumberOfInputPorts(0);
    this->Internal = new vtkSelectionSourceInternals;
  
    this->ContentType = vtkSelectionNode::INDICES;
    this->FieldType = vtkSelectionNode::CELL;
    this->ContainingCells = 1;
    this->Inverse = 0;
    this->ArrayName = nullptr;
    this->ArrayComponent = 0;
    for (int cc = 0; cc < 32; cc++)
    {
      this->Internal->Frustum[cc] = 0;
    }
    this->CompositeIndex = -1;
    this->HierarchicalLevel = -1;
    this->HierarchicalIndex = -1;
    this->QueryString = nullptr;
    this->NumberOfLayers = 0;
  }
  
  //----------------------------------------------------------------------------
  vtkSelectionSource::~vtkSelectionSource()
  {
    delete this->Internal;
    delete[] this->ArrayName;
    delete[] this->QueryString;
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::RemoveAllIDs()
  {
    this->Internal->IDs.clear();
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::RemoveAllStringIDs()
  {
    this->Internal->StringIDs.clear();
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::RemoveAllLocations()
  {
    this->Internal->Locations.clear();
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::RemoveAllThresholds()
  {
    this->Internal->Thresholds.clear();
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::AddID(vtkIdType proc, vtkIdType id)
  {
    // proc == -1 means all processes. All other are stored at index proc+1
    proc++;
  
    if (proc >= (vtkIdType)this->Internal->IDs.size())
    {
      this->Internal->IDs.resize(proc + 1);
    }
    vtkSelectionSourceInternals::IDSetType& idSet = this->Internal->IDs[proc];
    idSet.insert(id);
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::AddStringID(vtkIdType proc, const char* id)
  {
    // proc == -1 means all processes. All other are stored at index proc+1
    proc++;
  
    if (proc >= (vtkIdType)this->Internal->StringIDs.size())
    {
      this->Internal->StringIDs.resize(proc + 1);
    }
    vtkSelectionSourceInternals::StringIDSetType& idSet = this->Internal->StringIDs[proc];
    idSet.insert(id);
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::AddLocation(double x, double y, double z)
  {
    this->Internal->Locations.push_back(x);
    this->Internal->Locations.push_back(y);
    this->Internal->Locations.push_back(z);
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::AddThreshold(double min, double max)
  {
    this->Internal->Thresholds.push_back(min);
    this->Internal->Thresholds.push_back(max);
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::SetFrustum(double* vertices)
  {
    for (int cc = 0; cc < 32; cc++)
    {
      if (vertices[cc] != this->Internal->Frustum[cc])
      {
        memcpy(this->Internal->Frustum, vertices, 32 * sizeof(double));
        this->Modified();
        break;
      }
    }
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::AddBlock(vtkIdType block)
  {
    this->Internal->Blocks.insert(block);
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::RemoveAllBlocks()
  {
    this->Internal->Blocks.clear();
    this->Modified();
  }
  
  //----------------------------------------------------------------------------
  void vtkSelectionSource::PrintSelf(ostream& os, vtkIndent indent)
  {
    this->Superclass::PrintSelf(os, indent);
    os << indent << "ContentType: ";
    switch (this->ContentType)
    {
      case vtkSelectionNode::SELECTIONS:
        os << "SELECTIONS";
        break;
      case vtkSelectionNode::GLOBALIDS:
        os << "GLOBALIDS";
        break;
      case vtkSelectionNode::VALUES:
        os << "VALUES";
        break;
      case vtkSelectionNode::INDICES:
        os << "INDICES";
        break;
      case vtkSelectionNode::FRUSTUM:
        os << "FRUSTUM";
        break;
      case vtkSelectionNode::LOCATIONS:
        os << "LOCATIONS";
        break;
      case vtkSelectionNode::THRESHOLDS:
        os << "THRESHOLDS";
        break;
      case vtkSelectionNode::BLOCKS:
        os << "BLOCKS";
        break;
      default:
        os << "UNKNOWN";
    }
    os << endl;
  
    os << indent << "FieldType: ";
    switch (this->FieldType)
    {
      case vtkSelectionNode::CELL:
        os << "CELL";
        break;
      case vtkSelectionNode::POINT:
        os << "POINT";
        break;
      case vtkSelectionNode::FIELD:
        os << "FIELD";
        break;
      case vtkSelectionNode::VERTEX:
        os << "VERTEX";
        break;
      case vtkSelectionNode::EDGE:
        os << "EDGE";
        break;
      case vtkSelectionNode::ROW:
        os << "ROW";
        break;
      default:
        os << "UNKNOWN";
    }
    os << endl;
  
    os << indent << "ContainingCells: ";
    os << (this->ContainingCells ? "CELLS" : "POINTS") << endl;
    os << indent << "Inverse: " << this->Inverse << endl;
    os << indent << "ArrayName: " << (this->ArrayName ? this->ArrayName : "nullptr") << endl;
    os << indent << "ArrayComponent: " << this->ArrayComponent << endl;
    os << indent << "CompositeIndex: " << this->CompositeIndex << endl;
    os << indent << "HierarchicalLevel: " << this->HierarchicalLevel << endl;
    os << indent << "HierarchicalIndex: " << this->HierarchicalIndex << endl;
    os << indent << "QueryString: " << (this->QueryString ? this->QueryString : "nullptr") << endl;
    os << indent << "NumberOfLayers: " << this->NumberOfLayers << endl;
  }
  
  //----------------------------------------------------------------------------
  int vtkSelectionSource::RequestInformation(vtkInformation* vtkNotUsed(request),
    vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
  {
    vtkInformation* outInfo = outputVector->GetInformationObject(0);
    outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
  
    return 1;
  }
  
  //----------------------------------------------------------------------------
  int vtkSelectionSource::RequestData(vtkInformation* vtkNotUsed(request),
    vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
  {
    vtkSelection* outputSel = vtkSelection::GetData(outputVector);
    vtkNew<vtkSelectionNode> output;
    outputSel->AddNode(output);
    vtkInformation* oProperties = output->GetProperties();
  
    vtkInformation* outInfo = outputVector->GetInformationObject(0);
    int piece = 0;
    if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()))
    {
      piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
    }
  
    if (this->CompositeIndex >= 0)
    {
      oProperties->Set(vtkSelectionNode::COMPOSITE_INDEX(), this->CompositeIndex);
    }
  
    if (this->HierarchicalLevel >= 0 && this->HierarchicalIndex >= 0)
    {
      oProperties->Set(vtkSelectionNode::HIERARCHICAL_LEVEL(), this->HierarchicalLevel);
      oProperties->Set(vtkSelectionNode::HIERARCHICAL_INDEX(), this->HierarchicalIndex);
    }
  
    // First look for string ids.
    if (((this->ContentType == vtkSelectionNode::GLOBALIDS) ||
          (this->ContentType == vtkSelectionNode::PEDIGREEIDS) ||
          (this->ContentType == vtkSelectionNode::INDICES) ||
          (this->ContentType == vtkSelectionNode::VALUES)) &&
      !this->Internal->StringIDs.empty())
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
  
      vtkNew<vtkStringArray> selectionList;
      output->SetSelectionList(selectionList);
  
      // Number of selected items common to all pieces
      vtkIdType numCommonElems = 0;
      if (!this->Internal->StringIDs.empty())
      {
        numCommonElems = static_cast<vtkIdType>(this->Internal->StringIDs[0].size());
      }
      if (piece + 1 >= (int)this->Internal->StringIDs.size() && numCommonElems == 0)
      {
        vtkDebugMacro("No selection for piece: " << piece);
      }
      else
      {
        // idx == 0 is the list for all pieces
        // idx == piece+1 is the list for the current piece
        size_t pids[2];
        pids[0] = 0;
        pids[1] = static_cast<size_t>(piece + 1);
        for (int i = 0; i < 2; i++)
        {
          size_t idx = pids[i];
          if (idx >= this->Internal->StringIDs.size())
          {
            continue;
          }
  
          vtkSelectionSourceInternals::StringIDSetType& selSet = this->Internal->StringIDs[idx];
  
          if (!selSet.empty())
          {
            // Create the selection list
            selectionList->SetNumberOfTuples(static_cast<vtkIdType>(selSet.size()));
            // iterate over ids and insert to the selection list
            vtkSelectionSourceInternals::StringIDSetType::iterator iter = selSet.begin();
            for (vtkIdType idx2 = 0; iter != selSet.end(); ++iter, ++idx2)
            {
              selectionList->SetValue(idx2, *iter);
            }
          }
        }
      }
    }
  
    // If no string ids, use integer ids.
    if (((this->ContentType == vtkSelectionNode::GLOBALIDS) ||
          (this->ContentType == vtkSelectionNode::PEDIGREEIDS) ||
          (this->ContentType == vtkSelectionNode::INDICES) ||
          (this->ContentType == vtkSelectionNode::VALUES)) &&
      this->Internal->StringIDs.empty())
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
  
      vtkNew<vtkIdTypeArray> selectionList;
      output->SetSelectionList(selectionList);
  
      // Number of selected items common to all pieces
      vtkIdType numCommonElems = 0;
      if (!this->Internal->IDs.empty())
      {
        numCommonElems = static_cast<vtkIdType>(this->Internal->IDs[0].size());
      }
      if (piece + 1 >= (int)this->Internal->IDs.size() && numCommonElems == 0)
      {
        vtkDebugMacro("No selection for piece: " << piece);
      }
      else
      {
        // idx == 0 is the list for all pieces
        // idx == piece+1 is the list for the current piece
        size_t pids[2] = { static_cast<size_t>(0), static_cast<size_t>(piece + 1) };
        for (int i = 0; i < 2; i++)
        {
          size_t idx = pids[i];
          if (idx >= this->Internal->IDs.size())
          {
            continue;
          }
  
          vtkSelectionSourceInternals::IDSetType& selSet = this->Internal->IDs[idx];
  
          if (!selSet.empty())
          {
            // Create the selection list
            selectionList->SetNumberOfTuples(static_cast<vtkIdType>(selSet.size()));
            // iterate over ids and insert to the selection list
            vtkSelectionSourceInternals::IDSetType::iterator iter = selSet.begin();
            for (vtkIdType idx2 = 0; iter != selSet.end(); ++iter, ++idx2)
            {
              selectionList->SetValue(idx2, *iter);
            }
          }
        }
      }
    }
  
    if (this->ContentType == vtkSelectionNode::LOCATIONS)
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
      // Create the selection list
      vtkNew<vtkDoubleArray> selectionList;
      selectionList->SetNumberOfComponents(3);
      selectionList->SetNumberOfValues(static_cast<vtkIdType>(this->Internal->Locations.size()));
  
      std::vector<double>::iterator iter = this->Internal->Locations.begin();
      for (vtkIdType cc = 0; iter != this->Internal->Locations.end(); ++iter, ++cc)
      {
        selectionList->SetValue(cc, *iter);
      }
  
      output->SetSelectionList(selectionList);
    }
  
    if (this->ContentType == vtkSelectionNode::THRESHOLDS)
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
      oProperties->Set(vtkSelectionNode::COMPONENT_NUMBER(), this->ArrayComponent);
      // Create the selection list
      vtkNew<vtkDoubleArray> selectionList;
      selectionList->SetNumberOfComponents(2);
      selectionList->SetNumberOfValues(static_cast<vtkIdType>(this->Internal->Thresholds.size()));
  
      std::vector<double>::iterator iter = this->Internal->Thresholds.begin();
      for (vtkIdType cc = 0; iter != this->Internal->Thresholds.end(); ++iter, ++cc)
      {
        selectionList->SetTypedComponent(cc, 0, *iter);
        ++iter;
        selectionList->SetTypedComponent(cc, 1, *iter);
      }
  
      output->SetSelectionList(selectionList);
    }
  
    if (this->ContentType == vtkSelectionNode::FRUSTUM)
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
      // Create the selection list
      vtkNew<vtkDoubleArray> selectionList;
      selectionList->SetNumberOfComponents(4);
      selectionList->SetNumberOfTuples(8);
      for (vtkIdType cc = 0; cc < 32; cc++)
      {
        selectionList->SetValue(cc, this->Internal->Frustum[cc]);
      }
  
      output->SetSelectionList(selectionList);
    }
  
    if (this->ContentType == vtkSelectionNode::BLOCKS)
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
      vtkNew<vtkUnsignedIntArray> selectionList;
      selectionList->SetNumberOfComponents(1);
      selectionList->SetNumberOfTuples(static_cast<vtkIdType>(this->Internal->Blocks.size()));
      vtkSelectionSourceInternals::IDSetType::iterator iter;
      vtkIdType cc = 0;
      for (iter = this->Internal->Blocks.begin(); iter != this->Internal->Blocks.end(); ++iter, ++cc)
      {
        selectionList->SetValue(cc, *iter);
      }
      output->SetSelectionList(selectionList);
    }
  
    if (this->ContentType == vtkSelectionNode::QUERY)
    {
      oProperties->Set(vtkSelectionNode::CONTENT_TYPE(), this->ContentType);
      oProperties->Set(vtkSelectionNode::FIELD_TYPE(), this->FieldType);
      output->SetQueryString(this->QueryString);
    }
  
    if (this->ContentType == vtkSelectionNode::USER)
    {
      vtkErrorMacro("User-supplied, application-specific selections are not supported.");
      return 0;
    }
  
    oProperties->Set(vtkSelectionNode::CONTAINING_CELLS(), this->ContainingCells);
  
    oProperties->Set(vtkSelectionNode::INVERSE(), this->Inverse);
  
    if (output->GetSelectionList())
    {
      output->GetSelectionList()->SetName(this->ArrayName);
    }
    oProperties->Set(vtkSelectionNode::CONNECTED_LAYERS(), this->NumberOfLayers);
    return 1;
  }
  