Skip to content

Commit 04c33be

Browse files
committed
feat(MeshToWasmMeshFilter): add QuadEdgeMesh specialization
1 parent 11db76c commit 04c33be

10 files changed

+342
-60
lines changed

include/itkMeshJSON.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "itkPixelTypesJSON.h"
2828
#include "itkWasmMesh.h"
2929
#include "itkMetaDataDictionaryJSON.h"
30+
#include "itkQuadEdge.h"
3031

3132
#include "glaze/glaze.hpp"
3233

@@ -172,6 +173,100 @@ auto meshToMeshJSON(const TMesh * mesh, const WasmMesh<TMesh> * wasmMesh, bool i
172173

173174
return meshJSON;
174175
}
176+
177+
template <typename TPixel, unsigned int VDimension>
178+
auto meshToMeshJSON(const QuadEdgeMesh<TPixel, VDimension> * mesh, const WasmMesh<QuadEdgeMesh<TPixel, VDimension>> * wasmMesh, bool inMemory) -> MeshJSON
179+
{
180+
using MeshType = QuadEdgeMesh<TPixel, VDimension>;
181+
182+
MeshJSON meshJSON;
183+
184+
meshJSON.meshType.dimension = MeshType::PointDimension;
185+
186+
meshJSON.meshType.pointComponentType = wasm::MapComponentType<typename MeshType::CoordRepType>::JSONFloatTypeEnum;
187+
using PointPixelType = typename MeshType::PixelType;
188+
using ConvertPointPixelTraits = MeshConvertPixelTraits<PointPixelType>;
189+
meshJSON.meshType.pointPixelComponentType = wasm::MapComponentType<typename ConvertPointPixelTraits::ComponentType>::JSONComponentEnum;
190+
meshJSON.meshType.pointPixelType = wasm::MapPixelType<PointPixelType>::JSONPixelEnum;
191+
meshJSON.meshType.pointPixelComponents = ConvertPointPixelTraits::GetNumberOfComponents();
192+
meshJSON.meshType.cellComponentType = wasm::MapComponentType<typename MeshType::CellIdentifier>::JSONIntTypeEnum;
193+
using CellPixelType = typename MeshType::CellPixelType;
194+
using ConvertCellPixelTraits = MeshConvertPixelTraits<CellPixelType>;
195+
meshJSON.meshType.cellPixelComponentType = wasm::MapComponentType<typename ConvertPointPixelTraits::ComponentType>::JSONComponentEnum;
196+
meshJSON.meshType.cellPixelType = wasm::MapPixelType<CellPixelType>::JSONPixelEnum;
197+
meshJSON.meshType.cellPixelComponents = ConvertCellPixelTraits::GetNumberOfComponents();
198+
199+
meshJSON.name = mesh->GetObjectName();
200+
meshJSON.numberOfPoints = mesh->GetNumberOfPoints();
201+
if (mesh->GetPointData() == nullptr)
202+
{
203+
meshJSON.numberOfPointPixels = 0;
204+
}
205+
else
206+
{
207+
meshJSON.numberOfPointPixels = mesh->GetPointData()->Size();
208+
}
209+
meshJSON.numberOfCells = mesh->GetNumberOfCells();
210+
if (mesh->GetCellData() == nullptr)
211+
{
212+
meshJSON.numberOfCellPixels = 0;
213+
}
214+
else
215+
{
216+
meshJSON.numberOfCellPixels = mesh->GetCellData()->Size();
217+
}
218+
if (inMemory)
219+
{
220+
meshJSON.cellBufferSize = wasmMesh->GetCellBuffer()->Size();
221+
222+
const auto pointsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetPointsBuffer().at(0)) );
223+
std::ostringstream pointsStream;
224+
pointsStream << "data:application/vnd.itk.address,0:";
225+
pointsStream << pointsAddress;
226+
meshJSON.points = pointsStream.str();
227+
size_t cellsAddress = 0;
228+
if (mesh->GetNumberOfCells() > 0)
229+
{
230+
cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) );
231+
}
232+
std::ostringstream cellsStream;
233+
cellsStream << "data:application/vnd.itk.address,0:";
234+
cellsStream << cellsAddress;
235+
meshJSON.cells = cellsStream.str();
236+
237+
size_t pointDataAddress = 0;
238+
if (mesh->GetPointData() != nullptr && mesh->GetPointData()->Size() > 0)
239+
{
240+
pointDataAddress = reinterpret_cast< size_t >( &(wasmMesh->GetPointDataBuffer().at(0)) );
241+
}
242+
std::ostringstream pointDataStream;
243+
pointDataStream << "data:application/vnd.itk.address,0:";
244+
pointDataStream << pointDataAddress;
245+
meshJSON.pointData = pointDataStream.str();
246+
247+
size_t cellDataAddress = 0;
248+
if (mesh->GetCellData() != nullptr && mesh->GetCellData()->Size() > 0)
249+
{
250+
cellDataAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellDataBuffer().at(0)) );
251+
}
252+
std::ostringstream cellDataStream;
253+
cellDataStream << "data:application/vnd.itk.address,0:";
254+
cellDataStream << cellDataAddress;
255+
meshJSON.cellData = cellDataStream.str();
256+
}
257+
else
258+
{
259+
meshJSON.points = "data:application/vnd.itk.path,data/points.raw";
260+
meshJSON.cells = "data:application/vnd.itk.path,data/cells.raw";
261+
meshJSON.pointData = "data:application/vnd.itk.path,data/point-data.raw";
262+
meshJSON.cellData = "data:application/vnd.itk.path,data/cell-data.raw";
263+
}
264+
265+
auto dictionary = mesh->GetMetaDataDictionary();
266+
metaDataDictionaryToJSON(dictionary, meshJSON.metadata);
267+
268+
return meshJSON;
269+
}
175270
} // end namespace itk
176271

177272
#endif // itkMeshJSON_h

include/itkMeshToWasmMeshFilter.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "itkProcessObject.h"
2222
#include "itkWasmMesh.h"
2323
#include "itkMeshJSON.h"
24+
#include "itkQuadEdgeMesh.h"
2425

2526
namespace itk
2627
{
@@ -76,6 +77,71 @@ class ITK_TEMPLATE_EXPORT MeshToWasmMeshFilter : public ProcessObject
7677
WasmMeshType *
7778
GetOutput(unsigned int idx);
7879

80+
protected:
81+
MeshToWasmMeshFilter();
82+
~MeshToWasmMeshFilter() override = default;
83+
84+
ProcessObject::DataObjectPointer
85+
MakeOutput(ProcessObject::DataObjectPointerArraySizeType idx) override;
86+
ProcessObject::DataObjectPointer
87+
MakeOutput(const ProcessObject::DataObjectIdentifierType &) override;
88+
89+
void
90+
GenerateOutputInformation() override
91+
{} // do nothing
92+
void
93+
GenerateData() override;
94+
95+
void
96+
PrintSelf(std::ostream & os, Indent indent) const override;
97+
};
98+
99+
template <typename TPixel, unsigned int VDimension>
100+
class ITK_TEMPLATE_EXPORT MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>> : public ProcessObject
101+
{
102+
public:
103+
ITK_DISALLOW_COPY_AND_MOVE(MeshToWasmMeshFilter);
104+
105+
/** Standard class type aliases. */
106+
using Self = MeshToWasmMeshFilter;
107+
using Superclass = ProcessObject;
108+
using Pointer = SmartPointer<Self>;
109+
using ConstPointer = SmartPointer<const Self>;
110+
111+
/** Method for creation through the object factory. */
112+
itkNewMacro(Self);
113+
114+
/** Run-time type information (and related methods). */
115+
itkTypeMacro(MeshToWasmMeshFilter, ProcessObject);
116+
117+
using DataObjectIdentifierType = Superclass::DataObjectIdentifierType;
118+
using DataObjectPointerArraySizeType = Superclass::DataObjectPointerArraySizeType;
119+
120+
using MeshType = QuadEdgeMesh<TPixel, VDimension>;
121+
using WasmMeshType = WasmMesh<MeshType>;
122+
123+
/** Set/Get the path input of this process object. */
124+
using Superclass::SetInput;
125+
virtual void
126+
SetInput(const MeshType * mesh);
127+
128+
virtual void
129+
SetInput(unsigned int, const MeshType * mesh);
130+
131+
const MeshType *
132+
GetInput();
133+
134+
const MeshType *
135+
GetInput(unsigned int idx);
136+
137+
WasmMeshType *
138+
GetOutput();
139+
const WasmMeshType *
140+
GetOutput() const;
141+
142+
WasmMeshType *
143+
GetOutput(unsigned int idx);
144+
79145
protected:
80146
MeshToWasmMeshFilter();
81147
~MeshToWasmMeshFilter() override = default;

include/itkMeshToWasmMeshFilter.hxx

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,130 @@ MeshToWasmMeshFilter<TMesh>
147147
{
148148
Superclass::PrintSelf(os, indent);
149149
}
150+
151+
template <typename TPixel, unsigned int VDimension>
152+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
153+
::MeshToWasmMeshFilter()
154+
{
155+
this->SetNumberOfRequiredInputs(1);
156+
157+
typename WasmMeshType::Pointer output = static_cast<WasmMeshType *>(this->MakeOutput(0).GetPointer());
158+
this->ProcessObject::SetNumberOfRequiredOutputs(1);
159+
this->ProcessObject::SetNthOutput(0, output.GetPointer());
160+
}
161+
162+
template <typename TPixel, unsigned int VDimension>
163+
ProcessObject::DataObjectPointer
164+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
165+
::MakeOutput(ProcessObject::DataObjectPointerArraySizeType)
166+
{
167+
return WasmMeshType::New().GetPointer();
168+
}
169+
170+
template <typename TPixel, unsigned int VDimension>
171+
ProcessObject::DataObjectPointer
172+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
173+
::MakeOutput(const ProcessObject::DataObjectIdentifierType &)
174+
{
175+
return WasmMeshType::New().GetPointer();
176+
}
177+
178+
template <typename TPixel, unsigned int VDimension>
179+
auto
180+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
181+
::GetOutput() -> WasmMeshType *
182+
{
183+
// we assume that the first output is of the templated type
184+
return itkDynamicCastInDebugMode<WasmMeshType *>(this->GetPrimaryOutput());
185+
}
186+
187+
template <typename TPixel, unsigned int VDimension>
188+
auto
189+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
190+
::GetOutput() const -> const WasmMeshType *
191+
{
192+
// we assume that the first output is of the templated type
193+
return itkDynamicCastInDebugMode<const WasmMeshType *>(this->GetPrimaryOutput());
194+
}
195+
196+
template <typename TPixel, unsigned int VDimension>
197+
auto
198+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
199+
::GetOutput(unsigned int idx) -> WasmMeshType *
200+
{
201+
auto * out = dynamic_cast<WasmMeshType *>(this->ProcessObject::GetOutput(idx));
202+
203+
if (out == nullptr && this->ProcessObject::GetOutput(idx) != nullptr)
204+
{
205+
itkWarningMacro(<< "Unable to convert output number " << idx << " to type " << typeid(WasmMeshType).name());
206+
}
207+
return out;
208+
}
209+
210+
template <typename TPixel, unsigned int VDimension>
211+
void
212+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
213+
::SetInput(const MeshType * input)
214+
{
215+
// Process object is not const-correct so the const_cast is required here
216+
this->ProcessObject::SetNthInput(0, const_cast<MeshType *>(input));
217+
}
218+
219+
template <typename TPixel, unsigned int VDimension>
220+
void
221+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
222+
::SetInput(unsigned int index, const MeshType * mesh)
223+
{
224+
// Process object is not const-correct so the const_cast is required here
225+
this->ProcessObject::SetNthInput(index, const_cast<MeshType *>(mesh));
226+
}
227+
228+
template <typename TPixel, unsigned int VDimension>
229+
const typename MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>::MeshType *
230+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
231+
::GetInput()
232+
{
233+
return itkDynamicCastInDebugMode<const MeshType *>(this->GetPrimaryInput());
234+
}
235+
236+
template <typename TPixel, unsigned int VDimension>
237+
const typename MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>::MeshType *
238+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
239+
::GetInput(unsigned int idx)
240+
{
241+
return itkDynamicCastInDebugMode<const MeshType *>(this->ProcessObject::GetInput(idx));
242+
}
243+
244+
template <typename TPixel, unsigned int VDimension>
245+
void
246+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
247+
::GenerateData()
248+
{
249+
// Get the input and output pointers
250+
const MeshType * mesh = this->GetInput();
251+
WasmMeshType * wasmMesh = this->GetOutput();
252+
253+
wasmMesh->SetMesh(mesh);
254+
constexpr bool inMemory = true;
255+
const auto meshJSON = meshToMeshJSON<TPixel, VDimension>(mesh, wasmMesh, inMemory);
256+
std::string serialized{};
257+
auto ec = glz::write<glz::opts{ .prettify = true }>(meshJSON, serialized);
258+
if (ec)
259+
{
260+
itkExceptionMacro("Failed to serialize MeshJSON");
261+
}
262+
263+
wasmMesh->SetJSON(serialized);
264+
}
265+
266+
template <typename TPixel, unsigned int VDimension>
267+
void
268+
MeshToWasmMeshFilter<QuadEdgeMesh<TPixel, VDimension>>
269+
::PrintSelf(std::ostream & os, Indent indent) const
270+
{
271+
Superclass::PrintSelf(os, indent);
272+
}
273+
150274
} // end namespace itk
151275

152276
#endif

include/itkOutputMesh.h

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -188,35 +188,35 @@ class OutputMesh<itk::QuadEdgeMesh<TPixel, VDimension>>
188188

189189
if (this->m_Mesh->GetNumberOfPoints() > 0)
190190
{
191-
const auto pointsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetPointsBufferContainer().at(0)) );
192-
const auto pointsSize = wasmMesh->GetPointsBufferContainer().size() * sizeof(typename MeshType::PointIdentifier);
191+
const auto pointsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetPointsBuffer().at(0)) );
192+
const auto pointsSize = wasmMesh->GetPointsBuffer().size() * sizeof(typename MeshType::PointIdentifier);
193193
setMemoryStoreOutputArray(0, index, 0, pointsAddress, pointsSize);
194194
}
195195

196-
// if (this->m_Mesh->GetNumberOfCells() > 0)
197-
// {
198-
// const auto cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) );
199-
// const auto cellsSize = wasmMesh->GetCellBuffer()->Size() * sizeof(typename MeshType::CellIdentifier);
200-
// setMemoryStoreOutputArray(0, index, 1, cellsAddress, cellsSize);
201-
// }
196+
if (this->m_Mesh->GetNumberOfCells() > 0)
197+
{
198+
const auto cellsAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellBuffer()->at(0)) );
199+
const auto cellsSize = wasmMesh->GetCellBuffer()->Size() * sizeof(typename MeshType::CellIdentifier);
200+
setMemoryStoreOutputArray(0, index, 1, cellsAddress, cellsSize);
201+
}
202202

203-
// if (this->m_Mesh->GetPointData() != nullptr && this->m_Mesh->GetPointData()->Size() > 0)
204-
// {
205-
// using PointPixelType = typename MeshType::PixelType;
206-
// using ConvertPointPixelTraits = MeshConvertPixelTraits<PointPixelType>;
207-
// const auto pointDataAddress = reinterpret_cast< size_t >( &(wasmMesh->GetMesh()->GetPointData()->at(0)) );
208-
// const auto pointDataSize = wasmMesh->GetMesh()->GetPointData()->Size() * sizeof(typename ConvertPointPixelTraits::ComponentType) * ConvertPointPixelTraits::GetNumberOfComponents();
209-
// setMemoryStoreOutputArray(0, index, 2, pointDataAddress, pointDataSize);
210-
// }
203+
if (this->m_Mesh->GetPointData() != nullptr && this->m_Mesh->GetPointData()->Size() > 0)
204+
{
205+
using PointPixelType = typename MeshType::PixelType;
206+
using ConvertPointPixelTraits = MeshConvertPixelTraits<PointPixelType>;
207+
const auto pointDataAddress = reinterpret_cast< size_t >( &(wasmMesh->GetPointDataBuffer().at(0)) );
208+
const auto pointDataSize = wasmMesh->GetPointDataBuffer().size() * sizeof(typename ConvertPointPixelTraits::ComponentType);
209+
setMemoryStoreOutputArray(0, index, 2, pointDataAddress, pointDataSize);
210+
}
211211

212-
// if (this->m_Mesh->GetCellData() != nullptr && this->m_Mesh->GetCellData()->Size() > 0)
213-
// {
214-
// using CellPixelType = typename MeshType::CellPixelType;
215-
// using ConvertCellPixelTraits = MeshConvertPixelTraits<CellPixelType>;
216-
// const auto cellDataAddress = reinterpret_cast< size_t >( &(wasmMesh->GetMesh()->GetCellData()->at(0)) );
217-
// const auto cellDataSize = wasmMesh->GetMesh()->GetCellData()->Size() * sizeof(typename ConvertCellPixelTraits::ComponentType) * ConvertCellPixelTraits::GetNumberOfComponents();
218-
// setMemoryStoreOutputArray(0, index, 3, cellDataAddress, cellDataSize);
219-
// }
212+
if (this->m_Mesh->GetCellData() != nullptr && this->m_Mesh->GetCellData()->Size() > 0)
213+
{
214+
using CellPixelType = typename MeshType::CellPixelType;
215+
using ConvertCellPixelTraits = MeshConvertPixelTraits<CellPixelType>;
216+
const auto cellDataAddress = reinterpret_cast< size_t >( &(wasmMesh->GetCellDataBuffer().at(0)) );
217+
const auto cellDataSize = wasmMesh->GetCellDataBuffer().size() * sizeof(typename ConvertCellPixelTraits::ComponentType);
218+
setMemoryStoreOutputArray(0, index, 3, cellDataAddress, cellDataSize);
219+
}
220220
}
221221
#else
222222
std::cerr << "Memory IO not supported" << std::endl;

0 commit comments

Comments
 (0)