# cee::ug::DataReader

class `DataReader` : public RefCountedObject

  The DataReader is an easy and efficient way to get data into the UnstructGridModel, leveraging the data management support of UnstructGridModel through the DataSourceReader.

  The DataReader is responsible for providing data to the DataSourceReader data source. After implementing the DataReader for your file format, you can just plug this custom reader into a DataSourceReader, set this as the data source for you UnstructGridModel. Then you can open an analysis, and use the DataSourceDirectory information to populate your UI. Then specify what to visualize in the ModelSpec as well as on cutting planes, isosurfaces, isovolumes and particle traces. UnstructGridModel will use the derived DataReader to load the geometry and results whenever needed. You only have to specify what to show, and the UnstructGridModel will do the data management.

  To create a reader, you have to implement the following methods:

  - isSupportedFileFormat(): Return true if the file provided is supported by your reader. This can be used by your app to auto detect the file format and use the right reader for the given file.
  - open(): Open the file and prepare to answer the other methods in this class. Do not read all the data!
  - close(): Close any open files. Prepare for a new open().
  - geometryCount(): Return the number of geometries you are going to provide (usually 1).
  - initializeDirectory(): Update the given DataSourceDirectory with all the metadata for your analysis. Here you provide information about all parts, data states and results.
  - readGeometry(): Read the specified geometry. This will only be called once unless you override hasNewGeometryForEachState() and return true for the given geometry.

  Example:

      class SingleTriangleReader : public cee::ug::DataReader
      {
      public:
          bool isSupportedFileFormat(const cee::Str& filename) { return true; }
          bool open(const cee::Str& filename, Error* error)    { return true; }
          void close()                                        { }
          size_t geometryCount() const                        { return 1; }

          bool initializeDirectory(cee::ug::DataSourceDirectory* directory, Error* error)
          {
              directory->setPartInfo(0, cee::ug::PartInfo(1, "First part"));
              directory->setStateInfo(cee::ug::StateInfo(1, "First state", 0.0));
              directory->setResultInfo(cee::ug::ResultInfo(SCALAR, 10, "Per node result", cee::ug::PER_NODE));

              return true;
          }

          bool readGeometry(int stateId, size_t geometryIndex, DataGeometry* geometry, Error* error)
          {
              cee::PtrRef<cee::ug::DataPart> part = new cee::ug::DataPart(1);
              cee::PtrRef<cee::ug::DataElements> elements = new cee::ug::DataElements(false, 0);
              cee::PtrRef<cee::ug::DataNodes> nodes = new cee::ug::DataNodes(false);
              part->setElements(elements.get());
              part->setNodes(nodes.get());
              nodes->resize(3);
              nodes->setNode(0, cee::Vec3d(0,0,0));
              nodes->setNode(1, cee::Vec3d(1,0,0));
              nodes->setNode(2, cee::Vec3d(1,1,0));

              std::vector<unsigned int> elementIndices;
              for (unsigned int i = 0; i < 3; ++i) elementIndices.push_back(i);
              elements->addElement(cee::ug::Element::TRIANGLES, elementIndices);

              geometry->addPart(part.get());

              return true;
          }

          bool readScalarResult(int stateId, size_t geometryIndex, int resultId, DataResultScalar* scalarResult, Error* error)
          {
              std::vector<double> values;
              for (size_t i = 0; i < 3; ++i) values.push_back(static_cast<double>(i));

              cee::PtrRef<cee::ug::DataPartScalar> part = new cee::ug::DataPartScalar;
              part->setValues(values);
              scalarResult->addPart(part.get());

              return true;
          }
      };

      cee::PtrRef<SingleTriangleReader> reader = new SingleTriangleReader;
      cee::PtrRef<cee::ug::DataSourceReader> dataSource = new cee::ug::DataSourceReader(1, reader.get());

      cee::PtrRef<cee::ug::UnstructGridModel> model = new cee::ug::UnstructGridModel;
      model->setDataSource(dataSource.get());

      dataSource->open("MyFile.xyz");

      std::vector<cee::ug::StateInfo>  stateInfos  = dataSource->directory()->stateInfos();
      model->modelSpec().setStateId(stateInfos[0].id());
      std::vector<cee::ug::ResultInfo> scalarInfo = dataSource->directory()->scalarResultInfos();
      model->modelSpec().setFringesResultId(scalarInfo[0].id());

      model->updateVisualization();

  See also

  DataSourceReader, DataSourceDirectory, and UnstructGridModel

  Public Functions

  `DataReader`()
  virtual bool `isSupportedFileFormat`(const Str &filename) = 0

    Returns true if the given file is supported by the reader.

    Note! This method must be overridden by all derived readers.

  virtual bool `open`(const Str &filename, Error *error) = 0

    Opens the given file and prepare to answer the initializeDirectory() method and then readGeometry() etc.

    Returns true if the file was successfully opened the reader is ready to provide data. Please note that you should usually not read all the data in this method, only check that the file is present and maybe do some initial reading.

    Note! This method must be overridden by all derived readers.

  virtual void `close`() = 0

    Supposed to close any of your open file(s) and prepare to open a new file.

    Note! This method must be overridden by all derived readers.

  virtual size_t `geometryCount`() const = 0

    Returns the number of geometries provided by this data reader.

    The normal case will be one geometry

    Note! This method must be overridden by all derived readers.

  virtual bool `initializeDirectory`(DataSourceDirectory *directory, Error *error) = 0

    Updates the directory with all the data provided by this reader.

    You must add info about all states, parts, scalars, vectors, displacements and transformation results. The reader will only be asked about data that is in the directory.

    Note! This method must be overridden by all derived readers.

    Example:

        bool initializeDirectory(cee::ug::DataSourceDirectory* directory, Error* error)
        {
            directory->setPartInfo(0, cee::ug::PartInfo(1, "First part"));
            directory->setStateInfo(cee::ug::StateInfo(1, "First state", 0.0));
            directory->setResultInfo(cee::ug::ResultInfo(cee::ug::SCALAR, 10, "Per node result", cee::ug::PER_NODE));
            directory->setResultInfo(cee::ug::ResultInfo(cee::ug::VECTOR, 10, "Per node result", cee::ug::PER_NODE));
            directory->setResultInfo(cee::ug::ResultInfo(cee::ug::DISPLACEMENT,10, "Displacement result", cee::ug::PER_NODE));
            directory->setTransformationResult(true);

            return true;
        }

  virtual bool `hasNewGeometryForEachState`(size_t globalGeometryIndex) const

    Supposed to return true if each state has a separate/different geometry.

    The default implementation returns false.

    Use this method to specify that one (or more) of your geometries change for each state. This is usually the case if the model is remeshed between each time step.

    If only the nodes change but not the topology of the geometry, you should use displacements results as this is much more efficient than re-specifying the whole geometry.

    See also

    readGeometry

  virtual bool `readGeometry`(int stateId, size_t geometryIndex, DataGeometry *geometry, Error *error) = 0

    Reads the geometry from the analysis and fill in the passed geometry.

    Use this method to provide the geometry (with all parts) for the given geometry index. If you have overridden the hasNewGeometryForEachState() method and returned true, you will get a call to this method for each new state that is loaded. If not, you will only once get a call to this method.

    Note! This method must be overridden by all derived readers.

    Advanced example: Two states, two geometries, one remeshed and one constant.

        bool readGeometry(int stateId, size_t geometryIndex, DataGeometry* geometry, Error* /*error*/)
        {
            cee::PtrRef<cee::ug::DataPart> part = new cee::ug::DataPart(1);
            cee::PtrRef<cee::ug::DataElements> elements = new cee::ug::DataElements(false, 0);
            cee::PtrRef<cee::ug::DataNodes> nodes = new cee::ug::DataNodes(false);
            part->setElements(elements.get());
            part->setNodes(nodes.get());

            if (geometryIndex == 0)
            {
                if (stateId == 1)
                {
                    nodes->resize(3);
                    nodes->setNode(0, cee::Vec3d(0,0,0));
                    nodes->setNode(1, cee::Vec3d(1,0,0));
                    nodes->setNode(2, cee::Vec3d(1,1,0));

                    std::vector<unsigned int> elementIndices;
                    for (unsigned int i = 0; i < 3; ++i) elementIndices.push_back(i);
                    elements->addElement(cee::ug::Element::TRIANGLES, elementIndices);
                }
                else
                {
                    nodes->resize(4);
                    nodes->setNode(0, cee::Vec3d(0,0,0));
                    nodes->setNode(1, cee::Vec3d(1,0,0));
                    nodes->setNode(2, cee::Vec3d(1,1,0));
                    nodes->setNode(3, cee::Vec3d(0,1,0));

                    std::vector<unsigned int> elementIndices;
                    for (unsigned int i = 0; i < 3; ++i) elementIndices.push_back(i);
                    elements->addElement(cee::ug::Element::TRIANGLES, elementIndices);

                    elementIndices[1] = 2;
                    elementIndices[2] = 3;
                    elements->addElement(cee::ug::Element::TRIANGLES, elementIndices);
                }
            }
            else
            {
                nodes->resize(4);
                nodes->setNode(0, cee::Vec3d(0,2,0));
                nodes->setNode(1, cee::Vec3d(1,2,0));
                nodes->setNode(2, cee::Vec3d(1,3,0));
                nodes->setNode(3, cee::Vec3d(1,2,0));

                std::vector<unsigned int> elementIndices;
                for (unsigned int i = 0; i < 4; ++i) elementIndices.push_back(i);
                elements->addElement(cee::ug::Element::QUADS, elementIndices);
            }

            geometry->addPart(part.get());

            return true;
        }

    See also

    DataGeometry and hasNewGeometryForEachState

  virtual bool `readScalarResult`(int stateId, size_t geometryIndex, int resultId, DataResultScalar *scalarResult, Error *error)

    Reads the specified scalar result from the analysis and populate the passed scalarResult.

    Use this method to provide the specified scalar result for the given geometry and at the given state. The result mapping provided must match the one specified for this result in initializeDirectory() and the number of result values must match the corresponding geometry.

    Advanced example matching the example in readGeometry() (Two states, two geometries, one remeshed and one constant):

        bool readScalarResult(int stateId, size_t geometryIndex, int resultId, DataResultScalar* scalarResult, Error* /*error*/)
        {
            if (resultId == 10)
            {
                std::vector<double> values;

                if (geometryIndex == 0)
                {
                    if (stateId == 1)
                    {
                        for (size_t i = 0; i < 3; ++i) values.push_back(static_cast<double>(stateId*100 + i));
                    }
                    else
                    {
                        for (size_t i = 0; i < 4; ++i) values.push_back(static_cast<double>(stateId*200 + i));
                    }
                }
                else
                {
                    for (size_t i = 0; i < 4; ++i) values.push_back(static_cast<double>(stateId*300 + i));
                }

                cee::PtrRef<cee::ug::DataPartScalar> part = new cee::ug::DataPartScalar;
                part->setValues(values);
                scalarResult->addPart(part.get());

                return true;
            }

            return false;
        }

    See also

    initializeDirectory() and DataResultScalar

  virtual bool `readVectorResult`(int stateId, size_t geometryIndex, int resultId, DataResultVector *vectorResult, Error *error)

    Reads the specified vector result from the analysis and populate the passed vectorResult.

    Use this method to provide the specified vector result for the given geometry and at the given state. The result mapping provided must match the one specified for this result in initializeDirectory() and the number of result values must match the corresponding geometry.

    See also

    DataResultVector and DataPartVector

  virtual bool `readDisplacementResult`(int stateId, size_t geometryIndex, int resultId, DataResultDisplacement *displacementResult, Error *error)

    Reads the specified displacement result from the analysis and populate the passed vectorResult.

    Use this method to provide the specified displacement result for the given geometry and at the given state. The number of results values must match the number of nodes in the corresponding geometry.

    Note! The values are the absolute node positions, not just the relative offset to the undisplaced node position.

    See also

    DataResultDisplacement and DataPartDisplacement

  virtual bool `readSymmetricTensorResult`(int stateId, size_t geometryIndex, int resultId, DataResultSymmetricTensor *symmetricTensorResult, Error *error)

    Reads the specified symmetric tensor result from the analysis and populate the passed symmetricTensorResult.

    Use this method to provide the specified symmetric tensor result for the given geometry and at the given state. The result mapping provided must match the one specified for this result in initializeDirectory() and the number of result values must match the corresponding geometry.

    See also

    DataResultSymmetricTensor and DataPartSymmetricTensor

  virtual bool `readTransformationResult`(int stateId, size_t geometryIndex, DataResultTransformation *transformationResult, Error *error)

    Reads the specified transformation result from the analysis and populate the passed transformationResult.

    Use this method to provide per part transformation matrices for the given geometry and state. The number of parts must match the corresponding geometry.

    This method will be called if DataSourceDirectory::setTransformationResult(true) is done in initializeDirectory().

    See also

    initializeDirectory(), DataResultTransformation, and Mat4d

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Envision for Desktop in your own language, or choose a sample question below to start a conversation:

What is HOOPS Envision for Desktop?
What are the latest release notes for HOOPS Envision for Desktop?
How do I start evaluating HOOPS Envision for Desktop?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...