Skip to content

(Mesh): improve the API of ::fwData::Mesh

Emilie WERNERT requested to merge 66-improve-the-api-of-fwdata-mesh into dev

What does this MR do?

Refactor the mesh API:

  • deprecate the access to the points, cells and other arrays
  • rename allocate method to reserve
    • allow to allocate the color, normal and texture arrays in the same reserve method
  • add resize method to allocate the memory and set the number of points and cells
  • add iterator to iterate through the points and cells

Allocation:
The two methods reserve() and resize() allow to allocate the mesh arrays. The difference between the two methods is that resize modify the number of points and cells.

  • pushPoint() and pushCell() methods allow to add new points or cells, it increments the number of points and allocate the memory if needed.
  • setPoint() and setCell() methods allow to change the value in a given index.

Example with resize(), setPoint() and setCell():

    ::fwData::Mesh::sptr mesh = ::fwData::Mesh::New();

    mesh->resize(NB_POINTS, NB_CELLS, CELL_TYPE, EXTRA_ARRAY);
    const auto lock = mesh->lock();

    for (size_t i = 0; i < NB_POINTS; ++i)
    {
        const std::uint8_t val                               = static_cast<uint8_t>(i);
        const ::fwData::Mesh::ColorValueType color[4]        = {val, val, val, val};
        const float floatVal                                 = static_cast<float>(i);
        const ::fwData::Mesh::NormalValueType normal[3]      = {floatVal, floatVal, floatVal};
        const ::fwData::Mesh::TexCoordValueType texCoords[2] = {floatVal, floatVal};
        const size_t value                                   = 3*i;
        mesh->setPoint(i, static_cast<float>(value), static_cast<float>(value+1), static_cast<float>(value+2));
        mesh->setPointColor(i, color);
        mesh->setPointNormal(i, normal);
        mesh->setPointTexCoord(i, texCoords);
    }

    for (size_t i = 0; i < NB_CELLS; ++i)
    {
        mesh->setCell(i, i, i+1, i+2);

        const ::fwData::Mesh::ColorValueType val             = static_cast< ::fwData::Mesh::ColorValueType >(i);
        const ::fwData::Mesh::ColorValueType color[4]        = {val, val, val, val};
        const float floatVal                                 = static_cast<float>(i);
        const ::fwData::Mesh::NormalValueType normal[3]      = {floatVal, floatVal, floatVal};
        const ::fwData::Mesh::TexCoordValueType texCoords[2] = {floatVal, floatVal};
        mesh->setCellColor(i, color);
        mesh->setCellNormal(i, normal);
        mesh->setCellTexCoord(i, texCoords);
    }

Example with reseve(), pushPoint() and pushCell()

    ::fwData::Mesh::sptr mesh = ::fwData::Mesh::New();

    mesh->reserve(NB_POINTS, NB_CELLS, CELL_TYPE, EXTRA_ARRAY);
    const auto lock = mesh->lock();

    for (size_t i = 0; i < NB_POINTS; ++i)
    {
        const std::uint8_t val                               = static_cast<uint8_t>(i);
        const ::fwData::Mesh::ColorValueType color[4]        = {val, val, val, val};
        const float floatVal                                 = static_cast<float>(i);
        const ::fwData::Mesh::NormalValueType normal[3]      = {floatVal, floatVal, floatVal};
        const ::fwData::Mesh::TexCoordValueType texCoords[2] = {floatVal, floatVal};
        const size_t value                                   = 3*i;
        const auto id =
            mesh->pushPoint(static_cast<float>(value), static_cast<float>(value+1), static_cast<float>(value+2));
        mesh->setPointColor(id, color);
        mesh->setPointNormal(id, normal);
        mesh->setPointTexCoord(id, texCoords);
    }

    for (size_t i = 0; i < NB_CELLS; ++i)
    {
        const auto id = mesh->pushCell(i, i+1, i+2);

        const ::fwData::Mesh::ColorValueType val             = static_cast< ::fwData::Mesh::ColorValueType >(i);
        const ::fwData::Mesh::ColorValueType color[4]        = {val, val, val, val};
        const float floatVal                                 = static_cast<float>(i);
        const ::fwData::Mesh::NormalValueType normal[3]      = {floatVal, floatVal, floatVal};
        const ::fwData::Mesh::TexCoordValueType texCoords[2] = {floatVal, floatVal};
        mesh->setCellColor(id, color);
        mesh->setCellNormal(id, normal);
        mesh->setCellTexCoord(id, texCoords);
    }

Iterators

To access the mesh points and cells, you should uses the following iterators:

  • ::fwData::iterator::PointIterator: to iterate through mesh points
  • ::fwData::iterator::ConstPointIterator: to iterate through mesh points read-only
  • ::fwData::iterator::CellIterator: to iterate through mesh cells
  • ::fwData::iterator::ConstCellIterator: to iterate through mesh cells read-only

Example to iterate through points:

    ::fwData::Mesh::sptr mesh = ::fwData::Mesh::New();
    mesh->resize(25, 33, ::fwData::Mesh::TRIANGLE);
    auto iter    = mesh->begin< ::fwData::iterator::PointIterator >();
    const auto iterEnd = mesh->end< ::fwData::iterator::PointIterator >();
    float p[3] = {12.f, 16.f, 18.f};

   for (; iter != iterEnd; ++iter)
   {
       iter->point->x = p[0];
       iter->point->y = p[1];
       iter->point->z = p[2];
   }

Example to iterate through cells:

    ::fwData::Mesh::sptr mesh = ::fwData::Mesh::New();
    mesh->resize(25, 33, ::fwData::Mesh::TRIANGLE);
    auto iter         = mesh->begin< ::fwData::iterator::ConstCellIterator >();
    const auto endItr = mesh->end< ::fwData::iterator::ConstCellIterator >();

    auto itrPt = mesh->begin< ::fwData::iterator::ConstPointIterator >();
    float p[3];

    for(; iter != endItr; ++iter)
    {
        const auto nbPoints = iter->nbPoints;

        for(size_t i = 0 ; i < nbPoints ; ++i)
        {
            auto pIdx = static_cast< ::fwData::iterator::ConstCellIterator::difference_type >(iter->pointIdx[i]);

            ::fwData::iterator::ConstPointIterator pointItr(itrPt + pIdx);
            p[0] = pointItr->point->x;
            p[1] = pointItr->point->y;
            p[2] = pointItr->point->z;
        }
    }

pushCell() and setCell() may not be very efficient, you can use CellIterator to define the cell. But take care to properly define all the cell attribute.

Example of defining cells usign iterators

    ::fwData::Mesh::sptr mesh = ::fwData::Mesh::New();
    mesh->resize(25, 33, ::fwData::Mesh::QUAD);
    auto it          = mesh->begin< ::fwData::iterator::CellIterator >();
    const auto itEnd = mesh->end< ::fwData::iterator::CellIterator >();

    const auto cellType = ::fwData::Mesh::QUAD;
    const size_t nbPointPerCell = 4;

    size_t count = 0;
    for (; it != itEnd; ++it)
    {
        // define the cell type and cell offset
        (*it->type)   = cellType;
        (*it->offset) = nbPointPerCell*count;

        // /!\ define the next offset to be able to iterate through point indices
        if (it != itEnd-1)
        {
            (*(it+1)->offset) = nbPointPerCell*(count+1);
        }

        // define the point indices
        for (size_t i = 0; i < 4; ++i)
        {
            ::fwData::Mesh::CellValueType ptIdx = val;
            it->pointIdx[i] = ptIdx;
        }
    }

How to test it?

Launch the unit tests and some applications

Some results

nbPoints: 100002
nbCells: 100000 Triangles

Point iterator Cell iterator const cell iterator
Linux(Debug) 1.2ms 59.8ms 60.3333ms
Linux(Release) 0.666667ms 59ms 59.8667ms

Associated Issues/Merge Requests

Edited by Emilie WERNERT

Merge request reports