Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(PointSet): initial C++ addition #1185

Merged
merged 1 commit into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions include/itkInputPointSet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*=========================================================================
*
* 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
*
* https://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 itkInputPointSet_h
#define itkInputPointSet_h

#include "itkPipeline.h"

#ifndef ITK_WASM_NO_MEMORY_IO
#include "itkWasmExports.h"
#include "itkWasmPointSet.h"
#include "itkWasmPointSetToPointSetFilter.h"
#endif
#ifndef ITK_WASM_NO_FILESYSTEM_IO
#include "itkMesh.h"
#include "itkMeshFileReader.h"
#endif

namespace itk
{
namespace wasm
{

/**
*\class InputPointSet
* \brief Input pointSet for an itk::wasm::Pipeline
*
* This point set is read from the filesystem or memory when ITK_WASM_PARSE_ARGS is called.
*
* Call `Get()` to get the TPointSet * to use an input to a pipeline.
*
* \ingroup WebAssemblyInterface
*/
template <typename TPointSet>
class ITK_TEMPLATE_EXPORT InputPointSet
{
public:
using PointSetType = TPointSet;

void Set(const PointSetType * pointSet) {
this->m_PointSet = pointSet;
}

const PointSetType * Get() const {
return this->m_PointSet.GetPointer();
}

InputPointSet() = default;
~InputPointSet() = default;
protected:
typename TPointSet::ConstPointer m_PointSet;
};


template <typename TPointSet>
bool lexical_cast(const std::string &input, InputPointSet<TPointSet> &inputPointSet)
{
if (input.empty())
{
return false;
}

if (wasm::Pipeline::get_use_memory_io())
{
#ifndef ITK_WASM_NO_MEMORY_IO
using WasmPointSetToPointSetFilterType = WasmPointSetToPointSetFilter<TPointSet>;
auto wasmPointSetToPointSetFilter = WasmPointSetToPointSetFilterType::New();
auto wasmPointSet = WasmPointSetToPointSetFilterType::WasmPointSetType::New();
const unsigned int index = std::stoi(input);
auto json = getMemoryStoreInputJSON(0, index);
wasmPointSet->SetJSON(json);
wasmPointSetToPointSetFilter->SetInput(wasmPointSet);
wasmPointSetToPointSetFilter->Update();
inputPointSet.Set(wasmPointSetToPointSetFilter->GetOutput());
#else
return false;
#endif
}
else
{
#ifndef ITK_WASM_NO_FILESYSTEM_IO
using MeshType = Mesh<typename TPointSet::PixelType, TPointSet::PointDimension>;
using ReaderType = MeshFileReader<MeshType>;
auto reader = ReaderType::New();
reader->SetFileName(input);
reader->Update();
auto pointSet = reader->GetOutput();
inputPointSet.Set(pointSet);
#else
return false;
#endif
}
return true;
}

} // end namespace wasm
} // end namespace itk

#endif
145 changes: 145 additions & 0 deletions include/itkOutputPointSet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*=========================================================================
*
* 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
*
* https://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 itkOutputPointSet_h
#define itkOutputPointSet_h

#include "itkPipeline.h"
#include "itkMeshConvertPixelTraits.h"

#ifndef ITK_WASM_NO_MEMORY_IO
#include "itkWasmExports.h"
#include "itkWasmPointSet.h"
#include "itkPointSetToWasmPointSetFilter.h"
#endif
#ifndef ITK_WASM_NO_FILESYSTEM_IO
#include "itkMesh.h"
#include "itkMeshFileWriter.h"
#endif

namespace itk
{
namespace wasm
{
/**
*\class OutputPointSet
* \brief Output point set for an itk::wasm::Pipeline
*
* This point set is written to the filesystem or memory when it goes out of scope.
*
* Call `GetPointSet()` to get the TPointSet * to use an input to a pipeline.
*
* \ingroup WebAssemblyInterface
*/
template <typename TPointSet>
class ITK_TEMPLATE_EXPORT OutputPointSet
{
public:
using PointSetType = TPointSet;

void Set(const PointSetType * pointSet) {
this->m_PointSet = pointSet;
}

const PointSetType * Get() const {
return this->m_PointSet.GetPointer();
}

/** FileName or output index. */
void SetIdentifier(const std::string & identifier)
{
this->m_Identifier = identifier;
}
const std::string & GetIdentifier() const
{
return this->m_Identifier;
}

OutputPointSet() = default;
~OutputPointSet() {
if(wasm::Pipeline::get_use_memory_io())
{
#ifndef ITK_WASM_NO_MEMORY_IO
if (!this->m_PointSet.IsNull() && !this->m_Identifier.empty())
{
using PointSetToWasmPointSetFilterType = PointSetToWasmPointSetFilter<PointSetType>;
auto pointSetToWasmPointSetFilter = PointSetToWasmPointSetFilterType::New();
pointSetToWasmPointSetFilter->SetInput(this->m_PointSet);
pointSetToWasmPointSetFilter->Update();
auto wasmPointSet = pointSetToWasmPointSetFilter->GetOutput();
const auto index = std::stoi(this->m_Identifier);
setMemoryStoreOutputDataObject(0, index, wasmPointSet);

if (this->m_PointSet->GetNumberOfPoints() > 0)
{
const auto pointsAddress = reinterpret_cast< size_t >( &(wasmPointSet->GetPointSet()->GetPoints()->at(0)) );
const auto pointsSize = wasmPointSet->GetPointSet()->GetPoints()->Size() * sizeof(typename PointSetType::CoordRepType) * PointSetType::PointDimension;
setMemoryStoreOutputArray(0, index, 0, pointsAddress, pointsSize);
}

if (this->m_PointSet->GetPointData() != nullptr && this->m_PointSet->GetPointData()->Size() > 0)
{
using PointPixelType = typename PointSetType::PixelType;
using ConvertPointPixelTraits = MeshConvertPixelTraits<PointPixelType>;
const auto pointDataAddress = reinterpret_cast< size_t >( &(wasmPointSet->GetPointSet()->GetPointData()->at(0)) );
const auto pointDataSize = wasmPointSet->GetPointSet()->GetPointData()->Size() * sizeof(typename ConvertPointPixelTraits::ComponentType) * ConvertPointPixelTraits::GetNumberOfComponents();
setMemoryStoreOutputArray(0, index, 1, pointDataAddress, pointDataSize);
}
}
#else
std::cerr << "Memory IO not supported" << std::endl;
abort();
#endif
}
else
{
#ifndef ITK_WASM_NO_FILESYSTEM_IO
if (!this->m_PointSet.IsNull() && !this->m_Identifier.empty())
{
using MeshType = Mesh<typename TPointSet::PixelType, TPointSet::PointDimension>;
using PointSetWriterType = itk::MeshFileWriter<MeshType>;
auto pointSetWriter = PointSetWriterType::New();
pointSetWriter->SetFileName(this->m_Identifier);
typename MeshType::Pointer mesh = MeshType::New();
mesh->SetPoints(const_cast<typename MeshType::PointsContainer *>(this->m_PointSet->GetPoints()));
mesh->SetPointData(const_cast<typename MeshType::PointDataContainer *>(this->m_PointSet->GetPointData()));
pointSetWriter->SetInput(mesh);
pointSetWriter->Update();
}
#else
std::cerr << "Filesystem IO not supported" << std::endl;
abort();
#endif
}
}
protected:
typename TPointSet::ConstPointer m_PointSet;

std::string m_Identifier;
};

template <typename TPointSet>
bool lexical_cast(const std::string &input, OutputPointSet<TPointSet> &outputPointSet)
{
outputPointSet.SetIdentifier(input);
return true;
}

} // namespace wasm
} // namespace itk

#endif
128 changes: 128 additions & 0 deletions include/itkPointSetJSON.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*=========================================================================
*
* 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
*
* https://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 itkPointSetJSON_h
#define itkPointSetJSON_h

#include "itkMeshConvertPixelTraits.h"

#include "itkWasmMapComponentType.h"
#include "itkWasmMapPixelType.h"
#include "itkIntTypesJSON.h"
#include "itkFloatTypesJSON.h"
#include "itkPixelTypesJSON.h"
#include "itkWasmPointSet.h"
#include "itkMetaDataDictionaryJSON.h"

#include "glaze/glaze.hpp"

namespace itk
{
/** \class PointSetTypeJSON
*
* \brief PointSet type JSON representation data structure.
*
* \ingroup WebAssemblyInterface
*/
struct PointSetTypeJSON
{
unsigned int dimension { 2 };
JSONFloatTypesEnum pointComponentType { JSONFloatTypesEnum::float32 };
JSONComponentTypesEnum pointPixelComponentType { JSONComponentTypesEnum::float32 };
JSONPixelTypesEnum pointPixelType { JSONPixelTypesEnum::Scalar };
unsigned int pointPixelComponents { 1 };
};

/** \class PointSetJSON
*
* \brief PointSet JSON representation data structure.
*
* \ingroup WebAssemblyInterface
*/
struct PointSetJSON
{
PointSetTypeJSON pointSetType;

std::string name { "PointSet"};

size_t numberOfPoints{ 0 };
std::string points;

size_t numberOfPointPixels{ 0 };
std::string pointData;

MetadataJSON metadata;
};

template<typename TPointSet>
auto pointSetToPointSetJSON(const TPointSet * pointSet, const WasmPointSet<TPointSet> * wasmPointSet, bool inMemory) -> PointSetJSON
{
using PointSetType = TPointSet;

PointSetJSON pointSetJSON;

pointSetJSON.pointSetType.dimension = PointSetType::PointDimension;

pointSetJSON.pointSetType.pointComponentType = wasm::MapComponentType<typename PointSetType::CoordRepType>::JSONFloatTypeEnum;
using PointPixelType = typename TPointSet::PixelType;
using ConvertPointPixelTraits = MeshConvertPixelTraits<PointPixelType>;
pointSetJSON.pointSetType.pointPixelComponentType = wasm::MapComponentType<typename ConvertPointPixelTraits::ComponentType>::JSONComponentEnum;
pointSetJSON.pointSetType.pointPixelType = wasm::MapPixelType<PointPixelType>::JSONPixelEnum;
pointSetJSON.pointSetType.pointPixelComponents = ConvertPointPixelTraits::GetNumberOfComponents();

pointSetJSON.name = pointSet->GetObjectName();
pointSetJSON.numberOfPoints = pointSet->GetNumberOfPoints();
if (pointSet->GetPointData() == nullptr)
{
pointSetJSON.numberOfPointPixels = 0;
}
else
{
pointSetJSON.numberOfPointPixels = pointSet->GetPointData()->Size();
}
if (inMemory)
{
const auto pointsAddress = reinterpret_cast< size_t >( &(pointSet->GetPoints()->at(0)) );
std::ostringstream pointsStream;
pointsStream << "data:application/vnd.itk.address,0:";
pointsStream << pointsAddress;
pointSetJSON.points = pointsStream.str();

size_t pointDataAddress = 0;
if (pointSet->GetPointData() != nullptr && pointSet->GetPointData()->Size() > 0)
{
pointDataAddress = reinterpret_cast< size_t >( &(pointSet->GetPointData()->at(0)) );
}
std::ostringstream pointDataStream;
pointDataStream << "data:application/vnd.itk.address,0:";
pointDataStream << pointDataAddress;
pointSetJSON.pointData = pointDataStream.str();
}
else
{
pointSetJSON.points = "data:application/vnd.itk.path,data/points.raw";
pointSetJSON.pointData = "data:application/vnd.itk.path,data/point-data.raw";
}

auto dictionary = pointSet->GetMetaDataDictionary();
metaDataDictionaryToJSON(dictionary, pointSetJSON.metadata);

return pointSetJSON;
}
} // end namespace itk

#endif // itkPointSetJSON_h
Loading
Loading