diff --git a/Modules/Core/Common/include/itkCommonEnums.h b/Modules/Core/Common/include/itkCommonEnums.h index fc40b146849..00dcc7bf024 100644 --- a/Modules/Core/Common/include/itkCommonEnums.h +++ b/Modules/Core/Common/include/itkCommonEnums.h @@ -147,6 +147,7 @@ class CommonEnums QUADRATIC_EDGE_CELL = 7, QUADRATIC_TRIANGLE_CELL = 8, LAST_ITK_CELL = 9, + POLYLINE_CELL = 10, MAX_ITK_CELLS = 255 }; diff --git a/Modules/Core/Common/include/itkPolyLineCell.h b/Modules/Core/Common/include/itkPolyLineCell.h new file mode 100644 index 00000000000..b5c3f1bafe3 --- /dev/null +++ b/Modules/Core/Common/include/itkPolyLineCell.h @@ -0,0 +1,139 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef itkPolyLineCell_h +#define itkPolyLineCell_h + +#include "itkVertexCell.h" +namespace itk +{ +/** \class PolyLineCell + * \brief Represents a series of connected line segments for a Mesh. + * + * PolyLineCell represents a series of connected line segments for a Mesh. + * + * Template parameters for PolyLineCell: + * + * \tparam TPixelType The type associated with a point, cell, or boundary + * for use in storing its data. + * + * \tparam TCellTraits Type information of mesh containing cell. + * + * \ingroup MeshObjects + * \ingroup ITKCommon + */ + +template +class ITK_TEMPLATE_EXPORT PolyLineCell : public TCellInterface +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(PolyLineCell); + + /** Standard class type aliases. */ + itkCellCommonTypedefs(PolyLineCell); + itkCellInheritedTypedefs(TCellInterface); + + /** Standard part of every itk Object. */ + itkTypeMacro(PolyLineCell, CellInterface); + + /** The type of boundary for this lines's vertices. */ + using VertexType = VertexCell; + using VertexAutoPointer = typename VertexType::SelfAutoPointer; + + /** Line-specific topology numbers. */ + static constexpr unsigned int CellDimension = 1; + + /** Implement the standard CellInterface. */ + CellGeometryEnum + GetType() const override + { + return CellGeometryEnum::POLYLINE_CELL; + } + void + MakeCopy(CellAutoPointer &) const override; + + unsigned int + GetDimension() const override; + + unsigned int + GetNumberOfPoints() const override; + + CellFeatureCount + GetNumberOfBoundaryFeatures(int dimension) const override; + + bool + GetBoundaryFeature(int dimension, CellFeatureIdentifier, CellAutoPointer &) override; + + void + ClearPoints(); + + void + SetPointIds(PointIdConstIterator first) override; + + void + SetPointIds(PointIdConstIterator first, PointIdConstIterator last) override; + + void + SetPointIds(int dummy, int num, PointIdConstIterator first); + + void + SetPointId(int localId, PointIdentifier) override; + PointIdIterator + PointIdsBegin() override; + + PointIdConstIterator + PointIdsBegin() const override; + + PointIdIterator + PointIdsEnd() override; + + PointIdConstIterator + PointIdsEnd() const override; + + /** Line-specific interface. */ + virtual CellFeatureCount + GetNumberOfVertices() const; + + virtual bool + GetVertex(CellFeatureIdentifier, VertexAutoPointer &); + + /** Visitor interface */ + itkCellVisitMacro(CellGeometryEnum::LINE_CELL); + + /** Constructor and destructor */ + PolyLineCell() = default; + PolyLineCell(PointIdentifier NumberOfPoints) + { + for (PointIdentifier i = 0; i < NumberOfPoints; ++i) + { + m_PointIds.push_back(NumericTraits::max()); + } + } + + ~PolyLineCell() override = default; + +protected: + /** For storing the points needed for a line segment. */ + std::vector m_PointIds; +}; +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkPolyLineCell.hxx" +#endif + +#endif diff --git a/Modules/Core/Common/include/itkPolyLineCell.hxx b/Modules/Core/Common/include/itkPolyLineCell.hxx new file mode 100644 index 00000000000..32c05075220 --- /dev/null +++ b/Modules/Core/Common/include/itkPolyLineCell.hxx @@ -0,0 +1,277 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef itkPolyLineCell_hxx +#define itkPolyLineCell_hxx + +namespace itk +{ +/** + * Standard CellInterface: + */ +template +void +PolyLineCell::MakeCopy(CellAutoPointer & cellPointer) const +{ + auto * newPolylineCell = new Self; + + cellPointer.TakeOwnership(newPolylineCell); + const PointIdentifier numberOfPoints = this->GetNumberOfPoints(); + if (numberOfPoints) + { + newPolylineCell->SetPointIds(0, numberOfPoints, this->GetPointIds()); + } + else + { + newPolylineCell->ClearPoints(); + } +} + +/** + * Standard CellInterface: + * Get the topological dimension of this cell. + */ +template +unsigned int +PolyLineCell::GetDimension() const +{ + return Self::CellDimension; +} + +/** + * Standard CellInterface: + * Get the number of points present in the cell. + */ +template +unsigned int +PolyLineCell::GetNumberOfPoints() const +{ + return static_cast(m_PointIds.size()); +} + +/** + * Standard CellInterface: + * Get the number of boundary entities of the given dimension. + */ +template +auto +PolyLineCell::GetNumberOfBoundaryFeatures(int dimension) const -> CellFeatureCount +{ + switch (dimension) + { + case 0: + return GetNumberOfVertices(); + default: + return 0; + } +} + +/** + * Standard CellInterface: + * Get the boundary feature of the given dimension specified by the given + * cell feature Id. + * The Id can range from 0 to GetNumberOfBoundaryFeatures(dimension)-1. + */ +template +bool +PolyLineCell::GetBoundaryFeature(int dimension, + CellFeatureIdentifier featureId, + CellAutoPointer & cellPointer) +{ + VertexAutoPointer vertexPointer; + if ((dimension == 0) && this->GetVertex(featureId, vertexPointer)) + { + TransferAutoPointer(cellPointer, vertexPointer); + return true; + } + // else + cellPointer.Reset(); + return false; +} + +/** + * Standard CellInterface: + * Set the point id list used by the cell. It is assumed that the given + * iterator can be incremented and safely de-referenced enough times to + * get all the point ids needed by the cell. + */ +template +void +PolyLineCell::SetPointIds(PointIdConstIterator first) +{ + PointIdConstIterator ii(first); + + for (unsigned int i = 0; i < m_PointIds.size(); ++i) + { + m_PointIds[i] = *ii++; + } +} + +/** + * Standard CellInterface: + * Set the point id list used by the cell. It is assumed that the given + * iterator can be incremented and safely de-referenced enough times to + * get all the point ids needed by the cell. + */ +template +void +PolyLineCell::SetPointIds(int itkNotUsed(dummy), int num, PointIdConstIterator first) +{ + PointIdConstIterator ii(first); + + m_PointIds.clear(); + for (int i = 0; i < num; ++i) + { + m_PointIds.push_back(*ii++); + } +} + +/** + * Standard CellInterface: + * Set the point id list used by the cell. It is assumed that the range + * of iterators [first, last) contains the correct number of points needed to + * define the cell. The position *last is NOT dereferenced, so it can safely + * be one beyond the end of an array or other container. + */ +template +void +PolyLineCell::SetPointIds(PointIdConstIterator first, PointIdConstIterator last) +{ + PointIdConstIterator ii(first); + + m_PointIds.clear(); + while (ii != last) + { + m_PointIds.push_back(*ii++); + } +} + +/** + * Standard CellInterface: + * Set an individual point identifier in the cell. + */ +template +void +PolyLineCell::SetPointId(int localId, PointIdentifier ptId) +{ + if (m_PointIds.size() < static_cast(localId + 1)) + { + m_PointIds.resize(localId + 1); + } + m_PointIds[localId] = ptId; +} + +/** + * Standard CellInterface: + * Get a begin iterator to the list of point identifiers used by the cell. + */ +template +auto +PolyLineCell::PointIdsBegin() -> PointIdIterator +{ + return &m_PointIds[0]; +} + +/** + * Standard CellInterface: + * Get a const begin iterator to the list of point identifiers used + * by the cell. + */ +template +auto +PolyLineCell::PointIdsBegin() const -> PointIdConstIterator +{ + return &m_PointIds[0]; +} + +/** + * Standard CellInterface: + * Get an end iterator to the list of point identifiers used by the cell. + */ +template +auto +PolyLineCell::PointIdsEnd() -> PointIdIterator +{ + if (!m_PointIds.empty()) + { + return &m_PointIds.back() + 1; + } + else + { + return nullptr; + } +} + +/** + * Standard CellInterface: + * Get a const end iterator to the list of point identifiers used + * by the cell. + */ +template +auto +PolyLineCell::PointIdsEnd() const -> PointIdConstIterator +{ + if (!m_PointIds.empty()) + { + return &m_PointIds.back() + 1; + } + else + { + return nullptr; + } +} + +/** + * clear all the points in the cell. + */ +template +void +PolyLineCell::ClearPoints() +{ + m_PointIds.clear(); +} + + +/** + * Line-specific: + * Get the number of vertices for this polyline cell. + */ +template +auto +PolyLineCell::GetNumberOfVertices() const -> CellFeatureCount +{ + return static_cast(m_PointIds.size()); +} + +/** + * Line-specific: + * Get the vertex specified by the given cell feature Id. + * The Id can range from 0 to GetNumberOfVertices()-1. + */ +template +bool +PolyLineCell::GetVertex(CellFeatureIdentifier vertexId, VertexAutoPointer & vertexPointer) +{ + auto * vert = new VertexType; + + vert->SetPointId(0, m_PointIds[vertexId]); + vertexPointer.TakeOwnership(vert); + return true; +} +} // end namespace itk + +#endif diff --git a/Modules/Core/Common/src/itkCommonEnums.cxx b/Modules/Core/Common/src/itkCommonEnums.cxx index 69f93de132d..efcb61c2600 100644 --- a/Modules/Core/Common/src/itkCommonEnums.cxx +++ b/Modules/Core/Common/src/itkCommonEnums.cxx @@ -175,6 +175,8 @@ operator<<(std::ostream & out, const CommonEnums::CellGeometry value) return "itk::CommonEnums::CellGeometry::VERTEX_CELL"; case CommonEnums::CellGeometry::LINE_CELL: return "itk::CommonEnums::CellGeometry::LINE_CELL"; + case CommonEnums::CellGeometry::POLYLINE_CELL: + return "itk::CommonEnums::CellGeometry::POLYLINE_CELL"; case CommonEnums::CellGeometry::TRIANGLE_CELL: return "itk::CommonEnums::CellGeometry::TRIANGLE_CELL"; case CommonEnums::CellGeometry::QUADRILATERAL_CELL: diff --git a/Modules/Core/Common/test/itkLoggerTest.cxx b/Modules/Core/Common/test/itkLoggerTest.cxx index c77671793ee..bed0db4cd1b 100644 --- a/Modules/Core/Common/test/itkLoggerTest.cxx +++ b/Modules/Core/Common/test/itkLoggerTest.cxx @@ -204,7 +204,8 @@ itkLoggerTest(int argc, char * argv[]) itk::CellGeometryEnum::TRIANGLE_CELL, itk::CellGeometryEnum::QUADRILATERAL_CELL, itk::CellGeometryEnum::POLYGON_CELL, itk::CellGeometryEnum::TETRAHEDRON_CELL, itk::CellGeometryEnum::HEXAHEDRON_CELL, itk::CellGeometryEnum::QUADRATIC_TRIANGLE_CELL, - itk::CellGeometryEnum::LAST_ITK_CELL, itk::CellGeometryEnum::MAX_ITK_CELLS + itk::CellGeometryEnum::LAST_ITK_CELL, itk::CellGeometryEnum::POLYLINE_CELL, + itk::CellGeometryEnum::MAX_ITK_CELLS }; for (const auto & ee : allCellGeometryEnum) { diff --git a/Modules/Core/Mesh/include/itkMesh.h b/Modules/Core/Mesh/include/itkMesh.h index ae35900e4d2..f0a963b60a2 100644 --- a/Modules/Core/Mesh/include/itkMesh.h +++ b/Modules/Core/Mesh/include/itkMesh.h @@ -41,6 +41,7 @@ #include "itkVectorContainer.h" #include "itkVertexCell.h" #include "itkLineCell.h" +#include "itkPolyLineCell.h" #include "itkTriangleCell.h" #include "itkQuadrilateralCell.h" #include "itkPolygonCell.h" @@ -217,6 +218,7 @@ class ITK_TEMPLATE_EXPORT Mesh : public PointSet; using OutputVertexCellType = itk::VertexCell; using OutputLineCellType = itk::LineCell; + using OutputPolyLineCellType = itk::PolyLineCell; using OutputTriangleCellType = itk::TriangleCell; using OutputQuadrilateralCellType = itk::QuadrilateralCell; using OutputPolygonCellType = itk::PolygonCell; diff --git a/Modules/Core/Mesh/include/itkMesh.hxx b/Modules/Core/Mesh/include/itkMesh.hxx index a81eb1735d9..84e03ef363c 100644 --- a/Modules/Core/Mesh/include/itkMesh.hxx +++ b/Modules/Core/Mesh/include/itkMesh.hxx @@ -146,6 +146,9 @@ Mesh::CreateCell(int cellType, CellAutoPoin case CellGeometryEnum::LINE_CELL: cellPointer.TakeOwnership(new OutputLineCellType); break; + case CellGeometryEnum::POLYLINE_CELL: + cellPointer.TakeOwnership(new OutputPolyLineCellType); + break; case CellGeometryEnum::TRIANGLE_CELL: cellPointer.TakeOwnership(new OutputTriangleCellType); break; diff --git a/Modules/Core/Mesh/test/itkCellInterfaceTest.cxx b/Modules/Core/Mesh/test/itkCellInterfaceTest.cxx index 848a531697b..ab311b75d5a 100644 --- a/Modules/Core/Mesh/test/itkCellInterfaceTest.cxx +++ b/Modules/Core/Mesh/test/itkCellInterfaceTest.cxx @@ -19,6 +19,7 @@ #include #include "itkMesh.h" +#include "itkPolyLineCell.h" #include "itkHexahedronCell.h" #include "itkTetrahedronCell.h" #include "itkQuadraticTriangleCell.h" @@ -157,6 +158,20 @@ itkCellInterfaceTest(int, char *[]) return EXIT_FAILURE; } + using PolyLineCellType = itk::PolyLineCell; + status = TestCellInterface("PolyLine", new PolyLineCellType); + if (status != 0) + { + return EXIT_FAILURE; + } + + using PolyLineCellType = itk::PolyLineCell; + status = TestCellInterface("PolyLineCellType with 7 vertices", new PolyLineCellType(7)); + if (status != 0) + { + return EXIT_FAILURE; + } + using TriangleCellType = itk::TriangleCell; status = TestCellInterface("Triangle", new TriangleCellType); if (status != 0) diff --git a/Modules/Core/Mesh/test/itkMeshTest.cxx b/Modules/Core/Mesh/test/itkMeshTest.cxx index 114ec0ef44d..e8491f6db70 100644 --- a/Modules/Core/Mesh/test/itkMeshTest.cxx +++ b/Modules/Core/Mesh/test/itkMeshTest.cxx @@ -18,6 +18,7 @@ #include "itkMesh.h" #include "itkTetrahedronCell.h" +#include "itkPolyLineCell.h" #include "itkHexahedronCell.h" #include "itkQuadraticTriangleCell.h" #include "itkFileOutputWindow.h" @@ -48,6 +49,7 @@ using CellTraits = MeshType::CellTraits; */ using CellInterfaceType = itk::CellInterface; using LineCellType = itk::LineCell; +using PolyLineCellType = itk::PolyLineCell; using TetraCellType = itk::TetrahedronCell; using HexaCellType = itk::HexahedronCell; using QuadraticEdgeCellType = itk::QuadraticEdgeCell; @@ -197,8 +199,8 @@ itkMeshTest(int, char *[]) { itk::CellGeometryEnum::TETRAHEDRON_CELL, 4 }, { itk::CellGeometryEnum::HEXAHEDRON_CELL, 8 }, { itk::CellGeometryEnum::QUADRATIC_EDGE_CELL, 3 }, - { itk::CellGeometryEnum::QUADRATIC_TRIANGLE_CELL, - 6 } }; + { itk::CellGeometryEnum::QUADRATIC_TRIANGLE_CELL, 6 }, + { itk::CellGeometryEnum::POLYLINE_CELL, 5 } }; // Insert cell of each kind auto cellVectorContainer = MeshType::CellsVectorContainer::New(); diff --git a/Modules/IO/MeshBase/include/itkMeshFileReader.h b/Modules/IO/MeshBase/include/itkMeshFileReader.h index 0cbbd2f6b1b..5b18132e50f 100644 --- a/Modules/IO/MeshBase/include/itkMeshFileReader.h +++ b/Modules/IO/MeshBase/include/itkMeshFileReader.h @@ -22,6 +22,7 @@ #include "itkMacro.h" #include "itkHexahedronCell.h" #include "itkLineCell.h" +#include "itkPolyLineCell.h" #include "itkMeshIOBase.h" #include "itkMeshSource.h" #include "itkPolygonCell.h" @@ -108,6 +109,7 @@ class ITK_TEMPLATE_EXPORT MeshFileReader : public MeshSource using OutputVertexCellType = VertexCell; using OutputLineCellType = LineCell; + using OutputPolyLineCellType = PolyLineCell; using OutputTriangleCellType = TriangleCell; using OutputPolygonCellType = PolygonCell; using OutputTetrahedronCellType = TetrahedronCell; diff --git a/Modules/IO/MeshBase/include/itkMeshFileReader.hxx b/Modules/IO/MeshBase/include/itkMeshFileReader.hxx index 6e69b62aa3d..9467b22ff6a 100644 --- a/Modules/IO/MeshBase/include/itkMeshFileReader.hxx +++ b/Modules/IO/MeshBase/include/itkMeshFileReader.hxx @@ -168,6 +168,26 @@ MeshFileReader::Re } break; } + case CellGeometryEnum::POLYLINE_CELL: + { + auto numberOfPoints = static_cast(buffer[index++]); + if (numberOfPoints < 2) + { + itkExceptionMacro(<< "Invalid Line Cell with number of points = " << numberOfPoints); + } + auto * polyLineCell = new OutputPolyLineCellType; + OutputCellAutoPointer cell; + + for (unsigned int jj = 0; jj < numberOfPoints; ++jj) + { + auto pointIDBuffer = static_cast(buffer[index++]); + polyLineCell->SetPointId(jj, pointIDBuffer); + } + + cell.TakeOwnership(polyLineCell); + output->SetCell(id++, cell); + break; + } case CellGeometryEnum::TRIANGLE_CELL: { auto numberOfPoints = static_cast(buffer[index++]); diff --git a/Modules/IO/MeshBase/include/itkMeshFileTestHelper.h b/Modules/IO/MeshBase/include/itkMeshFileTestHelper.h index a8f403ec83d..f181c666e74 100644 --- a/Modules/IO/MeshBase/include/itkMeshFileTestHelper.h +++ b/Modules/IO/MeshBase/include/itkMeshFileTestHelper.h @@ -39,7 +39,7 @@ TestPointsContainer(typename TMesh::PointsContainerPointer points0, typename TMe { if (points0->Size() != points1->Size()) { - std::cerr << "Input mesh and output mesh have different number of cells!" << std::endl; + std::cerr << "Input mesh and output mesh have different number of points!" << std::endl; return EXIT_FAILURE; } @@ -155,7 +155,7 @@ TestPointDataContainer(typename TMesh::PointDataContainerPointer pointData0, { if (pointData0->Size() != pointData1->Size()) { - std::cerr << "Input mesh and output mesh have different number of cells!" << std::endl; + std::cerr << "Input mesh and output mesh have different number of point data!" << std::endl; return EXIT_FAILURE; } PointDataContainerIterator pdIt0 = pointData0->Begin(); @@ -206,7 +206,7 @@ TestCellDataContainer(typename TMesh::CellDataContainerPointer cellData0, { if (cellData0->Size() != cellData1->Size()) { - std::cerr << "Input mesh and output mesh have different number of cells!" << std::endl; + std::cerr << "Input mesh and output mesh have different number of cell data!" << std::endl; return EXIT_FAILURE; } diff --git a/Modules/IO/MeshBase/include/itkMeshFileWriter.hxx b/Modules/IO/MeshBase/include/itkMeshFileWriter.hxx index 25c04640b2f..ead1eed76e3 100644 --- a/Modules/IO/MeshBase/include/itkMeshFileWriter.hxx +++ b/Modules/IO/MeshBase/include/itkMeshFileWriter.hxx @@ -360,6 +360,9 @@ MeshFileWriter::CopyCellsToBuffer(Output * data) case CellGeometryEnum::LINE_CELL: data[index++] = static_cast(CellGeometryEnum::LINE_CELL); break; + case CellGeometryEnum::POLYLINE_CELL: + data[index++] = static_cast(CellGeometryEnum::POLYLINE_CELL); + break; case CellGeometryEnum::TRIANGLE_CELL: data[index++] = static_cast(CellGeometryEnum::TRIANGLE_CELL); break; @@ -387,7 +390,6 @@ MeshFileWriter::CopyCellsToBuffer(Output * data) // The second element is number of points for each cell data[index++] = cellPtr->GetNumberOfPoints(); - // Others are point identifiers in the cell ptIds = cellPtr->GetPointIds(); unsigned int numberOfPoints = cellPtr->GetNumberOfPoints(); diff --git a/Modules/IO/MeshBase/include/itkMeshIOBase.h b/Modules/IO/MeshBase/include/itkMeshIOBase.h index 217cf510034..20553f86c5a 100644 --- a/Modules/IO/MeshBase/include/itkMeshIOBase.h +++ b/Modules/IO/MeshBase/include/itkMeshIOBase.h @@ -725,7 +725,7 @@ class ITKIOMeshBase_EXPORT MeshIOBase : public LightProcessObject } } - /** Read cells from input buffer, used when Writting cells. This function only + /** Read cells from input buffer, used when Writing cells. This function only write specified type of cells(used when input cells container composes multiple type of cells and only want to write a specified cell type */ template @@ -783,7 +783,7 @@ class ITKIOMeshBase_EXPORT MeshIOBase : public LightProcessObject } } - /** Write cells to a data buffer, used when readding mesh, used for cellType + /** Write cells to a data buffer, used when reading mesh, used for cellType with non-constant number of points */ template void @@ -796,8 +796,13 @@ class ITKIOMeshBase_EXPORT MeshIOBase : public LightProcessObject for (SizeValueType ii = 0; ii < numberOfCells; ++ii) { auto numberOfPoints = static_cast(input[inputIndex++]); + if (numberOfPoints > 2 && cellType == CellGeometryEnum::LINE_CELL) + { + cellType = CellGeometryEnum::POLYLINE_CELL; + } output[outputIndex++] = static_cast(cellType); output[outputIndex++] = static_cast(numberOfPoints); + for (unsigned int jj = 0; jj < numberOfPoints; ++jj) { output[outputIndex++] = static_cast(input[inputIndex++]); diff --git a/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h b/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h index 69eda5bf235..56865c3f70b 100644 --- a/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h +++ b/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h @@ -159,6 +159,10 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase numberOfLines++; numberOfLineIndices += nn + 1; break; + case CellGeometryEnum::POLYLINE_CELL: + numberOfLines++; + numberOfLineIndices += nn + 1; + break; case CellGeometryEnum::TRIANGLE_CELL: numberOfPolygons++; numberOfPolygonIndices += nn + 1; @@ -516,45 +520,25 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase { auto cellType = static_cast(static_cast(buffer[index++])); auto nn = static_cast(buffer[index++]); + + pointIds.clear(); if (cellType == CellGeometryEnum::LINE_CELL) { - if (pointIds.size() >= nn) - { - SizeValueType id = pointIds.back(); - if (id == static_cast(buffer[index])) - { - pointIds.push_back(static_cast(buffer[index + 1])); - } - else if (id == static_cast(buffer[index + 1])) - { - pointIds.push_back(static_cast(buffer[index])); - } - else - { - polylines->InsertElement(numberOfPolylines++, pointIds); - numberOfLineIndices += pointIds.size(); - pointIds.clear(); - - for (unsigned int jj = 0; jj < nn; ++jj) - { - pointIds.push_back(static_cast(buffer[index + jj])); - } - } - } - else + pointIds.push_back(static_cast(buffer[index])); + pointIds.push_back(static_cast(buffer[index + 1])); + } + else if (cellType == CellGeometryEnum::POLYLINE_CELL) + { + for (unsigned int jj = 0; jj < nn; ++jj) { - for (unsigned int jj = 0; jj < nn; ++jj) - { - pointIds.push_back(static_cast(buffer[index + jj])); - } + pointIds.push_back(static_cast(buffer[index + jj])); } } + polylines->InsertElement(numberOfPolylines++, pointIds); + numberOfLineIndices += pointIds.size(); index += nn; } - polylines->InsertElement(numberOfPolylines++, pointIds); - numberOfLineIndices += pointIds.size(); - pointIds.clear(); numberOfLines = polylines->Size(); numberOfLineIndices += numberOfLines; @@ -642,45 +626,24 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase { auto cellType = static_cast(static_cast(buffer[index++])); auto nn = static_cast(buffer[index++]); + pointIds.clear(); + if (cellType == CellGeometryEnum::LINE_CELL) { - if (pointIds.size() >= nn) - { - SizeValueType id = pointIds.back(); - if (id == static_cast(buffer[index])) - { - pointIds.push_back(static_cast(buffer[index + 1])); - } - else if (id == static_cast(buffer[index + 1])) - { - pointIds.push_back(static_cast(buffer[index])); - } - else - { - polylines->InsertElement(numberOfPolylines++, pointIds); - numberOfLineIndices += pointIds.size(); - pointIds.clear(); - - for (unsigned int jj = 0; jj < nn; ++jj) - { - pointIds.push_back(static_cast(buffer[index + jj])); - } - } - } - else + pointIds.push_back(static_cast(buffer[index])); + pointIds.push_back(static_cast(buffer[index + 1])); + } + else if (cellType == CellGeometryEnum::POLYLINE_CELL) + { + for (unsigned int jj = 0; jj < nn; ++jj) { - for (unsigned int jj = 0; jj < nn; ++jj) - { - pointIds.push_back(static_cast(buffer[index + jj])); - } + pointIds.push_back(static_cast(buffer[index + jj])); } } - + polylines->InsertElement(numberOfPolylines++, pointIds); + numberOfLineIndices += pointIds.size(); index += nn; } - polylines->InsertElement(numberOfPolylines++, pointIds); - numberOfLineIndices += pointIds.size(); - pointIds.clear(); numberOfLines = polylines->Size(); numberOfLineIndices += numberOfLines; diff --git a/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx b/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx index e8c7f4c5044..007868fc53f 100644 --- a/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx +++ b/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx @@ -883,7 +883,15 @@ VTKPolyDataMeshIO::ReadCellsBufferAsASCII(std::ifstream & inputFile, void * buff for (unsigned int ii = 0; ii < numberOfLines; ++ii) { inputFile >> numPoints; - data[index++] = static_cast(CellGeometryEnum::LINE_CELL); + if (numPoints == 2) + { + data[index++] = static_cast(CellGeometryEnum::LINE_CELL); + } + else + { + // Use POLYLINE_CELL when more than 2 points are present + data[index++] = static_cast(CellGeometryEnum::POLYLINE_CELL); + } data[index++] = numPoints; for (unsigned int jj = 0; jj < numPoints; ++jj) { diff --git a/Modules/IO/MeshVTK/test/Baseline/hollow.vtk.sha512 b/Modules/IO/MeshVTK/test/Baseline/hollow.vtk.sha512 new file mode 100644 index 00000000000..23134fdfa9e --- /dev/null +++ b/Modules/IO/MeshVTK/test/Baseline/hollow.vtk.sha512 @@ -0,0 +1 @@ +60a0b9ceac31a2865cb3e5a039b76547b657ac6a38157363af2b44424a1687cbda3bc3d4373dcd24eb16da35de08f6088023cb18a2bf2ac73c4c6b7294531158 diff --git a/Modules/IO/MeshVTK/test/CMakeLists.txt b/Modules/IO/MeshVTK/test/CMakeLists.txt index dd8da2c6c61..29f5ba458ee 100644 --- a/Modules/IO/MeshVTK/test/CMakeLists.txt +++ b/Modules/IO/MeshVTK/test/CMakeLists.txt @@ -20,17 +20,22 @@ itk_add_test(NAME itkMeshFileReadWriteVectorAttributeTest DATA{Baseline/sphere_norm.vtk} ${ITK_TEST_OUTPUT_DIR}/sphere_norm.vtk ) -itk_add_test(NAME itkPolylineReadWriteTest00 +itk_add_test(NAME itkPolyLineReadWriteTest00 COMMAND ITKIOMeshVTKTestDriver itkPolylineReadWriteTest DATA{Baseline/fibers.vtk} ${ITK_TEST_OUTPUT_DIR}/fibers.vtk ) -itk_add_test(NAME itkPolylineReadWriteTest01 +itk_add_test(NAME itkPolyLineReadWriteTest01 COMMAND ITKIOMeshVTKTestDriver itkPolylineReadWriteTest DATA{Baseline/fibers.vtk} ${ITK_TEST_OUTPUT_DIR}/fibers_b.vtk 1 ) +itk_add_test(NAME itkPolyLineReadWriteTest02 + COMMAND ITKIOMeshVTKTestDriver itkPolylineReadWriteTest + DATA{Baseline/hollow.vtk} + ${ITK_TEST_OUTPUT_DIR}/hollow.vtk +) itk_add_test(NAME itkMeshFileWriteReadTensorTest COMMAND ITKIOMeshVTKTestDriver itkMeshFileWriteReadTensorTest ${ITK_TEST_OUTPUT_DIR}/itkMeshFileWriteReadTensorTest2D.vtk diff --git a/Modules/IO/MeshVTK/test/itkMeshFileReadWriteTest.cxx b/Modules/IO/MeshVTK/test/itkMeshFileReadWriteTest.cxx index 2363e3834cf..a8a7bf5f9a4 100644 --- a/Modules/IO/MeshVTK/test/itkMeshFileReadWriteTest.cxx +++ b/Modules/IO/MeshVTK/test/itkMeshFileReadWriteTest.cxx @@ -34,11 +34,11 @@ itkMeshFileReadWriteTest(int argc, char * argv[]) bool isBinary = (argc > 3); - constexpr unsigned int dimension = 3; + constexpr unsigned int Dimension = 3; using PixelType = float; - using MeshType = itk::Mesh; - using QEMeshType = itk::QuadEdgeMesh; + using MeshType = itk::Mesh; + using QEMeshType = itk::QuadEdgeMesh; int result = EXIT_SUCCESS; diff --git a/Modules/IO/MeshVTK/test/itkMeshFileReadWriteVectorAttributeTest.cxx b/Modules/IO/MeshVTK/test/itkMeshFileReadWriteVectorAttributeTest.cxx index 5e1c76e420f..733fb9e34f1 100644 --- a/Modules/IO/MeshVTK/test/itkMeshFileReadWriteVectorAttributeTest.cxx +++ b/Modules/IO/MeshVTK/test/itkMeshFileReadWriteVectorAttributeTest.cxx @@ -29,23 +29,23 @@ itkMeshFileReadWriteVectorAttributeTest(int argc, char * argv[]) return EXIT_FAILURE; } - bool IsBinary = (argc > 3); + bool isBinary = (argc > 3); - constexpr unsigned int dimension = 3; - using PixelType = itk::CovariantVector; + constexpr unsigned int Dimension = 3; + using PixelType = itk::CovariantVector; - using MeshType = itk::Mesh; - using QEMeshType = itk::QuadEdgeMesh; + using MeshType = itk::Mesh; + using QEMeshType = itk::QuadEdgeMesh; int result = EXIT_SUCCESS; - if (test(argv[1], argv[2], IsBinary)) + if (test(argv[1], argv[2], isBinary)) { std::cerr << "Failure for itk::Mesh" << std::endl; result = EXIT_FAILURE; } - if (test(argv[1], argv[2], IsBinary)) + if (test(argv[1], argv[2], isBinary)) { std::cerr << "Failure for itk::QuadEdgeMesh" << std::endl; result = EXIT_FAILURE; diff --git a/Modules/IO/MeshVTK/test/itkPolylineReadWriteTest.cxx b/Modules/IO/MeshVTK/test/itkPolylineReadWriteTest.cxx index 63c3f26f6f2..52de830bd47 100644 --- a/Modules/IO/MeshVTK/test/itkPolylineReadWriteTest.cxx +++ b/Modules/IO/MeshVTK/test/itkPolylineReadWriteTest.cxx @@ -29,13 +29,13 @@ itkPolylineReadWriteTest(int argc, char * argv[]) return EXIT_FAILURE; } - bool IsBinary = (argc > 3); + bool isBinary = (argc > 3); - constexpr unsigned int dimension = 3; + constexpr unsigned int Dimension = 3; using PixelType = itk::VariableLengthVector; - using MeshType = itk::Mesh; + using MeshType = itk::Mesh; - if (test(argv[1], argv[2], IsBinary)) + if (test(argv[1], argv[2], isBinary)) { return EXIT_FAILURE; }