Improve the API of ::fwData::Mesh
Depends on #68 (closed)
Refactoring Mesh
Existing
What we want to change?
We don't want to use helpers to access the data.
The buffers are accessible by helpers but the allocation is in the data.
There is too much variables to set to inialize a mesh
// allocate memory
mesh->allocate(nbPoint, nbCell, 3*nbCells);
// define number of points and cells
mesh->setNumberOfPoints(nbPoint);
mesh->setNumberOfCells(nbCell);
// just because a mesh can mix every type of cells (POINT, EDGE, TRIANGLE, ...)
mesh->setCellDataSize(3*nbCells);
// to realocate memory according of the number of points and cells
mesh->adjustAllocatedMemory();
// allocate colors, normals, ....
mesh->allocatePointNormals();
mesh->allocatePointColors(RGB);
// ...
There is too much arrays in a Mesh
There is 3 arrays to define de cell association:
- cellTypes: the type of the cell (POINT, EDGE, TRIANGLE, QUAD, TETRA)
- cellData: contains indices related to the vertices
- cellDataOffsets: contains indices related to a cell in cellData. It is used to parse cellData.
It will be very very easier to forbid to mix different types of cells in the same mesh.
The arrays dimensions can be created by two ways
- size:
vector<size_t>
- number of components
The two ways can be mixted, but the buffer is a monoblock and we must know how to go through it.
Information are missing in the ::fwData::Image
- 3D images usually uses 1 components of int16
- 2D images usually uses 3 components of uint8 with 3 or 4 components, or uint16 with 1 components
For colored 2D images, we always convert it to RGB(A), but there may be a lot of conversion. We need to add the pixel format information (also in the FrameTL).
What we don't want to change ?
Dump
The buffer can be automatically saved/load on the disk to release the memory
Serialization
We don't want to loose all our serialozed data (jsonz, apz, ...) We must be able to create a patch to convert the all data.
Proposal
- Deprecate helpers
- Hide the ::fwData::Array
- Rename
allocate
methods toresize
- Remove
vector<size_t>
in Image and use astd::array<size_t, 3>
- Get iterators on buffer (struct that contains a pointer on a buffer position, prevent overflow)
Don't forget to check on each access that the array in locked for dump.
Can we use ::fwData::ObjectLock
?
Mesh
New API
public:
typedef enum
{
NONE = (1 << 0),
POINT_COLORS = (1 << 1),
POINT_NORMALS = (1 << 2),
POINT_TEX_COORDS = (1 << 3),
CELL_COLORS = (1 << 4),
CELL_NORMALS = (1 << 5),
CELL_TEX_COORDS = (1 << 6)
} ArraysEnum;
/// allocate the memory of all the arrays, but don't change the number of points and cells,
/// uses a mask to define the extra arrays to resize (POINT_NORMALS|POINT_COLORS|CELL_COLORS).
size_t reserve(size_t nbPts, size_t nbCells, CellTypesEnum celltype, ArraysEnum arrays=NONE);
size_t reserve(size_t nbPts, size_t nbTriangleCells, size_t nbQuadCells, ArraysEnum arrays=NONE);
/// reserve memory if necessary and set the number of points and cells,
///uses a mask to define the extra information arrays to resize (Point colors, Cell Colors, ...).
/// It should be possible to call this method to allocate an array (ie. normals) even if the mesh is already allocated
/// (if the reserved size is greater than the given one, it only change the number of points and number of cells )
size_t resize(size_t nbPts, size_t nbCells, CellTypesEnum celltype, ArraysEnum arrays=NONE);
size_t resize(size_t nbPts, size_t nbTriangleCells, size_t nbQuadCells, ArraysEnum arrays=NONE);
// clear points and cells
void clear();
// getnumber of points and cells
Id getNumberOfPoints() const;
Id getNumberOfCells() const;
// push point and cell
Id pushPoint(const PointValueType p[3]);
Id pushPoint(PointValueType x,
PointValueType y,
PointValueType z);
Id pushCell(Id idPt);
Id pushCell(Id idP1, Id idP2);
Id pushCell(Id idP1, Id idP2, Id idP3);
Id pushCell(Id idP1, Id idP2, Id idP3, Id idP4, CellTypesEnum type = QUAD);
Id pushCell(CellTypesEnum type,
const std::vector<CellValueType> pointIds);
Id pushCell(CellTypesEnum type,
const CellValueType* pointIds,
size_t nbPoints );
// ...
// getter/setter for one value
void setPoint(Id id, const PointValueType p[3]);
const PointIterator getPoint(Id id) const;
void setPointColor(Id id, const ColorValueType c[4]);
//...
/// Get the mesh data size in bytes.
size_t getDataSizeInBytes() const;
///Get the amount of memory allocated in this mesh. Mey be bigger than getDataSizeInBytes().
size_t getAllocatedSizeInBytes() const;
/// get the raw buffer data
const float* getPoints() const;
float* getPoints();
const Id* getCells(CellTypesEnum type) const; ///< get all the cells of a type
Id* getCells(CellTypesEnum type) ; ///< get all the cells of a type
private:
Id m_nbPoints;
std::map<CellTypesEnum, Id> nbCells;
::fwData::Array::sptr m_points;
::fwData::Array::sptr m_pointColors;
::fwData::Array::sptr m_pointNormals;
::fwData::Array::sptr m_pointTexCoords;
std::map<CellTypesEnum, ::fwData::Array::sptr> m_cells;
How to create a mesh
::fwData::Mesh::sptr mesh = ::fwData::Mesh::New();
// allocate memory
mesh->reserve(nbPoints, nbCells, TRIANGLE, POINT_COLORS | POINT_NORMALS);
mesh->pushPoint(12.f 10.f, 0.1f);
mesh->pushPoint(22.f 0.f, 0.8f);
mesh->pushPoint(0.f 0.f, 0.f);
mesh->pushCell(0, 1, 2);
//...
How to parse the mesh ?
Create an iterator on points(increments by 3 on a ++it
). Assert on buffer overflow.
::fwData::Mesh::sptr mesh = this->getInput< ::fwData::Mesh >("mesh");
PointRGBANormalIterator points = mesh->getPointsBegin();
PointRGBANormalIterator pointsEnd = mesh->getPointsEnd();
for (; points!= pointsEnd; ++points)
{
float p[3];
p[0] = points.p[0];
p[1] = points.p[1];
p[2] = points.p[2];
float n[3];
n[0] = points.n[0];
n[1] = points.n[1];
n[2] = points.n[2];
uint8_t c[4];
c[0] = points.c[0];
c[1] = points.c[1];
c[2] = points.c[2];
c[3] = points.c[3];
//...
}
CellIterator cells = mesh->getCellsBegin();
CellIterator cellsEnd = mesh->getCellsEnd();
for(; cells != cellsEnd; ++cells)
{
uint64_t cell[3];
cell[0] = cells[0];
cell[1] = cells[1];
cell[2] = cells[2];
//...
}
Iterator like:
class PointRGBANormalIterator
{
public:
PointIterator(Mesh* m) : mesh(m)
{
p = m_mesh->getPointsArray()->begin<float*>();
n = m_mesh->getPointNormalsArray()->begin<float*>();
c = m_mesh->getPointColorsArray()->begin<uint8_t*>();
}
PointIterator(const PointIterator& mit):
p(mit.p), n(mit.n), c(mit.c), m_idx(mit.m_idx), m_mesh(mit.m_idx)
{}
PointIterator& operator++()
{
++idx;
assert(m_idx < m_mesh->getNumberOfPoints());
p+=3;
n+=3;
c+=4;
return *this;
}
PointIterator operator++(int)
{
PointIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const PointIterator& rhs) const
{
return p==rhs.p && n==rhs.n && c==rhs.c;
}
bool operator!=(const PointIterator& rhs) const
{
return p!=rhs.p || n!=rhs.n || c!=rhs.c;
}
float* p;
float* n;
float* c;
private:
size_t m_idx;
Mesh m_mesh;
}
Array
- Remove the components.
Image
- Add the pixel format information (RGB, RGBA, BGR, BGRA, L)
- Add iterator for the different formats
- Prevent to use more than 3 dimensions
- Hide the ::fwData::Array