mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Merge remote-tracking branch 'upstream/master' into lagrangian_bugfix
This commit is contained in:
commit
536249f634
@ -2,8 +2,8 @@
|
||||
|
||||
set -e
|
||||
|
||||
readonly version="nvcc_v3"
|
||||
readonly sha256sum="d5b56dd9e7d4597f4a47a90d6327e30a259151b59b897607e1804d6d3513f491"
|
||||
readonly version="nvcc_v4"
|
||||
readonly sha256sum="260779b4a740fe8373d251d1e318541a98dd5cd2f8051eedd55227a5a852fdf7"
|
||||
readonly filename="sccache-0.2.14-$version-x86_64-unknown-linux-musl"
|
||||
readonly tarball="$filename.tar.gz"
|
||||
|
||||
|
@ -24,7 +24,14 @@ ctest_build(APPEND
|
||||
RETURN_VALUE build_result)
|
||||
|
||||
if(NOT DEFINED ENV{GITLAB_CI_EMULATION})
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
|
||||
ctest_submit(PARTS Build BUILD_ID build_id)
|
||||
message(STATUS "Build submission build_id: ${build_id}")
|
||||
else()
|
||||
ctest_submit(PARTS Build)
|
||||
endif()
|
||||
|
||||
|
||||
endif()
|
||||
|
||||
if (build_result)
|
||||
|
@ -38,8 +38,15 @@ ctest_configure(APPEND
|
||||
|
||||
# We can now submit because we've configured.
|
||||
if(NOT DEFINED ENV{GITLAB_CI_EMULATION})
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
|
||||
ctest_submit(PARTS Update BUILD_ID build_id)
|
||||
message(STATUS "Update submission build_id: ${build_id}")
|
||||
ctest_submit(PARTS Configure BUILD_ID build_id)
|
||||
message(STATUS "Configure submission build_id: ${build_id}")
|
||||
else()
|
||||
ctest_submit(PARTS Update)
|
||||
ctest_submit(PARTS Configure)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (configure_result)
|
||||
|
@ -48,7 +48,8 @@ ctest_memcheck(
|
||||
EXCLUDE "${test_exclusions}"
|
||||
DEFECT_COUNT defects)
|
||||
|
||||
ctest_submit(PARTS Memcheck)
|
||||
ctest_submit(PARTS Memcheck BUILD_ID build_id)
|
||||
message(STATUS "Memcheck submission build_id: ${build_id}")
|
||||
|
||||
if (defects)
|
||||
message(FATAL_ERROR "Found ${defects} memcheck defects")
|
||||
|
@ -35,7 +35,8 @@ ctest_test(APPEND
|
||||
)
|
||||
|
||||
if(NOT DEFINED ENV{GITLAB_CI_EMULATION})
|
||||
ctest_submit(PARTS Test)
|
||||
ctest_submit(PARTS Test BUILD_ID build_id)
|
||||
message(STATUS "Test submission build_id: ${build_id}")
|
||||
endif()
|
||||
|
||||
if (test_result)
|
||||
|
@ -378,7 +378,7 @@ function(vtkm_library)
|
||||
EXTENDS_VTKM
|
||||
DEVICE_SOURCES ${VTKm_LIB_DEVICE_SOURCES}
|
||||
)
|
||||
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
|
||||
if(VTKm_HIDE_PRIVATE_SYMBOLS)
|
||||
set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
|
||||
set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden")
|
||||
endif()
|
||||
|
@ -134,7 +134,7 @@ function(vtkm_unit_tests)
|
||||
endif()
|
||||
vtkm_add_target_information(${test_prog} DEVICE_SOURCES ${device_sources})
|
||||
|
||||
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
|
||||
if(VTKm_HIDE_PRIVATE_SYMBOLS)
|
||||
set_property(TARGET ${test_prog} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
|
||||
set_property(TARGET ${test_prog} PROPERTY CXX_VISIBILITY_PRESET "hidden")
|
||||
endif()
|
||||
|
@ -118,7 +118,7 @@ vtkm_option(VTKm_INSTALL_ONLY_LIBRARIES "install only vtk-m libraries and no hea
|
||||
# rather than exporting all symbols. This flag is added so that consumers
|
||||
# which require static builds can force all symbols on, which is something
|
||||
# VTK does.
|
||||
vtkm_option(VTKm_USE_DEFAULT_SYMBOL_VISIBILITY "Don't explicitly hide symbols from libraries." OFF)
|
||||
vtkm_option(VTKm_HIDE_PRIVATE_SYMBOLS "Hide symbols from libraries." ON)
|
||||
|
||||
vtkm_option(BUILD_SHARED_LIBS "Build VTK-m with shared libraries" OFF)
|
||||
set(VTKm_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
|
||||
@ -136,7 +136,7 @@ mark_as_advanced(
|
||||
VTKm_ENABLE_LOGGING
|
||||
VTKm_NO_ASSERT
|
||||
VTKm_INSTALL_ONLY_LIBRARIES
|
||||
VTKm_USE_DEFAULT_SYMBOL_VISIBILITY
|
||||
VTKm_HIDE_PRIVATE_SYMBOLS
|
||||
VTKm_ENABLE_DEVELOPER_FLAGS
|
||||
VTKm_NO_INSTALL_README_LICENSE
|
||||
)
|
||||
|
@ -404,7 +404,7 @@ template <typename ValueType>
|
||||
void BenchCopy(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -580,7 +580,7 @@ template <typename ValueType>
|
||||
void BenchFillArrayHandle(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -610,7 +610,7 @@ VTKM_BENCHMARK_TEMPLATES_OPTS(BenchFillArrayHandle,
|
||||
void BenchFillBitFieldBool(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numBits = numBytes * CHAR_BIT;
|
||||
const bool value = state.range(1) != 0;
|
||||
|
||||
@ -640,7 +640,7 @@ template <typename WordType>
|
||||
void BenchFillBitFieldMask(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numBits = numBytes * CHAR_BIT;
|
||||
const WordType mask = static_cast<WordType>(0x1);
|
||||
|
||||
@ -717,7 +717,7 @@ template <typename ValueType>
|
||||
void BenchReduce(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -752,10 +752,10 @@ void BenchReduceByKey(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
const vtkm::Id percentKeys = state.range(1);
|
||||
const vtkm::Id percentKeys = static_cast<vtkm::Id>(state.range(1));
|
||||
const vtkm::Id numKeys = std::max((numValues * percentKeys) / 100, vtkm::Id{ 1 });
|
||||
|
||||
{
|
||||
@ -807,7 +807,7 @@ template <typename ValueType>
|
||||
void BenchScanExclusive(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -841,7 +841,7 @@ template <typename ValueType>
|
||||
void BenchScanExtended(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -875,7 +875,7 @@ template <typename ValueType>
|
||||
void BenchScanInclusive(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -909,7 +909,7 @@ template <typename ValueType>
|
||||
void BenchSort(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -950,7 +950,7 @@ void BenchSortByKey(benchmark::State& state)
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
const vtkm::Id percentKeys = state.range(1);
|
||||
const vtkm::Id percentKeys = static_cast<vtkm::Id>(state.range(1));
|
||||
const vtkm::Id numKeys = std::max((numValues * percentKeys) / 100, vtkm::Id{ 1 });
|
||||
|
||||
{
|
||||
@ -1005,7 +1005,7 @@ template <typename ValueType>
|
||||
void BenchStableSortIndices(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
state.SetLabel(SizeAndValuesString(numBytes, numValues));
|
||||
@ -1042,10 +1042,10 @@ template <typename ValueType>
|
||||
void BenchStableSortIndicesUnique(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
const vtkm::Id percentUnique = state.range(1);
|
||||
const vtkm::Id percentUnique = static_cast<vtkm::Id>(state.range(1));
|
||||
const vtkm::Id numUnique = std::max((numValues * percentUnique) / 100, vtkm::Id{ 1 });
|
||||
|
||||
{
|
||||
@ -1105,10 +1105,10 @@ template <typename ValueType>
|
||||
void BenchUnique(benchmark::State& state)
|
||||
{
|
||||
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
||||
const vtkm::Id numBytes = state.range(0);
|
||||
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
|
||||
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
|
||||
|
||||
const vtkm::Id percentUnique = state.range(1);
|
||||
const vtkm::Id percentUnique = static_cast<vtkm::Id>(state.range(1));
|
||||
const vtkm::Id numUnique = std::max((numValues * percentUnique) / 100, vtkm::Id{ 1 });
|
||||
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ set(VTKm_BENCHS_RANGE_UPPER_BOUNDARY 134217728 CACHE STRING "Biggest sample for
|
||||
mark_as_advanced(VTKm_BENCHS_RANGE_LOWER_BOUNDARY VTKm_BENCHS_RANGE_UPPER_BOUNDARY)
|
||||
|
||||
foreach (benchmark ${benchmarks})
|
||||
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter)
|
||||
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter vtkm_io)
|
||||
endforeach ()
|
||||
|
||||
target_compile_definitions(BenchmarkDeviceAdapter PUBLIC VTKm_BENCHS_RANGE_LOWER_BOUNDARY=${VTKm_BENCHS_RANGE_LOWER_BOUNDARY})
|
||||
|
13
docs/changelog/coordinate-transform-results.md
Normal file
13
docs/changelog/coordinate-transform-results.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Result DataSet of coordinate transform has its CoordinateSystem changed
|
||||
|
||||
When you run one of the coordinate transform filters,
|
||||
`CylindricalCoordinateTransform` or `SphericalCoordinateTransform`, the
|
||||
transform coordiantes are placed as the first `CoordinateSystem` in the
|
||||
returned `DataSet`. This means that after running this filter, the data
|
||||
will be moved to this new coordinate space.
|
||||
|
||||
Previously, the result of these filters was just placed in a named `Field`
|
||||
of the output. This caused some confusion because the filter did not seem
|
||||
to have any effect (unless you knew to modify the output data). Not using
|
||||
the result as the coordinate system seems like a dubious use case (and not
|
||||
hard to work around), so this is much better behavior.
|
17
docs/changelog/dataset-unique-field-names.md
Normal file
17
docs/changelog/dataset-unique-field-names.md
Normal file
@ -0,0 +1,17 @@
|
||||
# DataSet now only allows unique field names
|
||||
|
||||
When you add a `vtkm::cont::Field` to a `vtkm::cont::DataSet`, it now
|
||||
requires every `Field` to have a unique name. When you attempt to add a
|
||||
`Field` to a `DataSet` that already has a `Field` of the same name and
|
||||
association, the old `Field` is removed and replaced with the new `Field`.
|
||||
|
||||
You are allowed, however, to have two `Field`s with the same name but
|
||||
different associations. For example, you could have a point `Field` named
|
||||
"normals" and also have a cell `Field` named "normals" in the same
|
||||
`DataSet`.
|
||||
|
||||
This new behavior matches how VTK's data sets manage fields.
|
||||
|
||||
The old behavior allowed you to add multiple `Field`s with the same name,
|
||||
but it would be unclear which one you would get if you asked for a `Field`
|
||||
by name.
|
8
docs/changelog/filter-specifies-own-field-types.md
Normal file
8
docs/changelog/filter-specifies-own-field-types.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Filters specify their own field types
|
||||
|
||||
Previously, the policy specified which field types the filter should
|
||||
operate on. The filter could remove some types, but it was not able to
|
||||
add any types.
|
||||
|
||||
This is backward. Instead, the filter should specify what types its
|
||||
supports and the policy may cull out some of those.
|
15
docs/changelog/flying-edges.md
Normal file
15
docs/changelog/flying-edges.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Flying Edges
|
||||
|
||||
Added the flying edges contouring algorithm to VTK-m. This algorithm only
|
||||
works on structured grids, but operates much faster than the traditional
|
||||
Marching Cubes algorithm.
|
||||
|
||||
The speed of VTK-m's flying edges is comprable to VTK's running on the same
|
||||
CPUs. VTK-m's implementation also works well on CUDA hardware.
|
||||
|
||||
The Flying Edges algorithm was introduced in this paper:
|
||||
|
||||
Schroeder, W.; Maynard, R. & Geveci, B.
|
||||
"Flying edges: A high-performance scalable isocontouring algorithm."
|
||||
Large Data Analysis and Visualization (LDAV), 2015.
|
||||
DOI 10.1109/LDAV.2015.7348069
|
32
docs/changelog/image_io.md
Normal file
32
docs/changelog/image_io.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Implemented PNG/PPM image Readers/Writers
|
||||
|
||||
The original implementation of writing image data was only performed as a
|
||||
proxy through the Canvas rendering class. In order to implement true support
|
||||
for image-based regression testing, this interface needed to be expanded upon
|
||||
to support reading/writing arbitrary image data and storing it in a `vtkm::DataSet`.
|
||||
Using the new `vtkm::io::PNGReader` and `vtkm::io::PPMReader` it is possible
|
||||
to read data from files and Cavases directly and store them as a point field
|
||||
in a 2D uniform `vtkm::DataSet`
|
||||
|
||||
```cpp
|
||||
auto reader = vtkm::io::PNGReader();
|
||||
auto imageDataSet = reader.ReadFromFile("read_image.png");
|
||||
```
|
||||
|
||||
Similarly, the new `vtkm::io::PNGWriter` and `vtkm::io::PPMWriter` make it possible
|
||||
to write out a 2D uniform `vtkm::DataSet` directly to a file.
|
||||
|
||||
```cpp
|
||||
auto writer = vtkm::io::PNGWriter();
|
||||
writer.WriteToFile("write_image.png", imageDataSet);
|
||||
```
|
||||
|
||||
If canvas data is to be written out, the reader provides a method for converting
|
||||
a canvas's data to a `vtkm::DataSet`.
|
||||
|
||||
```cpp
|
||||
auto reader = vtkm::io::PNGReader();
|
||||
auto dataSet = reader.CreateImageDataSet(canvas);
|
||||
auto writer = vtkm::io::PNGWriter();
|
||||
writer.WriteToFile("output.png", dataSet);
|
||||
```
|
72
docs/changelog/no-cell-op-errors.md
Normal file
72
docs/changelog/no-cell-op-errors.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Avoid raising errors when operating on cells
|
||||
|
||||
Cell operations like interpolate and finding parametric coordinates can
|
||||
fail under certain conditions. The previous behavior was to call
|
||||
`RaiseError` on the worklet. By design, this would cause the worklet
|
||||
execution to fail. However, that makes the worklet unstable for a conditin
|
||||
that might be relatively common in data. For example, you wouldn't want a
|
||||
large streamline worklet to fail just because one cell was not found
|
||||
correctly.
|
||||
|
||||
To work around this, many of the cell operations in the execution
|
||||
environment have been changed to return an error code rather than raise an
|
||||
error in the worklet.
|
||||
|
||||
## Error Codes
|
||||
|
||||
To support cell operations efficiently returning errors, a new enum named
|
||||
`vtkm::ErrorCode` is available. This is the current implementation of
|
||||
`ErrorCode`.
|
||||
|
||||
``` cpp
|
||||
enum class ErrorCode
|
||||
{
|
||||
Success,
|
||||
InvalidShapeId,
|
||||
InvalidNumberOfPoints,
|
||||
WrongShapeIdForTagType,
|
||||
InvalidPointId,
|
||||
InvalidEdgeId,
|
||||
InvalidFaceId,
|
||||
SolutionDidNotConverge,
|
||||
MatrixFactorizationFailed,
|
||||
DegenerateCellDetected,
|
||||
MalformedCellDetected,
|
||||
OperationOnEmptyCell,
|
||||
CellNotFound,
|
||||
|
||||
UnknownError
|
||||
};
|
||||
```
|
||||
|
||||
A convenience function named `ErrorString` is provided to make it easy to
|
||||
convert the `ErrorCode` to a descriptive string that can be placed in an
|
||||
error.
|
||||
|
||||
## New Calling Specification
|
||||
|
||||
Previously, most execution environment functions took as an argument the
|
||||
worklet calling the function. This made it possible to call `RaiseError` on
|
||||
the worklet. The result of the operation was typically returned. For
|
||||
example, here is how the _old_ version of interpolate was called.
|
||||
|
||||
``` cpp
|
||||
FieldType interpolatedValue =
|
||||
vtkm::exec::CellInterpolate(fieldValues, pcoord, shape, worklet);
|
||||
```
|
||||
|
||||
The worklet is now no longer passed to the function. It is no longer needed
|
||||
because an error is never directly raised. Instead, an `ErrorCode` is
|
||||
returned from the function. Because the `ErrorCode` is returned, the
|
||||
computed result of the function is returned by passing in a reference to a
|
||||
variable. This is usually placed as the last argument (where the worklet
|
||||
used to be). here is the _new_ version of how interpolate is called.
|
||||
|
||||
``` cpp
|
||||
FieldType interpolatedValue;
|
||||
vtkm::ErrorCode result =
|
||||
vtkm::exec::CellInterpolate(fieldValues, pcoord, shape, interpolatedValue);
|
||||
```
|
||||
|
||||
The success of the operation can be determined by checking that the
|
||||
returned `ErrorCode` is equal to `vtkm::ErrorCode::Success`.
|
13
docs/changelog/remove-opengl-rendering-classes.md
Normal file
13
docs/changelog/remove-opengl-rendering-classes.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Removed OpenGL Rendering Classes
|
||||
|
||||
When the rendering library was first built, OpenGL was used to implement
|
||||
the components (windows, mappers, annotation, etc.). However, as the native
|
||||
ray casting became viable, the majority of the work has focused on using
|
||||
that. Since then, the original OpenGL classes have been largely ignored.
|
||||
|
||||
It has for many months been determined that it is not work attempting to
|
||||
maintain two different versions of the rendering libraries as features are
|
||||
added and changed. Thus, the OpenGL classes have fallen out of date and did
|
||||
not actually work.
|
||||
|
||||
These classes have finally been officially removed.
|
13
docs/changelog/vtk-io-in-library.md
Normal file
13
docs/changelog/vtk-io-in-library.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Move VTK file readers and writers into vtkm_io
|
||||
|
||||
The legacy VTK file reader and writer were created back when VTK-m was a
|
||||
header-only library. Things have changed and we now compile quite a bit of
|
||||
code into libraries. At this point, there is no reason why the VTK file
|
||||
reader/writer should be any different.
|
||||
|
||||
Thus, `VTKDataSetReader`, `VTKDataSetWriter`, and several supporting
|
||||
classes are now compiled into the `vtkm_io` library. Also similarly updated
|
||||
`BOVDataSetReader` for good measure.
|
||||
|
||||
As a side effect, code using VTK-m will need to link to `vtkm_io` if they
|
||||
are using any readers or writers.
|
@ -14,7 +14,7 @@ project(Clipping CXX)
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
|
||||
add_executable(Clipping Clipping.cxx)
|
||||
target_link_libraries(Clipping PRIVATE vtkm_filter)
|
||||
target_link_libraries(Clipping PRIVATE vtkm_filter vtkm_io)
|
||||
|
||||
vtkm_add_target_information(Clipping
|
||||
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
|
||||
|
@ -130,7 +130,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
return (it - this->mCLOptions.begin());
|
||||
return static_cast<vtkm::Id>(it - this->mCLOptions.begin());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ project(HelloWorklet CXX)
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
|
||||
add_executable(HelloWorklet HelloWorklet.cxx)
|
||||
target_link_libraries(HelloWorklet PRIVATE vtkm_filter)
|
||||
target_link_libraries(HelloWorklet PRIVATE vtkm_filter vtkm_io)
|
||||
|
||||
vtkm_add_target_information(HelloWorklet
|
||||
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
|
||||
|
@ -26,7 +26,7 @@ project(MeshQuality CXX)
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
|
||||
add_executable(MeshQuality MeshQuality.cxx)
|
||||
target_link_libraries(MeshQuality PRIVATE vtkm_filter)
|
||||
target_link_libraries(MeshQuality PRIVATE vtkm_filter vtkm_io)
|
||||
|
||||
if(TARGET vtkm::tbb)
|
||||
target_compile_definitions(MeshQuality PRIVATE BUILDING_TBB_VERSION)
|
||||
|
@ -62,19 +62,19 @@ void process_partition_tbb(RuntimeTaskQueue& queue)
|
||||
|
||||
void process_partition_openMP(RuntimeTaskQueue& queue)
|
||||
{
|
||||
//Step 1. Set the device adapter to this thread to TBB.
|
||||
//Step 1. Set the device adapter to this thread to openMP.
|
||||
//This makes sure that any vtkm::filters used by our
|
||||
//task operate only on TBB. The "global" thread tracker
|
||||
//task operate only on openMP. The "global" thread tracker
|
||||
//is actually thread-local, so we can use that.
|
||||
//
|
||||
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP{});
|
||||
|
||||
while (queue.hasTasks())
|
||||
{
|
||||
//Step 2. Get the task to run on TBB
|
||||
//Step 2. Get the task to run on openMP
|
||||
auto task = queue.pop();
|
||||
|
||||
//Step 3. Run the task on TBB. We check the validity
|
||||
//Step 3. Run the task on openMP. We check the validity
|
||||
//of the task since we could be given an empty task
|
||||
//when the queue is empty and we are shutting down
|
||||
if (task != nullptr)
|
||||
@ -84,7 +84,8 @@ void process_partition_openMP(RuntimeTaskQueue& queue)
|
||||
|
||||
//Step 4. Notify the queue that we finished processing this task
|
||||
queue.completedTask();
|
||||
std::cout << "finished a partition on tbb (" << std::this_thread::get_id() << ")" << std::endl;
|
||||
std::cout << "finished a partition on openMP (" << std::this_thread::get_id() << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ project(ParticleAdvection CXX)
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
|
||||
add_executable(Particle_Advection ParticleAdvection.cxx)
|
||||
target_link_libraries(Particle_Advection PRIVATE vtkm_filter)
|
||||
target_link_libraries(Particle_Advection PRIVATE vtkm_filter vtkm_io)
|
||||
vtkm_add_target_information(Particle_Advection
|
||||
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
|
||||
DEVICE_SOURCES ParticleAdvection.cxx)
|
||||
|
@ -13,7 +13,7 @@ project(RedistributePoints CXX)
|
||||
#Find the VTK-m package
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
add_executable(RedistributePoints RedistributePoints.cxx RedistributePoints.h)
|
||||
target_link_libraries(RedistributePoints PRIVATE vtkm_filter)
|
||||
target_link_libraries(RedistributePoints PRIVATE vtkm_filter vtkm_io)
|
||||
vtkm_add_target_information(RedistributePoints
|
||||
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
|
||||
DEVICE_SOURCES RedistributePoints.cxx)
|
||||
|
@ -19,4 +19,4 @@ add_executable(Temporal_Advection TemporalAdvection.cxx)
|
||||
vtkm_add_target_information(Temporal_Advection
|
||||
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
|
||||
DEVICE_SOURCES TemporalAdvection.cxx)
|
||||
target_link_libraries(Temporal_Advection PRIVATE vtkm_filter)
|
||||
target_link_libraries(Temporal_Advection PRIVATE vtkm_filter vtkm_io)
|
||||
|
@ -14,10 +14,10 @@ project(Tetrahedra CXX)
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
|
||||
add_executable(Tetrahedralize Tetrahedralize.cxx)
|
||||
target_link_libraries(Tetrahedralize PRIVATE vtkm_filter)
|
||||
target_link_libraries(Tetrahedralize PRIVATE vtkm_filter vtkm_io)
|
||||
|
||||
add_executable(Triangulate Triangulate.cxx)
|
||||
target_link_libraries(Triangulate PRIVATE vtkm_filter)
|
||||
target_link_libraries(Triangulate PRIVATE vtkm_filter vtkm_io)
|
||||
|
||||
vtkm_add_target_information(Tetrahedralize Triangulate
|
||||
DROP_UNUSED_SYMBOLS
|
||||
|
@ -60,7 +60,9 @@
|
||||
// [[deprecated]] is supported, then VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED will get defined.
|
||||
#ifndef VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
|
||||
|
||||
#if __cplusplus >= 201402L && !defined(__NVCC__)
|
||||
#if defined(__NVCC__)
|
||||
// Currently nvcc has zero support deprecated attributes
|
||||
#elif __cplusplus >= 201402L
|
||||
|
||||
// C++14 and better supports [[deprecated]]
|
||||
// Except in these cases:
|
||||
@ -68,7 +70,6 @@
|
||||
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
|
||||
|
||||
#elif defined(VTKM_GCC)
|
||||
|
||||
// GCC has supported [[deprecated]] since version 5.0, but using it on enum was not
|
||||
// supported until 6.0. So we have to make a special case to only use it for high
|
||||
// enough revisions.
|
||||
@ -76,14 +77,14 @@
|
||||
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
|
||||
#endif // Too old GCC
|
||||
|
||||
#elif defined(__has_cpp_attribute) && !defined(__NVCC__)
|
||||
#elif defined(__has_cpp_attribute)
|
||||
|
||||
#if __has_cpp_attribute(deprecated)
|
||||
// Compiler not fully C++14 compliant, but it reports to support [[deprecated]]
|
||||
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
|
||||
#endif // __has_cpp_attribute(deprecated)
|
||||
|
||||
#elif defined(VTKM_MSVC) && (_MSC_VER >= 1900) && !defined(__NVCC__)
|
||||
#elif defined(VTKM_MSVC) && (_MSC_VER >= 1900)
|
||||
|
||||
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
|
||||
|
||||
|
@ -54,9 +54,10 @@ void CellLocatorUniformGrid::Build()
|
||||
}
|
||||
|
||||
UniformType uniformCoords = coords.GetData().Cast<UniformType>();
|
||||
this->Origin = uniformCoords.ReadPortal().GetOrigin();
|
||||
auto coordsPortal = uniformCoords.ReadPortal();
|
||||
this->Origin = coordsPortal.GetOrigin();
|
||||
|
||||
vtkm::Vec3f spacing = uniformCoords.ReadPortal().GetSpacing();
|
||||
vtkm::Vec3f spacing = coordsPortal.GetSpacing();
|
||||
vtkm::Vec3f unitLength;
|
||||
unitLength[0] = static_cast<vtkm::FloatDefault>(this->PointDims[0] - 1);
|
||||
unitLength[1] = static_cast<vtkm::FloatDefault>(this->PointDims[1] - 1);
|
||||
|
@ -186,6 +186,9 @@ public:
|
||||
VTKM_CONT vtkm::IdComponent GetNumberOfPointsInCell(vtkm::Id cellid) const override;
|
||||
VTKM_CONT void GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const override;
|
||||
|
||||
VTKM_CONT typename vtkm::cont::ArrayHandle<vtkm::UInt8, ShapesStorageTag>::ReadPortalType
|
||||
ShapesReadPortal() const;
|
||||
|
||||
VTKM_CONT vtkm::UInt8 GetCellShape(vtkm::Id cellid) const override;
|
||||
|
||||
template <vtkm::IdComponent NumIndices>
|
||||
|
@ -9,7 +9,7 @@
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_CellSetExplicit_hxx
|
||||
#define vtk_m_cont_CellSetExplicit_hxx
|
||||
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/cont/CellSetExplicit.h>
|
||||
|
||||
#include <vtkm/cont/ArrayCopy.h>
|
||||
@ -176,14 +176,22 @@ vtkm::IdComponent CellSetExplicit<SST, CST, OST>
|
||||
|
||||
template <typename SST, typename CST, typename OST>
|
||||
VTKM_CONT
|
||||
typename vtkm::cont::ArrayHandle<vtkm::UInt8, SST>::ReadPortalType
|
||||
CellSetExplicit<SST, CST, OST>::ShapesReadPortal() const
|
||||
{
|
||||
return this->Data->CellPointIds.Shapes.ReadPortal();
|
||||
}
|
||||
|
||||
template <typename SST, typename CST, typename OST>
|
||||
VTKM_CONT
|
||||
VTKM_DEPRECATED(1.6, "Calling GetCellShape(cellid) is a performance bug. Call ShapesReadPortal() and loop over the .Get.")
|
||||
vtkm::UInt8 CellSetExplicit<SST, CST, OST>
|
||||
::GetCellShape(vtkm::Id cellid) const
|
||||
{
|
||||
// Looping over GetCellShape(cellid) is a performance bug.
|
||||
// Don't know quite what to do about it right now.
|
||||
return this->Data->CellPointIds.Shapes.ReadPortal().Get(cellid);
|
||||
return this->ShapesReadPortal().Get(cellid);
|
||||
}
|
||||
|
||||
|
||||
template <typename SST, typename CST, typename OST>
|
||||
template <vtkm::IdComponent NumVecIndices>
|
||||
VTKM_CONT
|
||||
|
@ -204,11 +204,14 @@ void TestCellLocator(const vtkm::Vec<vtkm::Id, DIMENSIONS>& dim, vtkm::Id number
|
||||
vtkm::worklet::DispatcherMapField<FindCellWorklet> dispatcher;
|
||||
dispatcher.Invoke(points, locator, cellIds, pcoords);
|
||||
|
||||
auto cellIdsPortal = cellIds.ReadPortal();
|
||||
auto expCellIdsPortal = expCellIds.ReadPortal();
|
||||
auto pcoordsPortal = pcoords.ReadPortal();
|
||||
auto expPCoordsPortal = expPCoords.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < numberOfPoints; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(cellIds.ReadPortal().Get(i) == expCellIds.ReadPortal().Get(i),
|
||||
"Incorrect cell ids");
|
||||
VTKM_TEST_ASSERT(test_equal(pcoords.ReadPortal().Get(i), expPCoords.ReadPortal().Get(i), 1e-3),
|
||||
VTKM_TEST_ASSERT(cellIdsPortal.Get(i) == expCellIdsPortal.Get(i), "Incorrect cell ids");
|
||||
VTKM_TEST_ASSERT(test_equal(pcoordsPortal.Get(i), expPCoordsPortal.Get(i), 1e-3),
|
||||
"Incorrect parameteric coordinates");
|
||||
}
|
||||
}
|
||||
|
@ -42,9 +42,10 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ahPortal = ah.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < size; ++i)
|
||||
{
|
||||
if (ah.ReadPortal().Get(i) != expected[i])
|
||||
if (ahPortal.Get(i) != expected[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -115,6 +116,7 @@ private:
|
||||
VTKM_TEST_ASSERT(conn.GetNumberOfValues() == connectivitySize,
|
||||
"Connectivity array wrong size.");
|
||||
vtkm::Id connectivityIndex = 0;
|
||||
auto connPortal = conn.ReadPortal();
|
||||
for (vtkm::Id pointIndex = 0; pointIndex < numPoints; pointIndex++)
|
||||
{
|
||||
vtkm::IdComponent numIncidentCells = correctNumIndices[pointIndex];
|
||||
@ -125,7 +127,7 @@ private:
|
||||
}
|
||||
for (vtkm::IdComponent cellIndex = 0; cellIndex < numIncidentCells; cellIndex++)
|
||||
{
|
||||
vtkm::Id expectedCell = conn.ReadPortal().Get(connectivityIndex + cellIndex);
|
||||
vtkm::Id expectedCell = connPortal.Get(connectivityIndex + cellIndex);
|
||||
std::set<vtkm::Id>::iterator foundCell = correctIncidentCells.find(expectedCell);
|
||||
VTKM_TEST_ASSERT(foundCell != correctIncidentCells.end(),
|
||||
"An incident cell in the connectivity list is wrong or repeated.");
|
||||
|
@ -36,9 +36,10 @@ void TestArrayHandleConcatenate()
|
||||
array5 = vtkm::cont::make_ArrayHandleConcatenate(array3, array4);
|
||||
}
|
||||
|
||||
auto array5Portal = array5.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < array5.GetNumberOfValues(); index++)
|
||||
{
|
||||
std::cout << array5.ReadPortal().Get(index) << std::endl;
|
||||
std::cout << array5Portal.Get(index) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,8 +60,9 @@ void TestConcatenateEmptyArray()
|
||||
ArrayConcat arrConc(arr2, arr1);
|
||||
ArrayConcat2 arrConc2(arrConc, arr3);
|
||||
|
||||
auto arrConc2Portal = arrConc2.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < arrConc2.GetNumberOfValues(); i++)
|
||||
std::cout << arrConc2.ReadPortal().Get(i) << std::endl;
|
||||
std::cout << arrConc2Portal.Get(i) << std::endl;
|
||||
}
|
||||
|
||||
} // namespace UnitTestArrayHandleIndexNamespace
|
||||
|
@ -102,14 +102,17 @@ struct TemplatedTests
|
||||
"Counting array using raw array handle + tag has wrong size.");
|
||||
|
||||
ValueType properValue = startingValue;
|
||||
auto arrayConstPortal = arrayConst.ReadPortal();
|
||||
auto arrayMakePortal = arrayMake.ReadPortal();
|
||||
auto arrayHandlePortal = arrayHandle.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
VTKM_TEST_ASSERT(arrayConst.ReadPortal().Get(index) == properValue,
|
||||
VTKM_TEST_ASSERT(arrayConstPortal.Get(index) == properValue,
|
||||
"Counting array using constructor has unexpected value.");
|
||||
VTKM_TEST_ASSERT(arrayMake.ReadPortal().Get(index) == properValue,
|
||||
VTKM_TEST_ASSERT(arrayMakePortal.Get(index) == properValue,
|
||||
"Counting array using make has unexpected value.");
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.ReadPortal().Get(index) == properValue,
|
||||
VTKM_TEST_ASSERT(arrayHandlePortal.Get(index) == properValue,
|
||||
"Counting array using raw array handle + tag has unexpected value.");
|
||||
properValue = properValue + step;
|
||||
}
|
||||
@ -128,6 +131,7 @@ void TestArrayHandleCounting()
|
||||
TemplatedTests<StringInt>()(StringInt(10), StringInt(2));
|
||||
}
|
||||
|
||||
|
||||
} // namespace UnitTestArrayHandleCountingNamespace
|
||||
|
||||
int UnitTestArrayHandleCounting(int argc, char* argv[])
|
||||
|
@ -42,12 +42,13 @@ struct ImplicitTests
|
||||
|
||||
using ImplicitHandle = vtkm::cont::ArrayHandleImplicit<FunctorType>;
|
||||
|
||||
ImplicitHandle implict = vtkm::cont::make_ArrayHandleImplicit(functor, ARRAY_SIZE);
|
||||
ImplicitHandle implicit = vtkm::cont::make_ArrayHandleImplicit(functor, ARRAY_SIZE);
|
||||
|
||||
//verify that the control portal works
|
||||
auto implicitPortal = implicit.ReadPortal();
|
||||
for (int i = 0; i < ARRAY_SIZE; ++i)
|
||||
{
|
||||
const ValueType v = implict.ReadPortal().Get(i);
|
||||
const ValueType v = implicitPortal.Get(i);
|
||||
const ValueType correct_value = functor(i);
|
||||
VTKM_TEST_ASSERT(v == correct_value, "Implicit Handle Failed");
|
||||
}
|
||||
@ -56,7 +57,7 @@ struct ImplicitTests
|
||||
vtkm::cont::Token token;
|
||||
using Device = vtkm::cont::DeviceAdapterTagSerial;
|
||||
using CEPortal = typename ImplicitHandle::template ExecutionTypes<Device>::PortalConst;
|
||||
CEPortal execPortal = implict.PrepareForInput(Device(), token);
|
||||
CEPortal execPortal = implicit.PrepareForInput(Device(), token);
|
||||
for (int i = 0; i < ARRAY_SIZE; ++i)
|
||||
{
|
||||
const ValueType v = execPortal.Get(i);
|
||||
|
@ -188,11 +188,14 @@ void TestWithDataSet(vtkm::cont::CellLocatorGeneral& locator, const vtkm::cont::
|
||||
// CellLocatorGeneral is non-copyable. Pass it via a pointer.
|
||||
dispatcher.Invoke(points, &locator, cellIds, pcoords);
|
||||
|
||||
auto cellIdPortal = cellIds.ReadPortal();
|
||||
auto expCellIdsPortal = expCellIds.ReadPortal();
|
||||
auto pcoordsPortal = pcoords.ReadPortal();
|
||||
auto expPCoordsPortal = expPCoords.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < 128; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(cellIds.ReadPortal().Get(i) == expCellIds.ReadPortal().Get(i),
|
||||
"Incorrect cell ids");
|
||||
VTKM_TEST_ASSERT(test_equal(pcoords.ReadPortal().Get(i), expPCoords.ReadPortal().Get(i), 1e-3),
|
||||
VTKM_TEST_ASSERT(cellIdPortal.Get(i) == expCellIdsPortal.Get(i), "Incorrect cell ids");
|
||||
VTKM_TEST_ASSERT(test_equal(pcoordsPortal.Get(i), expPCoordsPortal.Get(i), 1e-3),
|
||||
"Incorrect parameteric coordinates");
|
||||
}
|
||||
|
||||
|
@ -117,13 +117,13 @@ void TestAgainstBaseLine(const vtkm::cont::CellSet& cellset,
|
||||
: PermutationArray.GetNumberOfValues();
|
||||
VTKM_TEST_ASSERT(numCells == expectedNumCell, "Wrong number of cells");
|
||||
|
||||
auto permutationPortal = PermutationArray.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < numCells; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(cellset.GetCellShape(i) == vtkm::CELL_SHAPE_HEXAHEDRON, "Wrong shape");
|
||||
VTKM_TEST_ASSERT(cellset.GetNumberOfPointsInCell(i) == 8, "Wrong number of points-of-cell");
|
||||
|
||||
vtkm::Id baseLineCellId =
|
||||
(flag == IsPermutationCellSet::YES) ? PermutationArray.ReadPortal().Get(i) : i;
|
||||
vtkm::Id baseLineCellId = (flag == IsPermutationCellSet::YES) ? permutationPortal.Get(i) : i;
|
||||
auto baseLinePointIds = baseLineStructure.GetPointsOfCell(baseLineCellId);
|
||||
|
||||
vtkm::Id pointIds[8];
|
||||
|
@ -32,9 +32,10 @@ bool TestArrayHandle(const vtkm::cont::ArrayHandle<T, Storage>& ah,
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ahPortal = ah.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < size; ++i)
|
||||
{
|
||||
if (ah.ReadPortal().Get(i) != expected[i])
|
||||
if (ahPortal.Get(i) != expected[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -110,9 +111,10 @@ void TestDataSet_Explicit()
|
||||
|
||||
//iterate same cell 4 times
|
||||
vtkm::Float32 expected[4] = { 30.1667f, 30.1667f, 30.1667f, 30.1667f };
|
||||
auto resultPortal = result.ReadPortal();
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
|
||||
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
|
||||
"Wrong result for CellAverage worklet on explicit subset data");
|
||||
}
|
||||
}
|
||||
@ -145,9 +147,10 @@ void TestDataSet_Structured2D()
|
||||
dispatcher.Invoke(subset, dataSet.GetField("pointvar"), result);
|
||||
|
||||
vtkm::Float32 expected[4] = { 40.1f, 40.1f, 40.1f, 40.1f };
|
||||
auto resultPortal = result.ReadPortal();
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
|
||||
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
|
||||
"Wrong result for CellAverage worklet on 2d structured subset data");
|
||||
}
|
||||
}
|
||||
@ -180,9 +183,10 @@ void TestDataSet_Structured3D()
|
||||
dispatcher.Invoke(subset, dataSet.GetField("pointvar"), result);
|
||||
|
||||
vtkm::Float32 expected[4] = { 70.2125f, 70.2125f, 70.2125f, 70.2125f };
|
||||
auto resultPortal = result.ReadPortal();
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
|
||||
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
|
||||
"Wrong result for CellAverage worklet on 2d structured subset data");
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ void RunTests()
|
||||
int UnitTestLogging(int, char* [])
|
||||
{
|
||||
// Test that parameterless init works:
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Log before intialize");
|
||||
vtkm::cont::InitLogging();
|
||||
|
||||
RunTests();
|
||||
|
@ -23,8 +23,7 @@ namespace
|
||||
using TimerTestDevices =
|
||||
vtkm::ListAppend<VTKM_DEFAULT_DEVICE_ADAPTER_LIST, vtkm::List<vtkm::cont::DeviceAdapterTagAny>>;
|
||||
|
||||
constexpr long long waitTimeMilliseconds = 100;
|
||||
constexpr vtkm::Float64 waitTimeSeconds = vtkm::Float64(waitTimeMilliseconds) / 1000;
|
||||
constexpr long long waitTimeMilliseconds = 5;
|
||||
|
||||
struct Waiter
|
||||
{
|
||||
@ -44,17 +43,10 @@ struct Waiter
|
||||
long long millisecondsToSleep = this->ExpectedTimeMilliseconds - elapsedMilliseconds;
|
||||
|
||||
std::cout << " Sleeping for " << millisecondsToSleep << "ms (to " << expectedTimeSeconds
|
||||
<< "s)" << std::endl;
|
||||
<< "s)\n";
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(millisecondsToSleep));
|
||||
|
||||
VTKM_TEST_ASSERT(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - this->Start)
|
||||
.count() <
|
||||
(this->ExpectedTimeMilliseconds + ((3 * waitTimeMilliseconds) / 4)),
|
||||
"Internal test error: Sleep lasted longer than expected. System must be busy. "
|
||||
"Might need to increase waitTimeMilliseconds.");
|
||||
|
||||
return expectedTimeSeconds;
|
||||
}
|
||||
};
|
||||
@ -64,14 +56,11 @@ void CheckTime(const vtkm::cont::Timer& timer, vtkm::Float64 expectedTime)
|
||||
vtkm::Float64 elapsedTime = timer.GetElapsedTime();
|
||||
VTKM_TEST_ASSERT(
|
||||
elapsedTime > (expectedTime - 0.001), "Timer did not capture full wait. ", elapsedTime);
|
||||
VTKM_TEST_ASSERT(elapsedTime < (expectedTime + waitTimeSeconds),
|
||||
"Timer counted too far or system really busy. ",
|
||||
elapsedTime);
|
||||
}
|
||||
|
||||
void DoTimerCheck(vtkm::cont::Timer& timer)
|
||||
{
|
||||
std::cout << " Starting timer" << std::endl;
|
||||
std::cout << " Starting timer\n";
|
||||
timer.Start();
|
||||
VTKM_TEST_ASSERT(timer.Started(), "Timer fails to track started status");
|
||||
VTKM_TEST_ASSERT(!timer.Stopped(), "Timer fails to track non stopped status");
|
||||
@ -85,14 +74,14 @@ void DoTimerCheck(vtkm::cont::Timer& timer)
|
||||
|
||||
CheckTime(timer, expectedTime);
|
||||
|
||||
std::cout << " Make sure timer is still running" << std::endl;
|
||||
std::cout << " Make sure timer is still running\n";
|
||||
VTKM_TEST_ASSERT(!timer.Stopped(), "Timer fails to track stopped status");
|
||||
|
||||
expectedTime = waiter.Wait();
|
||||
|
||||
CheckTime(timer, expectedTime);
|
||||
|
||||
std::cout << " Stop the timer" << std::endl;
|
||||
std::cout << " Stop the timer\n";
|
||||
timer.Stop();
|
||||
VTKM_TEST_ASSERT(timer.Stopped(), "Timer fails to track stopped status");
|
||||
|
||||
@ -100,7 +89,7 @@ void DoTimerCheck(vtkm::cont::Timer& timer)
|
||||
|
||||
waiter.Wait(); // Do not advanced expected time
|
||||
|
||||
std::cout << " Check that timer legitimately stopped" << std::endl;
|
||||
std::cout << " Check that timer legitimately stopped\n";
|
||||
CheckTime(timer, expectedTime);
|
||||
}
|
||||
|
||||
@ -146,7 +135,7 @@ struct TimerCheckFunctor
|
||||
|
||||
void DoTimerTest()
|
||||
{
|
||||
std::cout << "Check default timer" << std::endl;
|
||||
std::cout << "Check default timer\n";
|
||||
vtkm::cont::Timer timer;
|
||||
DoTimerCheck(timer);
|
||||
|
||||
|
@ -30,9 +30,10 @@ template <typename FetchType, typename ExecObjectType>
|
||||
struct Fetch<FetchType, vtkm::exec::arg::AspectTagIncidentElementIndices, ExecObjectType>
|
||||
{
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename Device>
|
||||
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<
|
||||
vtkm::exec::ConnectivityExtrude<Device>>& indices,
|
||||
template <typename Device, typename ScatterAndMaskMode>
|
||||
VTKM_EXEC auto Load(
|
||||
const vtkm::exec::arg::ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>,
|
||||
ScatterAndMaskMode>& indices,
|
||||
const ExecObjectType&) const -> vtkm::Vec<vtkm::Id, 6>
|
||||
{
|
||||
// std::cout << "opimized fetch for point ids" << std::endl;
|
||||
@ -50,8 +51,9 @@ struct Fetch<FetchType, vtkm::exec::arg::AspectTagIncidentElementIndices, ExecOb
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename ConnectivityType>
|
||||
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType>& indices,
|
||||
template <typename ConnectivityType, typename ScatterAndMaskMode>
|
||||
VTKM_EXEC auto Load(
|
||||
const vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType, ScatterAndMaskMode>& indices,
|
||||
const ExecObjectType&) const -> decltype(indices.GetIndicesIncident())
|
||||
{
|
||||
return indices.GetIndicesIncident();
|
||||
@ -133,9 +135,10 @@ struct Fetch<vtkm::exec::arg::FetchTagArrayDirectIn,
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename Device>
|
||||
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<
|
||||
vtkm::exec::ReverseConnectivityExtrude<Device>>& indices,
|
||||
template <typename Device, typename ScatterAndMaskMode>
|
||||
VTKM_EXEC auto Load(
|
||||
const vtkm::exec::arg::ThreadIndicesTopologyMap<vtkm::exec::ReverseConnectivityExtrude<Device>,
|
||||
ScatterAndMaskMode>& indices,
|
||||
const vtkm::exec::ArrayPortalExtrude<T>& points)
|
||||
-> decltype(points.Get(indices.GetIndexLogical()))
|
||||
{
|
||||
|
@ -213,11 +213,11 @@ struct Fetch<vtkm::exec::arg::FetchTagArrayTopologyMapIn,
|
||||
|
||||
//Optimized fetch for point arrays when iterating the cells ConnectivityExtrude
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename Device>
|
||||
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<
|
||||
vtkm::exec::ConnectivityExtrude<Device>>& indices,
|
||||
const ExecObjectType& portal)
|
||||
-> vtkm::Vec<typename ExecObjectType::ValueType, 6>
|
||||
template <typename Device, typename ScatterAndMaskMode>
|
||||
VTKM_EXEC auto Load(
|
||||
const vtkm::exec::arg::ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>,
|
||||
ScatterAndMaskMode>& indices,
|
||||
const ExecObjectType& portal) -> vtkm::Vec<typename ExecObjectType::ValueType, 6>
|
||||
{
|
||||
// std::cout << "opimized fetch for point values" << std::endl;
|
||||
const auto& xgcidx = indices.GetIndicesIncident();
|
||||
|
@ -21,8 +21,8 @@ namespace arg
|
||||
{
|
||||
|
||||
// Specialization for extrude types.
|
||||
template <typename Device>
|
||||
class ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>>
|
||||
template <typename Device, typename ScatterAndMaskMode>
|
||||
class ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>, ScatterAndMaskMode>
|
||||
{
|
||||
|
||||
using ConnectivityType = vtkm::exec::ConnectivityExtrude<Device>;
|
||||
@ -175,8 +175,8 @@ private:
|
||||
};
|
||||
|
||||
// Specialization for extrude types.
|
||||
template <typename Device>
|
||||
class ThreadIndicesTopologyMap<vtkm::exec::ReverseConnectivityExtrude<Device>>
|
||||
template <typename Device, typename ScatterAndMaskMode>
|
||||
class ThreadIndicesTopologyMap<vtkm::exec::ReverseConnectivityExtrude<Device>, ScatterAndMaskMode>
|
||||
{
|
||||
using ConnectivityType = vtkm::exec::ReverseConnectivityExtrude<Device>;
|
||||
|
||||
|
@ -69,6 +69,17 @@ static inline VTKM_EXEC vtkm::Id2 Deflate(const vtkm::Id3& index, vtkm::Id2)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \brief Uses spaces optimizations when using MaskNone and ScatterIdentity
|
||||
///
|
||||
struct DefaultScatterAndMaskTag
|
||||
{
|
||||
};
|
||||
|
||||
/// \brief Used for when not using MaskNone and ScatterIdentity.
|
||||
///
|
||||
struct CustomScatterOrMaskTag
|
||||
{
|
||||
};
|
||||
|
||||
/// \brief Container for thread indices in a topology map
|
||||
///
|
||||
@ -80,7 +91,7 @@ static inline VTKM_EXEC vtkm::Id2 Deflate(const vtkm::Id3& index, vtkm::Id2)
|
||||
/// This class is templated on the type that stores the connectivity (such
|
||||
/// as \c ConnectivityExplicit or \c ConnectivityStructured).
|
||||
///
|
||||
template <typename ConnectivityType>
|
||||
template <typename ConnectivityType, typename ScatterAndMaskMode>
|
||||
class ThreadIndicesTopologyMap : public vtkm::exec::arg::ThreadIndicesBasic
|
||||
{
|
||||
using Superclass = vtkm::exec::arg::ThreadIndicesBasic;
|
||||
@ -144,10 +155,11 @@ private:
|
||||
CellShapeTag CellShape;
|
||||
};
|
||||
|
||||
// Specialization for structured connectivity types.
|
||||
/// \brief Specialization for CustomScatterOrMaskTag
|
||||
template <typename VisitTopology, typename IncidentTopology, vtkm::IdComponent Dimension>
|
||||
class ThreadIndicesTopologyMap<
|
||||
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>>
|
||||
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>,
|
||||
CustomScatterOrMaskTag>
|
||||
{
|
||||
using ConnectivityType =
|
||||
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>;
|
||||
@ -160,15 +172,15 @@ public:
|
||||
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>;
|
||||
|
||||
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
|
||||
vtkm::Id inIndex,
|
||||
vtkm::Id inputIndex,
|
||||
vtkm::IdComponent visitIndex,
|
||||
vtkm::Id outIndex,
|
||||
vtkm::Id outputIndex,
|
||||
const ConnectivityType& connectivity)
|
||||
{
|
||||
this->ThreadIndex = threadIndex;
|
||||
this->InputIndex = inIndex;
|
||||
this->InputIndex = inputIndex;
|
||||
this->VisitIndex = visitIndex;
|
||||
this->OutputIndex = outIndex;
|
||||
this->OutputIndex = outputIndex;
|
||||
this->LogicalIndex = connectivity.FlatToLogicalToIndex(this->InputIndex);
|
||||
this->IndicesIncident = connectivity.GetIndices(this->LogicalIndex);
|
||||
this->CellShape = connectivity.GetCellShape(this->InputIndex);
|
||||
@ -181,9 +193,6 @@ public:
|
||||
// This constructor handles multidimensional indices on one-to-one input-to-output
|
||||
auto logicalIndex = detail::Deflate(threadIndex3D, LogicalIndexType());
|
||||
this->ThreadIndex = threadIndex1D;
|
||||
this->InputIndex = threadIndex1D;
|
||||
this->OutputIndex = threadIndex1D;
|
||||
this->VisitIndex = 0;
|
||||
this->LogicalIndex = logicalIndex;
|
||||
this->IndicesIncident = connectivity.GetIndices(logicalIndex);
|
||||
this->CellShape = connectivity.GetCellShape(threadIndex1D);
|
||||
@ -207,6 +216,7 @@ public:
|
||||
this->CellShape = connectivity.GetCellShape(threadIndex1D);
|
||||
}
|
||||
|
||||
|
||||
/// \brief The index of the thread or work invocation.
|
||||
///
|
||||
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
|
||||
@ -292,20 +302,176 @@ public:
|
||||
|
||||
private:
|
||||
vtkm::Id ThreadIndex;
|
||||
vtkm::Id InputIndex;
|
||||
vtkm::IdComponent VisitIndex;
|
||||
LogicalIndexType LogicalIndex;
|
||||
IndicesIncidentType IndicesIncident;
|
||||
CellShapeTag CellShape;
|
||||
vtkm::Id InputIndex;
|
||||
vtkm::Id OutputIndex;
|
||||
};
|
||||
|
||||
/// \brief Specialization for DefaultScatterAndMaskTag
|
||||
///
|
||||
/// It does not store VisitIndex, InputIndex and OutputIndex
|
||||
/// since this is used only when Scatter is set as ScatterIdentity
|
||||
/// and Mask is set as MaskNone which does not performs any transformation onto the
|
||||
/// indices.
|
||||
///
|
||||
template <typename VisitTopology, typename IncidentTopology, vtkm::IdComponent Dimension>
|
||||
class ThreadIndicesTopologyMap<
|
||||
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>,
|
||||
DefaultScatterAndMaskTag>
|
||||
{
|
||||
using ConnectivityType =
|
||||
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>;
|
||||
|
||||
public:
|
||||
using IndicesIncidentType = typename ConnectivityType::IndicesType;
|
||||
using CellShapeTag = typename ConnectivityType::CellShapeTag;
|
||||
using LogicalIndexType = typename ConnectivityType::SchedulingRangeType;
|
||||
using Connectivity = ConnectivityType;
|
||||
|
||||
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
|
||||
vtkm::Id inputIndex,
|
||||
vtkm::IdComponent vtkmNotUsed(visitIndex),
|
||||
vtkm::Id vtkmNotUsed(outputIndex),
|
||||
const ConnectivityType& connectivity)
|
||||
{
|
||||
this->ThreadIndex = threadIndex;
|
||||
this->LogicalIndex = connectivity.FlatToLogicalToIndex(inputIndex);
|
||||
this->IndicesIncident = connectivity.GetIndices(this->LogicalIndex);
|
||||
this->CellShape = connectivity.GetCellShape(inputIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
VTKM_EXEC ThreadIndicesTopologyMap(const vtkm::Id3& threadIndex3D,
|
||||
vtkm::Id threadIndex1D,
|
||||
const ConnectivityType& connectivity)
|
||||
{
|
||||
// This constructor handles multidimensional indices on one-to-one input-to-output
|
||||
auto logicalIndex = detail::Deflate(threadIndex3D, LogicalIndexType());
|
||||
this->ThreadIndex = threadIndex1D;
|
||||
this->LogicalIndex = logicalIndex;
|
||||
this->IndicesIncident = connectivity.GetIndices(logicalIndex);
|
||||
this->CellShape = connectivity.GetCellShape(threadIndex1D);
|
||||
}
|
||||
|
||||
VTKM_EXEC ThreadIndicesTopologyMap(const vtkm::Id3& threadIndex3D,
|
||||
vtkm::Id threadIndex1D,
|
||||
vtkm::Id vtkmNotUsed(inIndex),
|
||||
vtkm::IdComponent vtkmNotUsed(visitIndex),
|
||||
vtkm::Id vtkmNotUsed(outIndex),
|
||||
const ConnectivityType& connectivity)
|
||||
{
|
||||
// This constructor handles multidimensional indices on many-to-many input-to-output
|
||||
auto logicalIndex = detail::Deflate(threadIndex3D, LogicalIndexType());
|
||||
this->ThreadIndex = threadIndex1D;
|
||||
this->LogicalIndex = logicalIndex;
|
||||
this->IndicesIncident = connectivity.GetIndices(logicalIndex);
|
||||
this->CellShape = connectivity.GetCellShape(threadIndex1D);
|
||||
}
|
||||
|
||||
/// \brief The index of the thread or work invocation.
|
||||
///
|
||||
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
|
||||
/// worklet has a unique thread index. This is also called the work index depending on the
|
||||
/// context.
|
||||
///
|
||||
VTKM_EXEC
|
||||
vtkm::Id GetThreadIndex() const { return this->ThreadIndex; }
|
||||
|
||||
/// \brief The logical index into the input domain.
|
||||
///
|
||||
/// This is similar to \c GetIndex3D except the Vec size matches the actual
|
||||
/// dimensions of the data.
|
||||
///
|
||||
VTKM_EXEC
|
||||
LogicalIndexType GetIndexLogical() const { return this->LogicalIndex; }
|
||||
|
||||
/// \brief The index into the input domain.
|
||||
///
|
||||
/// This index refers to the input element (array value, cell, etc.) that
|
||||
/// this thread is being invoked for. This is the typical index used during
|
||||
/// fetches.
|
||||
///
|
||||
VTKM_EXEC
|
||||
vtkm::Id GetInputIndex() const { return this->ThreadIndex; }
|
||||
|
||||
/// \brief The 3D index into the input domain.
|
||||
///
|
||||
/// Overloads the implementation in the base class to return the 3D index
|
||||
/// for the input.
|
||||
///
|
||||
VTKM_EXEC
|
||||
vtkm::Id3 GetInputIndex3D() const { return detail::InflateTo3D(this->GetIndexLogical()); }
|
||||
|
||||
/// \brief The index into the output domain.
|
||||
///
|
||||
/// This index refers to the output element (array value, cell, etc.) that
|
||||
/// this thread is creating. This is the typical index used during
|
||||
/// Fetch::Store.
|
||||
///
|
||||
VTKM_EXEC
|
||||
vtkm::Id GetOutputIndex() const { return this->ThreadIndex; }
|
||||
|
||||
/// \brief The visit index.
|
||||
///
|
||||
/// When multiple output indices have the same input index, they are
|
||||
/// distinguished using the visit index.
|
||||
///
|
||||
VTKM_EXEC
|
||||
vtkm::IdComponent GetVisitIndex() const { return 0; }
|
||||
|
||||
/// \brief The indices of the incident elements.
|
||||
///
|
||||
/// A topology map has "visited" and "incident" elements (e.g. points, cells,
|
||||
/// etc). For each worklet invocation, there is exactly one visited element,
|
||||
/// but there can be several incident elements. This method returns a
|
||||
/// Vec-like object containing the indices to the incident elements.
|
||||
///
|
||||
VTKM_EXEC
|
||||
const IndicesIncidentType& GetIndicesIncident() const { return this->IndicesIncident; }
|
||||
|
||||
/// \brief The input indices of the incident elements in pointer form.
|
||||
///
|
||||
/// Returns the same object as GetIndicesIncident except that it returns a
|
||||
/// pointer to the internally held object rather than a reference or copy.
|
||||
/// Since the from indices can be a sizeable Vec (8 entries is common), it is
|
||||
/// best not to have a bunch a copies. Thus, you can pass around a pointer
|
||||
/// instead. However, care should be taken to make sure that this object does
|
||||
/// not go out of scope, at which time the returned pointer becomes invalid.
|
||||
///
|
||||
VTKM_EXEC
|
||||
const IndicesIncidentType* GetIndicesIncidentPointer() const { return &this->IndicesIncident; }
|
||||
|
||||
/// \brief The shape of the input cell.
|
||||
///
|
||||
/// In topology maps that map from points to something, the indices make up
|
||||
/// the structure of a cell. Although the shape tag is not technically and
|
||||
/// index, it defines the meaning of the indices, so we put it here. (That
|
||||
/// and this class is the only convenient place to store it.)
|
||||
///
|
||||
VTKM_EXEC
|
||||
CellShapeTag GetCellShape() const { return this->CellShape; }
|
||||
|
||||
private:
|
||||
vtkm::Id ThreadIndex;
|
||||
LogicalIndexType LogicalIndex;
|
||||
IndicesIncidentType IndicesIncident;
|
||||
CellShapeTag CellShape;
|
||||
};
|
||||
|
||||
// Specialization for permuted structured connectivity types.
|
||||
|
||||
/// \brief Specialization for permuted structured connectivity types.
|
||||
template <typename PermutationPortal, vtkm::IdComponent Dimension>
|
||||
class ThreadIndicesTopologyMap<vtkm::exec::ConnectivityPermutedVisitCellsWithPoints<
|
||||
PermutationPortal,
|
||||
vtkm::exec::
|
||||
ConnectivityStructured<vtkm::TopologyElementTagCell, vtkm::TopologyElementTagPoint, Dimension>>>
|
||||
vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagCell,
|
||||
vtkm::TopologyElementTagPoint,
|
||||
Dimension>>,
|
||||
CustomScatterOrMaskTag>
|
||||
{
|
||||
using PermutedConnectivityType = vtkm::exec::ConnectivityPermutedVisitCellsWithPoints<
|
||||
PermutationPortal,
|
||||
|
@ -87,7 +87,9 @@ struct FetchArrayTopologyMapInTests
|
||||
void TryInvocation(const Invocation& invocation) const
|
||||
{
|
||||
using ConnectivityType = typename Invocation::InputDomainType;
|
||||
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType>;
|
||||
using ThreadIndicesType =
|
||||
vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType,
|
||||
vtkm::exec::arg::CustomScatterOrMaskTag>;
|
||||
|
||||
using FetchType = vtkm::exec::arg::Fetch<vtkm::exec::arg::FetchTagArrayTopologyMapIn,
|
||||
vtkm::exec::arg::AspectTagDefault,
|
||||
@ -166,7 +168,9 @@ template <vtkm::IdComponent NumDimensions, vtkm::IdComponent ParamIndex, typenam
|
||||
void TryStructuredPointCoordinatesInvocation(const Invocation& invocation)
|
||||
{
|
||||
using ConnectivityType = typename Invocation::InputDomainType;
|
||||
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType>;
|
||||
using ThreadIndicesType =
|
||||
vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType,
|
||||
vtkm::exec::arg::CustomScatterOrMaskTag>;
|
||||
|
||||
vtkm::exec::arg::Fetch<vtkm::exec::arg::FetchTagArrayTopologyMapIn,
|
||||
vtkm::exec::arg::AspectTagDefault,
|
||||
|
@ -69,7 +69,7 @@ set(unit_tests
|
||||
|
||||
vtkm_unit_tests(
|
||||
SOURCES ${unit_tests}
|
||||
LIBRARIES vtkm_filter vtkm_source
|
||||
LIBRARIES vtkm_filter vtkm_source vtkm_io
|
||||
ALL_BACKENDS
|
||||
USE_VTKM_JOB_POOL
|
||||
)
|
||||
|
@ -97,11 +97,12 @@ void TestNormals(const vtkm::cont::DataSet& dataset, bool structured)
|
||||
result.GetField("normals").GetData().CopyTo(normals);
|
||||
VTKM_TEST_ASSERT(normals.GetNumberOfValues() == numVerts,
|
||||
"Wrong number of values in normals field");
|
||||
auto normalsPortal = normals.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < numVerts; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(normals.ReadPortal().Get(i), expected[i], 0.001),
|
||||
VTKM_TEST_ASSERT(test_equal(normalsPortal.Get(i), expected[i], 0.001),
|
||||
"Result (",
|
||||
normals.ReadPortal().Get(i),
|
||||
normalsPortal.Get(i),
|
||||
") does not match expected value (",
|
||||
expected[i],
|
||||
") vert ",
|
||||
@ -124,9 +125,10 @@ void TestNormals(const vtkm::cont::DataSet& dataset, bool structured)
|
||||
result.GetField("normals").GetData().CopyTo(normals);
|
||||
VTKM_TEST_ASSERT(normals.GetNumberOfValues() == numVerts,
|
||||
"Wrong number of values in normals field");
|
||||
normalsPortal = normals.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < numVerts; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(normals.ReadPortal().Get(i), expected[i], 0.001),
|
||||
VTKM_TEST_ASSERT(test_equal(normalsPortal.Get(i), expected[i], 0.001),
|
||||
"Result does not match expected values");
|
||||
}
|
||||
}
|
||||
|
@ -73,9 +73,10 @@ void TestVertexClustering()
|
||||
auto pointArray = output.GetCoordinateSystem(0).GetData();
|
||||
VTKM_TEST_ASSERT(pointArray.GetNumberOfValues() == output_points,
|
||||
"Number of output points mismatch");
|
||||
auto pointArrayPortal = pointArray.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < pointArray.GetNumberOfValues(); ++i)
|
||||
{
|
||||
const PointType& p1 = pointArray.ReadPortal().Get(i);
|
||||
const PointType& p1 = pointArrayPortal.Get(i);
|
||||
PointType p2 = vtkm::make_Vec(output_point[i][0], output_point[i][1], output_point[i][2]);
|
||||
VTKM_TEST_ASSERT(test_equal(p1, p2), "Point Array mismatch");
|
||||
}
|
||||
|
254
vtkm/io/BOVDataSetReader.cxx
Normal file
254
vtkm/io/BOVDataSetReader.cxx
Normal file
@ -0,0 +1,254 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/BOVDataSetReader.h>
|
||||
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/DataSetFieldAdd.h>
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
enum class DataFormat
|
||||
{
|
||||
ByteData,
|
||||
ShortData,
|
||||
IntegerData,
|
||||
FloatData,
|
||||
DoubleData
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void ReadBuffer(const std::string& fName, const vtkm::Id& sz, std::vector<T>& buff)
|
||||
{
|
||||
FILE* fp = fopen(fName.c_str(), "rb");
|
||||
size_t readSize = static_cast<size_t>(sz);
|
||||
if (fp == nullptr)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Unable to open data file: " + fName);
|
||||
}
|
||||
buff.resize(readSize);
|
||||
size_t nread = fread(&buff[0], sizeof(T), readSize, fp);
|
||||
if (nread != readSize)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Data file read failed: " + fName);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReadScalar(const std::string& fName, const vtkm::Id& nTuples, vtkm::cont::ArrayHandle<T>& var)
|
||||
{
|
||||
std::vector<T> buff;
|
||||
ReadBuffer(fName, nTuples, buff);
|
||||
var.Allocate(nTuples);
|
||||
auto writePortal = var.WritePortal();
|
||||
for (vtkm::Id i = 0; i < nTuples; i++)
|
||||
{
|
||||
writePortal.Set(i, buff[static_cast<size_t>(i)]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReadVector(const std::string& fName,
|
||||
const vtkm::Id& nTuples,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& var)
|
||||
{
|
||||
std::vector<T> buff;
|
||||
ReadBuffer(fName, nTuples * 3, buff);
|
||||
|
||||
var.Allocate(nTuples);
|
||||
vtkm::Vec<T, 3> v;
|
||||
auto writePortal = var.WritePortal();
|
||||
for (vtkm::Id i = 0; i < nTuples; i++)
|
||||
{
|
||||
v[0] = buff[static_cast<size_t>(i * 3 + 0)];
|
||||
v[1] = buff[static_cast<size_t>(i * 3 + 1)];
|
||||
v[2] = buff[static_cast<size_t>(i * 3 + 2)];
|
||||
writePortal.Set(i, v);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
BOVDataSetReader::BOVDataSetReader(const char* fileName)
|
||||
: FileName(fileName)
|
||||
, Loaded(false)
|
||||
, DataSet()
|
||||
{
|
||||
}
|
||||
|
||||
BOVDataSetReader::BOVDataSetReader(const std::string& fileName)
|
||||
: FileName(fileName)
|
||||
, Loaded(false)
|
||||
, DataSet()
|
||||
{
|
||||
}
|
||||
|
||||
const vtkm::cont::DataSet& BOVDataSetReader::ReadDataSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
this->LoadFile();
|
||||
}
|
||||
catch (std::ifstream::failure& e)
|
||||
{
|
||||
std::string message("IO Error: ");
|
||||
throw vtkm::io::ErrorIO(message + e.what());
|
||||
}
|
||||
return this->DataSet;
|
||||
}
|
||||
|
||||
void BOVDataSetReader::LoadFile()
|
||||
{
|
||||
if (this->Loaded)
|
||||
return;
|
||||
|
||||
std::ifstream stream(this->FileName);
|
||||
if (stream.fail())
|
||||
throw vtkm::io::ErrorIO("Failed to open file: " + this->FileName);
|
||||
|
||||
DataFormat dataFormat = DataFormat::ByteData;
|
||||
std::string bovFile, line, token, options, variableName;
|
||||
vtkm::Id numComponents = 1;
|
||||
vtkm::Id3 dim;
|
||||
vtkm::Vec3f origin(0, 0, 0);
|
||||
vtkm::Vec3f spacing(1, 1, 1);
|
||||
bool spacingSet = false;
|
||||
|
||||
while (stream.good())
|
||||
{
|
||||
std::getline(stream, line);
|
||||
if (line.size() == 0 || line[0] == '#')
|
||||
continue;
|
||||
//std::cout<<"::"<<line<<"::"<<std::endl;
|
||||
std::size_t pos = line.find(":");
|
||||
if (pos == std::string::npos)
|
||||
throw vtkm::io::ErrorIO("Unsupported option: " + line);
|
||||
token = line.substr(0, pos);
|
||||
options = line.substr(pos + 1, line.size() - 1);
|
||||
//std::cout<<token<<"::"<<options<<std::endl;
|
||||
|
||||
std::stringstream strStream(options);
|
||||
|
||||
//Format supports both space and "_" separated tokens...
|
||||
if (token.find("DATA") != std::string::npos && token.find("FILE") != std::string::npos)
|
||||
{
|
||||
strStream >> bovFile >> std::ws;
|
||||
}
|
||||
else if (token.find("DATA") != std::string::npos && token.find("SIZE") != std::string::npos)
|
||||
{
|
||||
strStream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
}
|
||||
else if (token.find("BRICK") != std::string::npos && token.find("ORIGIN") != std::string::npos)
|
||||
{
|
||||
strStream >> origin[0] >> origin[1] >> origin[2] >> std::ws;
|
||||
}
|
||||
|
||||
//DRP
|
||||
else if (token.find("BRICK") != std::string::npos && token.find("SIZE") != std::string::npos)
|
||||
{
|
||||
strStream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
|
||||
spacingSet = true;
|
||||
}
|
||||
else if (token.find("DATA") != std::string::npos && token.find("FORMAT") != std::string::npos)
|
||||
{
|
||||
std::string opt;
|
||||
strStream >> opt >> std::ws;
|
||||
if (opt.find("FLOAT") != std::string::npos || opt.find("REAL") != std::string::npos)
|
||||
dataFormat = DataFormat::FloatData;
|
||||
else if (opt.find("DOUBLE") != std::string::npos)
|
||||
dataFormat = DataFormat::DoubleData;
|
||||
else
|
||||
throw vtkm::io::ErrorIO("Unsupported data type: " + token);
|
||||
}
|
||||
else if (token.find("DATA") != std::string::npos &&
|
||||
token.find("COMPONENTS") != std::string::npos)
|
||||
{
|
||||
strStream >> numComponents >> std::ws;
|
||||
if (numComponents != 1 && numComponents != 3)
|
||||
throw vtkm::io::ErrorIO("Unsupported number of components");
|
||||
}
|
||||
else if (token.find("VARIABLE") != std::string::npos &&
|
||||
token.find("PALETTE") == std::string::npos)
|
||||
{
|
||||
strStream >> variableName >> std::ws;
|
||||
if (variableName[0] == '"')
|
||||
variableName = variableName.substr(1, variableName.size() - 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (spacingSet)
|
||||
{
|
||||
spacing[0] = (spacing[0]) / static_cast<vtkm::FloatDefault>(dim[0] - 1);
|
||||
spacing[1] = (spacing[1]) / static_cast<vtkm::FloatDefault>(dim[1] - 1);
|
||||
spacing[2] = (spacing[2]) / static_cast<vtkm::FloatDefault>(dim[2] - 1);
|
||||
}
|
||||
|
||||
std::string fullPathDataFile;
|
||||
std::size_t pos = FileName.rfind("/");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string baseDir;
|
||||
baseDir = this->FileName.substr(0, pos);
|
||||
fullPathDataFile = baseDir + "/" + bovFile;
|
||||
}
|
||||
else
|
||||
fullPathDataFile = bovFile;
|
||||
|
||||
|
||||
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
|
||||
vtkm::cont::DataSetFieldAdd dsf;
|
||||
this->DataSet = dataSetBuilder.Create(dim, origin, spacing);
|
||||
|
||||
vtkm::Id numTuples = dim[0] * dim[1] * dim[2];
|
||||
if (numComponents == 1)
|
||||
{
|
||||
if (dataFormat == DataFormat::FloatData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> var;
|
||||
ReadScalar(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
else if (dataFormat == DataFormat::DoubleData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64> var;
|
||||
ReadScalar(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
}
|
||||
else if (numComponents == 3)
|
||||
{
|
||||
if (dataFormat == DataFormat::FloatData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> var;
|
||||
ReadVector(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
else if (dataFormat == DataFormat::DoubleData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> var;
|
||||
ReadVector(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
}
|
||||
|
||||
this->Loaded = true;
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -10,239 +10,31 @@
|
||||
#ifndef vtk_m_io_BOVDataSetReader_h
|
||||
#define vtk_m_io_BOVDataSetReader_h
|
||||
|
||||
#include <fstream>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/DataSetFieldAdd.h>
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
|
||||
#include <vtkm/io/vtkm_io_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
class BOVDataSetReader
|
||||
class VTKM_IO_EXPORT BOVDataSetReader
|
||||
{
|
||||
public:
|
||||
BOVDataSetReader(const char* fileName)
|
||||
: FileName(fileName)
|
||||
, Loaded(false)
|
||||
, DataSet()
|
||||
{
|
||||
}
|
||||
BOVDataSetReader(const std::string& fileName)
|
||||
: FileName(fileName)
|
||||
, Loaded(false)
|
||||
, DataSet()
|
||||
{
|
||||
}
|
||||
VTKM_CONT BOVDataSetReader(const char* fileName);
|
||||
VTKM_CONT BOVDataSetReader(const std::string& fileName);
|
||||
|
||||
const vtkm::cont::DataSet& ReadDataSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadFile();
|
||||
}
|
||||
catch (std::ifstream::failure& e)
|
||||
{
|
||||
std::string message("IO Error: ");
|
||||
throw vtkm::io::ErrorIO(message + e.what());
|
||||
}
|
||||
return this->DataSet;
|
||||
}
|
||||
VTKM_CONT const vtkm::cont::DataSet& ReadDataSet();
|
||||
|
||||
private:
|
||||
using DataFormat = enum { ByteData, ShortData, IntegerData, FloatData, DoubleData };
|
||||
|
||||
void LoadFile()
|
||||
{
|
||||
if (this->Loaded)
|
||||
return;
|
||||
|
||||
std::ifstream stream(this->FileName);
|
||||
if (stream.fail())
|
||||
throw vtkm::io::ErrorIO("Failed to open file: " + this->FileName);
|
||||
|
||||
DataFormat dataFormat = ByteData;
|
||||
std::string bovFile, line, token, options, variableName;
|
||||
vtkm::Id numComponents = 1;
|
||||
vtkm::Id3 dim;
|
||||
vtkm::Vec3f origin(0, 0, 0);
|
||||
vtkm::Vec3f spacing(1, 1, 1);
|
||||
bool spacingSet = false;
|
||||
|
||||
while (stream.good())
|
||||
{
|
||||
std::getline(stream, line);
|
||||
if (line.size() == 0 || line[0] == '#')
|
||||
continue;
|
||||
//std::cout<<"::"<<line<<"::"<<std::endl;
|
||||
std::size_t pos = line.find(":");
|
||||
if (pos == std::string::npos)
|
||||
throw vtkm::io::ErrorIO("Unsupported option: " + line);
|
||||
token = line.substr(0, pos);
|
||||
options = line.substr(pos + 1, line.size() - 1);
|
||||
//std::cout<<token<<"::"<<options<<std::endl;
|
||||
|
||||
std::stringstream strStream(options);
|
||||
|
||||
//Format supports both space and "_" separated tokens...
|
||||
if (token.find("DATA") != std::string::npos && token.find("FILE") != std::string::npos)
|
||||
{
|
||||
strStream >> bovFile >> std::ws;
|
||||
}
|
||||
else if (token.find("DATA") != std::string::npos && token.find("SIZE") != std::string::npos)
|
||||
{
|
||||
strStream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
}
|
||||
else if (token.find("BRICK") != std::string::npos &&
|
||||
token.find("ORIGIN") != std::string::npos)
|
||||
{
|
||||
strStream >> origin[0] >> origin[1] >> origin[2] >> std::ws;
|
||||
}
|
||||
|
||||
//DRP
|
||||
else if (token.find("BRICK") != std::string::npos && token.find("SIZE") != std::string::npos)
|
||||
{
|
||||
strStream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
|
||||
spacingSet = true;
|
||||
}
|
||||
else if (token.find("DATA") != std::string::npos && token.find("FORMAT") != std::string::npos)
|
||||
{
|
||||
std::string opt;
|
||||
strStream >> opt >> std::ws;
|
||||
if (opt.find("FLOAT") != std::string::npos || opt.find("REAL") != std::string::npos)
|
||||
dataFormat = FloatData;
|
||||
else if (opt.find("DOUBLE") != std::string::npos)
|
||||
dataFormat = DoubleData;
|
||||
else
|
||||
throw vtkm::io::ErrorIO("Unsupported data type: " + token);
|
||||
}
|
||||
else if (token.find("DATA") != std::string::npos &&
|
||||
token.find("COMPONENTS") != std::string::npos)
|
||||
{
|
||||
strStream >> numComponents >> std::ws;
|
||||
if (numComponents != 1 && numComponents != 3)
|
||||
throw vtkm::io::ErrorIO("Unsupported number of components");
|
||||
}
|
||||
else if (token.find("VARIABLE") != std::string::npos &&
|
||||
token.find("PALETTE") == std::string::npos)
|
||||
{
|
||||
strStream >> variableName >> std::ws;
|
||||
if (variableName[0] == '"')
|
||||
variableName = variableName.substr(1, variableName.size() - 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (spacingSet)
|
||||
{
|
||||
spacing[0] = (spacing[0]) / static_cast<vtkm::FloatDefault>(dim[0] - 1);
|
||||
spacing[1] = (spacing[1]) / static_cast<vtkm::FloatDefault>(dim[1] - 1);
|
||||
spacing[2] = (spacing[2]) / static_cast<vtkm::FloatDefault>(dim[2] - 1);
|
||||
}
|
||||
|
||||
std::string fullPathDataFile;
|
||||
std::size_t pos = FileName.rfind("/");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string baseDir;
|
||||
baseDir = this->FileName.substr(0, pos);
|
||||
fullPathDataFile = baseDir + "/" + bovFile;
|
||||
}
|
||||
else
|
||||
fullPathDataFile = bovFile;
|
||||
|
||||
|
||||
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
|
||||
vtkm::cont::DataSetFieldAdd dsf;
|
||||
this->DataSet = dataSetBuilder.Create(dim, origin, spacing);
|
||||
|
||||
vtkm::Id numTuples = dim[0] * dim[1] * dim[2];
|
||||
if (numComponents == 1)
|
||||
{
|
||||
if (dataFormat == FloatData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> var;
|
||||
ReadScalar(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
else if (dataFormat == DoubleData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64> var;
|
||||
ReadScalar(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
}
|
||||
else if (numComponents == 3)
|
||||
{
|
||||
if (dataFormat == FloatData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> var;
|
||||
ReadVector(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
else if (dataFormat == DoubleData)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> var;
|
||||
ReadVector(fullPathDataFile, numTuples, var);
|
||||
dsf.AddPointField(this->DataSet, variableName, var);
|
||||
}
|
||||
}
|
||||
|
||||
this->Loaded = true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReadBuffer(const std::string& fName, const vtkm::Id& sz, std::vector<T>& buff)
|
||||
{
|
||||
FILE* fp = fopen(fName.c_str(), "rb");
|
||||
size_t readSize = static_cast<size_t>(sz);
|
||||
if (fp == nullptr)
|
||||
throw vtkm::io::ErrorIO("Unable to open data file: " + fName);
|
||||
buff.resize(readSize);
|
||||
size_t nread = fread(&buff[0], sizeof(T), readSize, fp);
|
||||
if (nread != readSize)
|
||||
throw vtkm::io::ErrorIO("Data file read failed: " + fName);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReadScalar(const std::string& fName,
|
||||
const vtkm::Id& nTuples,
|
||||
vtkm::cont::ArrayHandle<T>& var)
|
||||
{
|
||||
std::vector<T> buff;
|
||||
ReadBuffer(fName, nTuples, buff);
|
||||
var.Allocate(nTuples);
|
||||
for (vtkm::Id i = 0; i < nTuples; i++)
|
||||
var.WritePortal().Set(i, buff[(size_t)i]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReadVector(const std::string& fName,
|
||||
const vtkm::Id& nTuples,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& var)
|
||||
{
|
||||
std::vector<T> buff;
|
||||
ReadBuffer(fName, nTuples * 3, buff);
|
||||
|
||||
var.Allocate(nTuples);
|
||||
vtkm::Vec<T, 3> v;
|
||||
for (vtkm::Id i = 0; i < nTuples; i++)
|
||||
{
|
||||
v[0] = buff[static_cast<size_t>(i * 3 + 0)];
|
||||
v[1] = buff[static_cast<size_t>(i * 3 + 1)];
|
||||
v[2] = buff[static_cast<size_t>(i * 3 + 2)];
|
||||
var.WritePortal().Set(i, v);
|
||||
}
|
||||
}
|
||||
VTKM_CONT void LoadFile();
|
||||
|
||||
std::string FileName;
|
||||
bool Loaded;
|
||||
vtkm::cont::DataSet DataSet;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // vtkm::io
|
||||
|
||||
#endif // vtk_m_io_BOVReader_h
|
||||
|
@ -13,14 +13,23 @@ set(headers
|
||||
ErrorIO.h
|
||||
DecodePNG.h
|
||||
EncodePNG.h
|
||||
ImageReader.h
|
||||
ImageWriter.h
|
||||
PixelTypes.h
|
||||
VTKDataSetReader.h
|
||||
VTKDataSetReaderBase.h
|
||||
VTKDataSetWriter.h
|
||||
VTKPolyDataReader.h
|
||||
VTKRectilinearGridReader.h
|
||||
VTKStructuredGridReader.h
|
||||
VTKStructuredPointsReader.h
|
||||
VTKUnstructuredGridReader.h
|
||||
VTKDataSetWriter.h
|
||||
)
|
||||
|
||||
set(template_sources
|
||||
ImageReader.hxx
|
||||
ImageWriter.hxx
|
||||
PixelTypes.hxx
|
||||
)
|
||||
|
||||
set(sources
|
||||
@ -28,13 +37,35 @@ set(sources
|
||||
EncodePNG.cxx
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
||||
|
||||
vtkm_library( NAME vtkm_io
|
||||
SOURCES ${sources}
|
||||
HEADERS ${headers}
|
||||
# TODO: None of these codes actually use a device. Rather, they access ArrayHandle, and we
|
||||
# currently need to ensure that ArrayHandle is correctly compiled for all devices. This is
|
||||
# kind of silly, so hopefully sometime in the future you will no longer need to compile for
|
||||
# devices for ArrayHandle, and this requirement will go away.
|
||||
set(device_sources
|
||||
BOVDataSetReader.cxx
|
||||
VTKDataSetReader.cxx
|
||||
VTKDataSetReaderBase.cxx
|
||||
VTKDataSetWriter.cxx
|
||||
VTKPolyDataReader.cxx
|
||||
VTKRectilinearGridReader.cxx
|
||||
VTKStructuredGridReader.cxx
|
||||
VTKStructuredPointsReader.cxx
|
||||
VTKUnstructuredGridReader.cxx
|
||||
)
|
||||
|
||||
vtkm_declare_headers(
|
||||
${headers}
|
||||
${template_sources}
|
||||
)
|
||||
|
||||
vtkm_library(
|
||||
NAME vtkm_io
|
||||
SOURCES ${sources}
|
||||
DEVICE_SOURCES ${device_sources}
|
||||
HEADERS ${headers}
|
||||
TEMPLATE_SOURCES ${template_sources}
|
||||
)
|
||||
|
||||
target_link_libraries(vtkm_io PUBLIC vtkm_cont PRIVATE vtkm_lodepng)
|
||||
|
||||
add_subdirectory(internal)
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <vtkm/cont/Logging.h>
|
||||
#include <vtkm/internal/Configure.h>
|
||||
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
155
vtkm/io/ImageReader.h
Normal file
155
vtkm/io/ImageReader.h
Normal file
@ -0,0 +1,155 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_io_ImageReader_h
|
||||
#define vtk_m_io_ImageReader_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
|
||||
// Forward Declare
|
||||
namespace rendering
|
||||
{
|
||||
class Canvas;
|
||||
} // namespace rendering
|
||||
|
||||
namespace io
|
||||
{
|
||||
|
||||
/// \brief Manages reading, and loading data from images
|
||||
///
|
||||
/// \c BaseImageReader implements methods for loading imaging data from a canvas or
|
||||
/// ArrayHandle and storing that data in a vtkm::cont::DataSet. Image rgb values
|
||||
/// are represented as a point field in a 2D uniform dataset.
|
||||
///
|
||||
/// \c BaseImageReader can be constructed from a file, canvas, or ArrayHandle. It can
|
||||
/// also be empy constructed and filled in with a dataset later.
|
||||
///
|
||||
/// \c BaseImageReader implements virtual methods for reading files. Ideally,
|
||||
/// these methods will be overriden in various subclasses to implement specific
|
||||
/// functionality for reading data to specific image file-types.
|
||||
///
|
||||
/// \c The templated type is used when Filling the ImageDataSet.
|
||||
///
|
||||
class BaseImageReader
|
||||
{
|
||||
public:
|
||||
/// Constructs an emtpy BaseImageReader.
|
||||
///
|
||||
BaseImageReader() = default;
|
||||
explicit BaseImageReader(const vtkm::Id& maxColorValue)
|
||||
: MaxColorValue(maxColorValue)
|
||||
{
|
||||
}
|
||||
~BaseImageReader() noexcept = default;
|
||||
|
||||
/// Reads image data from a file. Meant to be implemented in overriden
|
||||
/// image-specific classes
|
||||
///
|
||||
virtual vtkm::cont::DataSet ReadFromFile(const std::string& fileName) = 0;
|
||||
|
||||
/// Creates an ImageDataSet from a Canvas object
|
||||
///
|
||||
vtkm::cont::DataSet CreateImageDataSet(const vtkm::rendering::Canvas& canvas);
|
||||
|
||||
/// Creates an ImageDataSet from a RGBA 32bit float color buffer
|
||||
/// Assumes the color buffer is stored in row-major ordering
|
||||
///
|
||||
vtkm::cont::DataSet CreateImageDataSet(const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorBuffer,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height);
|
||||
|
||||
const std::string& GetPointFieldName() const { return this->PointFieldName; }
|
||||
|
||||
protected:
|
||||
vtkm::cont::DataSet InitializeImageDataSet(const vtkm::Id& width, const vtkm::Id& height);
|
||||
|
||||
std::string PointFieldName = "pixel-data";
|
||||
vtkm::Id MaxColorValue{ 0 };
|
||||
};
|
||||
|
||||
/// \brief Manages reading images using the PNG format via lodepng
|
||||
///
|
||||
/// \c PNGReader extends BaseImageReader and implements reading images in a valid
|
||||
/// PNG format. It utilizes lodepng's decode file functions to read
|
||||
/// PNG images that are automatically compressed to optimal sizes relative to
|
||||
/// the actual bit complexity of the image.
|
||||
///
|
||||
/// \c PNGReader will automatically upsample/downsample read image data
|
||||
/// to a 16 bit RGB no matter how the image is compressed. It is up to the user to
|
||||
/// decide the pixel format for input PNGs
|
||||
class PNGReader : public BaseImageReader
|
||||
{
|
||||
using Superclass = BaseImageReader;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
PNGReader() = default;
|
||||
~PNGReader() noexcept = default;
|
||||
|
||||
/// Reads PNG data from the provided file and stores it
|
||||
/// as a 16bit RGB value
|
||||
///
|
||||
vtkm::cont::DataSet ReadFromFile(const std::string& fileName) override;
|
||||
|
||||
/// Reads PNG data from the provided file and stores it
|
||||
/// according to the method's templated PixelType
|
||||
///
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet ReadFromFile(const std::string& fileName);
|
||||
};
|
||||
|
||||
|
||||
/// \brief Manages reading images using the PNM format
|
||||
///
|
||||
/// \c PNMImage extends BaseImage, and implements reading images from a
|
||||
/// valid PNM format (for magic number P6). More details on the PNM
|
||||
/// format can be found here: http://netpbm.sourceforge.net/doc/ppm.html
|
||||
///
|
||||
/// When a file is read the parsed MagicNumber and MaxColorSize provided
|
||||
/// are utilized to correctly parse the bits from the file
|
||||
class PNMReader : public BaseImageReader
|
||||
{
|
||||
using Superclass = BaseImageReader;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
PNMReader() = default;
|
||||
~PNMReader() noexcept = default;
|
||||
|
||||
/// Attempts to read the provided file into a DataSet object.
|
||||
/// Will pull the image's MaxColorValue from the file and then Decode
|
||||
/// with the appropriate RGB PixelType bit depth.
|
||||
///
|
||||
vtkm::cont::DataSet ReadFromFile(const std::string& fileName) override;
|
||||
|
||||
protected:
|
||||
/// Reads image data from the provided inStream with the supplied width/height
|
||||
/// Stores the data in a vector of PixelType which is converted to an DataSet
|
||||
///
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet DecodeFile(std::ifstream& inStream,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height);
|
||||
|
||||
// This is set to only work for P6 pnm image types for now (ie ppm)
|
||||
std::string MagicNumber{ "P6" };
|
||||
};
|
||||
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#include <vtkm/io/ImageReader.hxx>
|
||||
|
||||
#endif
|
176
vtkm/io/ImageReader.hxx
Normal file
176
vtkm/io/ImageReader.hxx
Normal file
@ -0,0 +1,176 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_io_ImageReader_hxx
|
||||
#define vtk_m_io_ImageReader_hxx
|
||||
|
||||
#include <vtkm/cont/CellSetStructured.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/DataSetFieldAdd.h>
|
||||
#include <vtkm/io/ImageReader.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
#include <vtkm/rendering/Canvas.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
// Start BaseReaderImage Class Template Implementations
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet BaseImageReader::CreateImageDataSet(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
return this->CreateImageDataSet(canvas.GetColorBuffer(), canvas.GetWidth(), canvas.GetHeight());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet BaseImageReader::CreateImageDataSet(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorBuffer,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec4f_32>::ReadPortalType colorPortal = colorBuffer.ReadPortal();
|
||||
std::vector<vtkm::Vec4f_32> fieldData;
|
||||
for (vtkm::Id yIndex = 0; yIndex < height; yIndex++)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
|
||||
{
|
||||
vtkm::Vec4f_32 tuple = colorPortal.Get(yIndex * width + xIndex);
|
||||
fieldData.push_back(tuple);
|
||||
}
|
||||
}
|
||||
auto dataSet = this->InitializeImageDataSet(width, height);
|
||||
vtkm::cont::DataSetFieldAdd dsf;
|
||||
dsf.AddPointField(dataSet, this->PointFieldName, fieldData);
|
||||
return dataSet;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet BaseImageReader::InitializeImageDataSet(const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::cont::DataSetBuilderUniform dsb;
|
||||
vtkm::Id2 dimensions(width, height);
|
||||
return dsb.Create(dimensions);
|
||||
}
|
||||
// End BaseReaderImage Class Template Implementations
|
||||
|
||||
// Start PNGReader Class Template Implementations
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet PNGReader::ReadFromFile(const std::string& fileName)
|
||||
{
|
||||
return this->ReadFromFile<io::RGBPixel_16>(fileName);
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet PNGReader::ReadFromFile(const std::string& fileName)
|
||||
{
|
||||
unsigned char* imageData;
|
||||
unsigned uwidth, uheight;
|
||||
vtkm::Id width, height;
|
||||
vtkm::png::lodepng_decode_file(&imageData,
|
||||
&uwidth,
|
||||
&uheight,
|
||||
fileName.c_str(),
|
||||
PixelType::PNG_COLOR_TYPE,
|
||||
PixelType::BIT_DEPTH);
|
||||
|
||||
width = static_cast<vtkm::Id>(uwidth);
|
||||
height = static_cast<vtkm::Id>(uheight);
|
||||
|
||||
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
|
||||
// but are stored from Bottom-Left to Top-Right)
|
||||
std::vector<vtkm::Vec4f_32> fieldData;
|
||||
for (vtkm::Id yIndex = static_cast<vtkm::Id>(height - 1); yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < static_cast<vtkm::Id>(width); xIndex++)
|
||||
{
|
||||
vtkm::Id index = static_cast<vtkm::Id>(yIndex * width + xIndex);
|
||||
fieldData.push_back(PixelType(imageData, index).ToVec4f());
|
||||
}
|
||||
}
|
||||
|
||||
auto dataSet = this->InitializeImageDataSet(width, height);
|
||||
vtkm::cont::DataSetFieldAdd dsf;
|
||||
dsf.AddPointField(dataSet, this->PointFieldName, fieldData);
|
||||
|
||||
free(imageData);
|
||||
return dataSet;
|
||||
}
|
||||
// End PNGReader Class Template Implementations
|
||||
|
||||
// Start PNMReader Class Template Implementations
|
||||
VTKM_CONT
|
||||
vtkm::cont::DataSet PNMReader::ReadFromFile(const std::string& fileName)
|
||||
{
|
||||
std::ifstream inStream(fileName.c_str(), std::ios_base::binary | std::ios_base::in);
|
||||
vtkm::Id width;
|
||||
vtkm::Id height;
|
||||
std::string val;
|
||||
|
||||
inStream >> val;
|
||||
if (this->MagicNumber != val)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue("MagicNumber: " + this->MagicNumber + " in file: " + fileName +
|
||||
" did not match: " + val);
|
||||
}
|
||||
|
||||
inStream >> width >> height >> this->MaxColorValue;
|
||||
inStream.get();
|
||||
|
||||
switch (this->MaxColorValue)
|
||||
{
|
||||
case 255:
|
||||
return this->DecodeFile<io::RGBPixel_8>(inStream, width, height);
|
||||
case 65535:
|
||||
return this->DecodeFile<io::RGBPixel_16>(inStream, width, height);
|
||||
default:
|
||||
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
|
||||
" from file: " + fileName + " was not one of: {8, 16}");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
vtkm::cont::DataSet PNMReader::DecodeFile(std::ifstream& inStream,
|
||||
const vtkm::Id& width,
|
||||
const vtkm::Id& height)
|
||||
{
|
||||
vtkm::UInt32 imageSize = static_cast<vtkm::UInt32>(width * height * PixelType::BYTES_PER_PIXEL);
|
||||
std::vector<unsigned char> imageData(imageSize);
|
||||
inStream.read((char*)imageData.data(), imageSize);
|
||||
|
||||
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
|
||||
// but are stored from Bottom-Left to Top-Right)
|
||||
std::vector<vtkm::Vec4f_32> fieldData;
|
||||
for (vtkm::Id yIndex = height - 1; yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
|
||||
{
|
||||
vtkm::Id index = yIndex * width + xIndex;
|
||||
fieldData.push_back(PixelType(imageData.data(), index).ToVec4f());
|
||||
}
|
||||
}
|
||||
|
||||
auto dataSet = this->InitializeImageDataSet(width, height);
|
||||
vtkm::cont::DataSetFieldAdd dsf;
|
||||
dsf.AddPointField(dataSet, this->PointFieldName, fieldData);
|
||||
return dataSet;
|
||||
}
|
||||
// End PNMReader Class Template Implementations
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
140
vtkm/io/ImageWriter.h
Normal file
140
vtkm/io/ImageWriter.h
Normal file
@ -0,0 +1,140 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_io_ImageWriter_h
|
||||
#define vtk_m_io_ImageWriter_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
/// \brief Manages writing, and loading data from images
|
||||
///
|
||||
/// \c BaseImageWriter implements methods for loading imaging data from a canvas or
|
||||
/// ArrayHandle and storing that data in a vtkm::cont::DataSet. Image rgb values
|
||||
/// are represented as a point field in a 2D uniform dataset.
|
||||
///
|
||||
/// \c BaseImageWriter can be constructed from a file, canvas, or ArrayHandle. It can
|
||||
/// also be empy constructed and filled in with a dataset later.
|
||||
///
|
||||
/// \c BaseImageWriter implements virtual methods for writing files. Ideally,
|
||||
/// these methods will be overriden in various subclasses to implement specific
|
||||
/// functionality for writing data to specific image file-types.
|
||||
///
|
||||
class BaseImageWriter
|
||||
{
|
||||
public:
|
||||
/// Constructs an emtpy BaseImageWriter.
|
||||
///
|
||||
BaseImageWriter() = default;
|
||||
explicit BaseImageWriter(const vtkm::Id& maxColorValue)
|
||||
: MaxColorValue(maxColorValue)
|
||||
{
|
||||
}
|
||||
~BaseImageWriter() noexcept = default;
|
||||
|
||||
/// Write and store ImageDataSet to a file. Meant to be implemented in
|
||||
/// overriden image-specific classes
|
||||
///
|
||||
virtual void WriteToFile(const std::string& fileName,
|
||||
const vtkm::cont::DataSet& dataSet) const = 0;
|
||||
|
||||
vtkm::Id GetImageWidth(vtkm::cont::DataSet dataSet) const;
|
||||
vtkm::Id GetImageHeight(vtkm::cont::DataSet dataSet) const;
|
||||
|
||||
const std::string& GetPointFieldName() const { return this->PointFieldName; }
|
||||
void SetMaxColorValue(const vtkm::Id& maxColorValue) { this->MaxColorValue = maxColorValue; }
|
||||
|
||||
protected:
|
||||
std::string PointFieldName = "pixel-data";
|
||||
vtkm::Id MaxColorValue{ 0 };
|
||||
};
|
||||
|
||||
/// \brief Manages writing images using the PNM format
|
||||
///
|
||||
/// \c PNMWriter extends BaseImageWriter, and implements writing images in a
|
||||
/// valid PNM format (for magic number P6). More details on the PNM
|
||||
/// format can be found here: http://netpbm.sourceforge.net/doc/ppm.html
|
||||
///
|
||||
/// When a file is writen the MaxColorValue found in the file is used to
|
||||
/// determine the PixelType required to stored PixelType is instead dependent
|
||||
/// upon the read MaxColorValue obtained from the file
|
||||
class PNMWriter : public BaseImageWriter
|
||||
{
|
||||
using Superclass = BaseImageWriter;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
PNMWriter() = default;
|
||||
~PNMWriter() noexcept = default;
|
||||
|
||||
/// Attempts to write the ImageDataSet to a PNM file. The MaxColorValue
|
||||
/// set in the file with either be selected from the stored MaxColorValue
|
||||
/// member variable, or from the templated type if MaxColorValue hasn't been
|
||||
/// set from a read file.
|
||||
///
|
||||
void WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const override;
|
||||
|
||||
protected:
|
||||
/// Writes image data stored in ImageDataSet to the provided outStream
|
||||
/// Casts the data to the provided PixelType
|
||||
///
|
||||
template <typename PixelType>
|
||||
void EncodeFile(std::ofstream& outStream, const vtkm::cont::DataSet& dataSet) const;
|
||||
|
||||
// Currently only works with P6 PNM files (PPM)
|
||||
std::string MagicNumber{ "P6" };
|
||||
};
|
||||
|
||||
/// \brief Manages writing images using the PNG format via lodepng
|
||||
///
|
||||
/// \c PNGWriter extends BaseImageWriter and implements writing images in a valid
|
||||
/// PNG format. It utilizes lodepng's encode file functions to write
|
||||
/// PNG images that are automatically compressed to optimal sizes relative to
|
||||
/// the actual bit complexity of the image.
|
||||
///
|
||||
/// \c PNGImage will automatically upsample/downsample written image data
|
||||
/// to the supplied templated PixelType. For example, it is possible to write
|
||||
/// a 1-bit greyscale image into a 16bit RGB PNG object. It is up to the user to
|
||||
/// decide the pixel format for output PNGs
|
||||
class PNGWriter : public BaseImageWriter
|
||||
{
|
||||
using Superclass = BaseImageWriter;
|
||||
|
||||
public:
|
||||
using Superclass::Superclass;
|
||||
PNGWriter() = default;
|
||||
~PNGWriter() noexcept = default;
|
||||
|
||||
/// Writes stored data matched to the class's templated type
|
||||
/// to a file in PNG format. Relies upon the lodepng encoding
|
||||
/// method to optimize compression and choose the best storage format.
|
||||
///
|
||||
void WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const override;
|
||||
|
||||
/// Writes stored data matched to the method's templated type
|
||||
/// to a file in PNG format. Relies upon the lodepng encoding
|
||||
/// method to optimize compression and choose the best storage format.
|
||||
///
|
||||
template <typename PixelType>
|
||||
void WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#include <vtkm/io/ImageWriter.hxx>
|
||||
|
||||
#endif
|
173
vtkm/io/ImageWriter.hxx
Normal file
173
vtkm/io/ImageWriter.hxx
Normal file
@ -0,0 +1,173 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_io_ImageWriter_hxx
|
||||
#define vtk_m_io_ImageWriter_hxx
|
||||
|
||||
#include <vtkm/cont/CellSetStructured.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/DataSetFieldAdd.h>
|
||||
#include <vtkm/io/ImageWriter.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKM_CONT
|
||||
vtkm::Id BaseImageWriter::GetImageWidth(vtkm::cont::DataSet dataSet) const
|
||||
{
|
||||
if (dataSet.GetNumberOfCoordinateSystems() > 0)
|
||||
{
|
||||
// Add 1 since the Bounds are 0 indexed
|
||||
return static_cast<vtkm::Id>(dataSet.GetCoordinateSystem().GetBounds().X.Max) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
vtkm::Id BaseImageWriter::GetImageHeight(vtkm::cont::DataSet dataSet) const
|
||||
{
|
||||
if (dataSet.GetNumberOfCoordinateSystems() > 0)
|
||||
{
|
||||
// Add 1 since the Bounds are 0 indexed
|
||||
return static_cast<vtkm::Id>(dataSet.GetCoordinateSystem().GetBounds().Y.Max) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void PNMWriter::WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const
|
||||
{
|
||||
if (!dataSet.HasField(this->PointFieldName))
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue(
|
||||
"No pixel data found in DataSet, cannot write without image data!");
|
||||
}
|
||||
|
||||
std::ofstream outStream(fileName.c_str(), std::ios_base::binary | std::ios_base::out);
|
||||
outStream << this->MagicNumber << std::endl
|
||||
<< this->GetImageWidth(dataSet) << " " << this->GetImageHeight(dataSet) << std::endl;
|
||||
|
||||
switch (this->MaxColorValue)
|
||||
{
|
||||
case 0:
|
||||
this->EncodeFile<RGBPixel_8>(outStream, dataSet);
|
||||
break;
|
||||
case 255:
|
||||
this->EncodeFile<RGBPixel_8>(outStream, dataSet);
|
||||
break;
|
||||
case 65535:
|
||||
this->EncodeFile<RGBPixel_16>(outStream, dataSet);
|
||||
break;
|
||||
default:
|
||||
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
|
||||
" was not one of: {255, 65535}");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
void PNMWriter::EncodeFile(std::ofstream& outStream, const vtkm::cont::DataSet& dataSet) const
|
||||
{
|
||||
outStream << PixelType::MAX_COLOR_VALUE << std::endl;
|
||||
auto pixelField = dataSet.GetPointField(this->PointFieldName)
|
||||
.GetData()
|
||||
.template Cast<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>();
|
||||
auto pixelPortal = pixelField.ReadPortal();
|
||||
|
||||
vtkm::UInt32 imageSize =
|
||||
static_cast<vtkm::UInt32>(pixelField.GetNumberOfValues() * PixelType::BYTES_PER_PIXEL);
|
||||
std::vector<unsigned char> imageData(imageSize);
|
||||
|
||||
// Write out the data starting from the end (Images are stored Bottom-Left to Top-Right,
|
||||
// but are viewed from Top-Left to Bottom-Right)
|
||||
vtkm::Id imageIndex = 0;
|
||||
vtkm::Id imageHeight = this->GetImageHeight(dataSet);
|
||||
vtkm::Id imageWidth = this->GetImageWidth(dataSet);
|
||||
for (vtkm::Id yIndex = imageHeight - 1; yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < imageWidth; xIndex++, imageIndex++)
|
||||
{
|
||||
vtkm::Id index = yIndex * imageWidth + xIndex;
|
||||
PixelType(pixelPortal.Get(index)).FillImageAtIndexWithPixel(imageData.data(), imageIndex);
|
||||
}
|
||||
}
|
||||
outStream.write((char*)imageData.data(), imageSize);
|
||||
outStream.close();
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void PNGWriter::WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const
|
||||
{
|
||||
switch (this->MaxColorValue)
|
||||
{
|
||||
case 0:
|
||||
WriteToFile<RGBPixel_8>(fileName, dataSet);
|
||||
break;
|
||||
case 255:
|
||||
WriteToFile<RGBPixel_8>(fileName, dataSet);
|
||||
break;
|
||||
case 65535:
|
||||
WriteToFile<RGBPixel_16>(fileName, dataSet);
|
||||
break;
|
||||
default:
|
||||
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
|
||||
" was not one of: {255, 65535}");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename PixelType>
|
||||
void PNGWriter::WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const
|
||||
{
|
||||
if (!dataSet.HasField(this->PointFieldName))
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue(
|
||||
"No pixel data found in DataSet, cannot write without image data!");
|
||||
}
|
||||
|
||||
auto pixelField = dataSet.GetPointField(this->PointFieldName)
|
||||
.GetData()
|
||||
.template Cast<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>();
|
||||
auto pixelPortal = pixelField.ReadPortal();
|
||||
std::vector<unsigned char> imageData(static_cast<typename std::vector<unsigned char>::size_type>(
|
||||
pixelField.GetNumberOfValues() * PixelType::BYTES_PER_PIXEL));
|
||||
|
||||
// Write out the data starting from the end (Images are stored Bottom-Left to Top-Right,
|
||||
// but are viewed from Top-Left to Bottom-Right)
|
||||
vtkm::Id imageIndex = 0;
|
||||
vtkm::Id imageHeight = this->GetImageHeight(dataSet);
|
||||
vtkm::Id imageWidth = this->GetImageWidth(dataSet);
|
||||
for (vtkm::Id yIndex = imageHeight - 1; yIndex >= 0; yIndex--)
|
||||
{
|
||||
for (vtkm::Id xIndex = 0; xIndex < imageWidth; xIndex++, imageIndex++)
|
||||
{
|
||||
vtkm::Id index = yIndex * imageWidth + xIndex;
|
||||
PixelType(pixelPortal.Get(index)).FillImageAtIndexWithPixel(imageData.data(), imageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
vtkm::png::lodepng_encode_file(fileName.c_str(),
|
||||
imageData.data(),
|
||||
static_cast<unsigned>(imageWidth),
|
||||
static_cast<unsigned>(imageHeight),
|
||||
PixelType::PNG_COLOR_TYPE,
|
||||
PixelType::BIT_DEPTH);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
201
vtkm/io/PixelTypes.h
Normal file
201
vtkm/io/PixelTypes.h
Normal file
@ -0,0 +1,201 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_io_PixelTypes_h
|
||||
#define vtk_m_io_PixelTypes_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Define custom SFINAE structures to calculate the VTKM types associated
|
||||
// with provided BitDepths
|
||||
template <const vtkm::Id size, typename = void>
|
||||
struct ComponentTypeFromSize
|
||||
{
|
||||
};
|
||||
|
||||
template <const vtkm::Id size>
|
||||
struct ComponentTypeFromSize<size, typename std::enable_if<(size == 8)>::type>
|
||||
{
|
||||
using type = vtkm::UInt8;
|
||||
};
|
||||
template <const vtkm::Id size>
|
||||
struct ComponentTypeFromSize<size, typename std::enable_if<(size == 16)>::type>
|
||||
{
|
||||
using type = vtkm::UInt16;
|
||||
};
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/// \brief Base type for more complex pixels (RGB, Greyscale, etc) that describes various values
|
||||
/// such as bit-depth, channel width, bytes per pixel, and how various data should be polled
|
||||
///
|
||||
/// \c BasePixel takes BitDepth and Channels as template parameters. BitDepth describes the number
|
||||
/// of bits in the pixel, while Channels describes the multiple of bits that are available.
|
||||
/// BasePixel extends vtkm::Vec. The ComponentType is pulled from the ComponentTypeFromSize
|
||||
/// SFINAE struct defined above. This helps with optimizing the pixel size for a given
|
||||
/// bit-depth. The Size is pulled from the Channels param.
|
||||
///
|
||||
/// \c BasePixel requires BitDepths that are > 8 and powers of 2 at the moment. BitDepths of
|
||||
/// 4, 2, or 1 bit are not correctly handled at the moment.
|
||||
///
|
||||
/// \c BasePixel describes how to populate itself from an unsigned char pointer (assuming that
|
||||
/// the data stored within the pointer matches the bit-depth and channels described by the
|
||||
/// BasePixel type), and how to fill in data for an unsigned char pointer. This is mostly
|
||||
/// useful in serialization and deserialization to various image formats.
|
||||
///
|
||||
template <const vtkm::Id BitDepth, const vtkm::IdComponent Channels>
|
||||
class BasePixel : public vtkm::Vec<typename ComponentTypeFromSize<BitDepth>::type, Channels>
|
||||
{
|
||||
static_assert(BitDepth >= 8, "BitDepth not >= 8");
|
||||
static_assert(!(BitDepth & (BitDepth - 1)), "BitDepth not a power of 2");
|
||||
|
||||
public:
|
||||
using Superclass = vtkm::Vec<typename ComponentTypeFromSize<BitDepth>::type, Channels>;
|
||||
using ComponentType = typename Superclass::ComponentType;
|
||||
using BaseType = BasePixel<BitDepth, Channels>;
|
||||
|
||||
static constexpr vtkm::IdComponent BIT_DEPTH = BitDepth;
|
||||
static constexpr vtkm::IdComponent NUM_BYTES = BitDepth / 8;
|
||||
static constexpr vtkm::IdComponent MAX_COLOR_VALUE = (1 << BitDepth) - 1;
|
||||
static constexpr vtkm::IdComponent NUM_CHANNELS = Superclass::NUM_COMPONENTS;
|
||||
static constexpr vtkm::IdComponent BYTES_PER_PIXEL = NUM_CHANNELS * NUM_BYTES;
|
||||
|
||||
using Superclass::Superclass;
|
||||
BasePixel() = default;
|
||||
|
||||
/// Fills in this->Components by calling ConstructPixelFromImage. Requires
|
||||
/// the base vec values to be zeroed out initially.
|
||||
///
|
||||
BasePixel(const unsigned char* imageData, const vtkm::Id index)
|
||||
: Superclass(0)
|
||||
{
|
||||
ConstructPixelFromImage(imageData, index);
|
||||
}
|
||||
|
||||
virtual ~BasePixel() = default;
|
||||
|
||||
/// Calculates this difference between two pixels as a single value.
|
||||
///
|
||||
virtual ComponentType Diff(const BaseType& pixel) const = 0;
|
||||
|
||||
/// Generates a Vec4f_32 from the current data available in the pixel
|
||||
///
|
||||
virtual vtkm::Vec4f_32 ToVec4f() const = 0;
|
||||
|
||||
/// Implement the << operator for this class type. Will call the overloaded
|
||||
/// print method for the subclassed type.
|
||||
///
|
||||
friend std::ostream& operator<<(std::ostream& os, const BaseType& basePixel)
|
||||
{
|
||||
basePixel.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/// Takes an output imageData pointer and in index to a location in that dataset
|
||||
/// and fills in the pixel data at the location. Utilizes BIT_DEPTH and
|
||||
/// NUM_CHANNELS to fill in multiple bytes worth of data if necessary.
|
||||
///
|
||||
void FillImageAtIndexWithPixel(unsigned char* imageData, const vtkm::Id index);
|
||||
|
||||
protected:
|
||||
/// Takes an input imageData pointer and an index to a location in that dataset
|
||||
/// and fills in this->Components correctly using the provided BIT_DEPTH and
|
||||
/// NUM_CHANNELS. Does NOT 0 out the current Components.
|
||||
///
|
||||
void ConstructPixelFromImage(const unsigned char* imageData, const vtkm::Id index);
|
||||
|
||||
virtual void print(std::ostream& os) const = 0;
|
||||
};
|
||||
|
||||
|
||||
template <const vtkm::Id BitDepth>
|
||||
class RGBPixel : public BasePixel<BitDepth, 3>
|
||||
{
|
||||
public:
|
||||
// RGB values are stored in a vtkm::Vec<ComponentType, 3>
|
||||
using Superclass = BasePixel<BitDepth, 3>;
|
||||
using ComponentType = typename Superclass::ComponentType;
|
||||
static constexpr vtkm::png::LodePNGColorType PNG_COLOR_TYPE =
|
||||
vtkm::png::LodePNGColorType::LCT_RGB;
|
||||
|
||||
using Superclass::Superclass;
|
||||
RGBPixel() = default;
|
||||
RGBPixel(vtkm::Vec4f_32 tuple)
|
||||
: Superclass(static_cast<ComponentType>(tuple[0] * this->MAX_COLOR_VALUE),
|
||||
static_cast<ComponentType>(tuple[1] * this->MAX_COLOR_VALUE),
|
||||
static_cast<ComponentType>(tuple[2] * this->MAX_COLOR_VALUE))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~RGBPixel() = default;
|
||||
|
||||
ComponentType Diff(const Superclass& pixel) const override;
|
||||
vtkm::Vec4f_32 ToVec4f() const override;
|
||||
|
||||
protected:
|
||||
void print(std::ostream& os) const override
|
||||
{
|
||||
os << "(" << (int)this->Components[0] << "," << (int)this->Components[1] << ","
|
||||
<< (int)this->Components[2] << ")";
|
||||
}
|
||||
};
|
||||
|
||||
// Default types for 8 and 16 bit RGB pixels
|
||||
using RGBPixel_8 = RGBPixel<8>;
|
||||
using RGBPixel_16 = RGBPixel<16>;
|
||||
|
||||
template <const vtkm::Id BitDepth>
|
||||
class GreyPixel : public BasePixel<BitDepth, 1>
|
||||
{
|
||||
public:
|
||||
// Grey values are stored in a vtkm::Vec<ComponentType, 1>
|
||||
// Note: A vec of size 1 is used instead of just a `ComponentType`
|
||||
// in order to simplify the pixel helper functions
|
||||
using Superclass = BasePixel<BitDepth, 1>;
|
||||
using ComponentType = typename Superclass::ComponentType;
|
||||
static constexpr vtkm::png::LodePNGColorType PNG_COLOR_TYPE =
|
||||
vtkm::png::LodePNGColorType::LCT_GREY;
|
||||
|
||||
using Superclass::Superclass;
|
||||
GreyPixel() = default;
|
||||
GreyPixel(vtkm::Vec4f_32 tuple)
|
||||
: Superclass(
|
||||
static_cast<ComponentType>((tuple[0] + tuple[1] + tuple[2]) * this->MAX_COLOR_VALUE / 3))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~GreyPixel() = default;
|
||||
|
||||
ComponentType Diff(const Superclass& pixel) const override;
|
||||
vtkm::Vec4f_32 ToVec4f() const override;
|
||||
|
||||
protected:
|
||||
void print(std::ostream& os) const override { os << "(" << (int)this->Components[0] << ")"; }
|
||||
};
|
||||
|
||||
// Default types for 8 and 16 bit Grey pixels
|
||||
using GreyPixel_16 = GreyPixel<16>;
|
||||
using GreyPixel_8 = GreyPixel<8>;
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#include <vtkm/io/PixelTypes.hxx>
|
||||
|
||||
#endif //vtk_m_io_PixelTypes_h
|
85
vtkm/io/PixelTypes.hxx
Normal file
85
vtkm/io/PixelTypes.hxx
Normal file
@ -0,0 +1,85 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_io_PixelTypes_hxx
|
||||
#define vtk_m_io_PixelTypes_hxx
|
||||
|
||||
#include <vtkm/Math.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
template <const vtkm::Id B, const vtkm::IdComponent C>
|
||||
void BasePixel<B, C>::FillImageAtIndexWithPixel(unsigned char* imageData, const vtkm::Id index)
|
||||
{
|
||||
vtkm::Id initShift = BIT_DEPTH - 8;
|
||||
for (vtkm::Id channel = 0; channel < NUM_CHANNELS; channel++)
|
||||
{
|
||||
for (vtkm::Id shift = initShift, i = 0; shift >= 0; shift -= 8, i++)
|
||||
{
|
||||
imageData[index * BYTES_PER_PIXEL + i + (channel * NUM_BYTES)] =
|
||||
static_cast<unsigned char>((this->Components[channel] & (0xff << shift)) >> shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <const vtkm::Id B, const vtkm::IdComponent C>
|
||||
void BasePixel<B, C>::ConstructPixelFromImage(const unsigned char* imageData, const vtkm::Id index)
|
||||
{
|
||||
vtkm::Id initShift = BIT_DEPTH - 8;
|
||||
for (vtkm::Id channel = 0; channel < NUM_CHANNELS; channel++)
|
||||
{
|
||||
for (vtkm::Id shift = initShift, i = 0; shift >= 0; shift -= 8, i++)
|
||||
{
|
||||
this->Components[channel] |= imageData[index * BYTES_PER_PIXEL + i + (channel * NUM_BYTES)]
|
||||
<< shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <const vtkm::Id B>
|
||||
typename RGBPixel<B>::ComponentType RGBPixel<B>::Diff(const Superclass& pixel) const
|
||||
{
|
||||
return static_cast<RGBPixel<B>::ComponentType>(vtkm::Abs(this->Components[0] - pixel[0]) +
|
||||
vtkm::Abs(this->Components[1] - pixel[1]) +
|
||||
vtkm::Abs(this->Components[2] - pixel[2]));
|
||||
}
|
||||
|
||||
template <const vtkm::Id B>
|
||||
vtkm::Vec4f_32 RGBPixel<B>::ToVec4f() const
|
||||
{
|
||||
return vtkm::Vec4f_32(static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
|
||||
static_cast<vtkm::Float32>(this->Components[1]) / this->MAX_COLOR_VALUE,
|
||||
static_cast<vtkm::Float32>(this->Components[2]) / this->MAX_COLOR_VALUE,
|
||||
1);
|
||||
}
|
||||
|
||||
template <const vtkm::Id B>
|
||||
typename GreyPixel<B>::ComponentType GreyPixel<B>::Diff(const Superclass& pixel) const
|
||||
{
|
||||
return static_cast<GreyPixel<B>::ComponentType>(vtkm::Abs(this->Components[0] - pixel[0]));
|
||||
}
|
||||
|
||||
template <const vtkm::Id B>
|
||||
vtkm::Vec4f_32 GreyPixel<B>::ToVec4f() const
|
||||
{
|
||||
return vtkm::Vec4f_32(static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
|
||||
static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
|
||||
static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
|
||||
1);
|
||||
}
|
||||
|
||||
|
||||
} // namespace io
|
||||
} // namespace vtkm
|
||||
|
||||
#endif //vtk_m_io_PixelTypes_h
|
92
vtkm/io/VTKDataSetReader.cxx
Normal file
92
vtkm/io/VTKDataSetReader.cxx
Normal file
@ -0,0 +1,92 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKDataSetReader.h>
|
||||
|
||||
#include <vtkm/io/VTKPolyDataReader.h>
|
||||
#include <vtkm/io/VTKRectilinearGridReader.h>
|
||||
#include <vtkm/io/VTKStructuredGridReader.h>
|
||||
#include <vtkm/io/VTKStructuredPointsReader.h>
|
||||
#include <vtkm/io/VTKUnstructuredGridReader.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKDataSetReader::VTKDataSetReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKDataSetReader::VTKDataSetReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKDataSetReader::~VTKDataSetReader()
|
||||
{
|
||||
}
|
||||
|
||||
void VTKDataSetReader::PrintSummary(std::ostream& out) const
|
||||
{
|
||||
if (this->Reader)
|
||||
{
|
||||
this->Reader->PrintSummary(out);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKDataSetReaderBase::PrintSummary(out);
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReader::CloseFile()
|
||||
{
|
||||
if (this->Reader)
|
||||
{
|
||||
this->Reader->CloseFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKDataSetReaderBase::CloseFile();
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReader::Read()
|
||||
{
|
||||
switch (this->DataFile->Structure)
|
||||
{
|
||||
case vtkm::io::internal::DATASET_STRUCTURED_POINTS:
|
||||
this->Reader.reset(new VTKStructuredPointsReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_STRUCTURED_GRID:
|
||||
this->Reader.reset(new VTKStructuredGridReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_RECTILINEAR_GRID:
|
||||
this->Reader.reset(new VTKRectilinearGridReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_POLYDATA:
|
||||
this->Reader.reset(new VTKPolyDataReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_UNSTRUCTURED_GRID:
|
||||
this->Reader.reset(new VTKUnstructuredGridReader(""));
|
||||
break;
|
||||
default:
|
||||
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
|
||||
}
|
||||
|
||||
this->TransferDataFile(*this->Reader.get());
|
||||
this->Reader->Read();
|
||||
this->DataSet = this->Reader->GetDataSet();
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -11,86 +11,27 @@
|
||||
#define vtk_m_io_VTKDataSetReader_h
|
||||
|
||||
#include <vtkm/io/VTKDataSetReaderBase.h>
|
||||
#include <vtkm/io/VTKPolyDataReader.h>
|
||||
#include <vtkm/io/VTKRectilinearGridReader.h>
|
||||
#include <vtkm/io/VTKStructuredGridReader.h>
|
||||
#include <vtkm/io/VTKStructuredPointsReader.h>
|
||||
#include <vtkm/io/VTKUnstructuredGridReader.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKDataSetReader : public VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKDataSetReader : public VTKDataSetReaderBase
|
||||
{
|
||||
public:
|
||||
explicit VTKDataSetReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
VTKM_CONT VTKDataSetReader(const char* fileName);
|
||||
VTKM_CONT VTKDataSetReader(const std::string& fileName);
|
||||
VTKM_CONT ~VTKDataSetReader() override;
|
||||
|
||||
explicit VTKDataSetReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
VTKDataSetReader(const VTKDataSetReader&) = delete;
|
||||
void operator=(const VTKDataSetReader&) = delete;
|
||||
|
||||
virtual void PrintSummary(std::ostream& out) const
|
||||
{
|
||||
if (this->Reader)
|
||||
{
|
||||
this->Reader->PrintSummary(out);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKDataSetReaderBase::PrintSummary(out);
|
||||
}
|
||||
}
|
||||
VTKM_CONT void PrintSummary(std::ostream& out) const override;
|
||||
|
||||
private:
|
||||
virtual void CloseFile()
|
||||
{
|
||||
if (this->Reader)
|
||||
{
|
||||
this->Reader->CloseFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKDataSetReaderBase::CloseFile();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Read()
|
||||
{
|
||||
switch (this->DataFile->Structure)
|
||||
{
|
||||
case vtkm::io::internal::DATASET_STRUCTURED_POINTS:
|
||||
this->Reader.reset(new VTKStructuredPointsReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_STRUCTURED_GRID:
|
||||
this->Reader.reset(new VTKStructuredGridReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_RECTILINEAR_GRID:
|
||||
this->Reader.reset(new VTKRectilinearGridReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_POLYDATA:
|
||||
this->Reader.reset(new VTKPolyDataReader(""));
|
||||
break;
|
||||
case vtkm::io::internal::DATASET_UNSTRUCTURED_GRID:
|
||||
this->Reader.reset(new VTKUnstructuredGridReader(""));
|
||||
break;
|
||||
default:
|
||||
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
|
||||
}
|
||||
|
||||
this->TransferDataFile(*this->Reader.get());
|
||||
this->Reader->Read();
|
||||
this->DataSet = this->Reader->GetDataSet();
|
||||
}
|
||||
VTKM_CONT void CloseFile() override;
|
||||
VTKM_CONT void Read() override;
|
||||
|
||||
std::unique_ptr<VTKDataSetReaderBase> Reader;
|
||||
};
|
||||
|
826
vtkm/io/VTKDataSetReaderBase.cxx
Normal file
826
vtkm/io/VTKDataSetReaderBase.cxx
Normal file
@ -0,0 +1,826 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKDataSetReaderBase.h>
|
||||
|
||||
#include <vtkm/VecTraits.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
#include <vtkm/cont/Logging.h>
|
||||
#include <vtkm/cont/VariantArrayHandle.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline void PrintVTKDataFileSummary(const vtkm::io::internal::VTKDataSetFile& df, std::ostream& out)
|
||||
{
|
||||
out << "\tFile: " << df.FileName << std::endl;
|
||||
out << "\tVersion: " << df.Version[0] << "." << df.Version[0] << std::endl;
|
||||
out << "\tTitle: " << df.Title << std::endl;
|
||||
out << "\tFormat: " << (df.IsBinary ? "BINARY" : "ASCII") << std::endl;
|
||||
out << "\tDataSet type: " << vtkm::io::internal::DataSetStructureString(df.Structure)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Since Fields and DataSets store data in the default VariantArrayHandle, convert
|
||||
// the data to the closest type supported by default. The following will
|
||||
// need to be updated if VariantArrayHandle or TypeListCommon changes.
|
||||
template <typename T>
|
||||
struct ClosestCommonType
|
||||
{
|
||||
using Type = T;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::Int8>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt8>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::Int16>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt16>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt32>
|
||||
{
|
||||
using Type = vtkm::Int64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt64>
|
||||
{
|
||||
using Type = vtkm::Int64;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ClosestFloat
|
||||
{
|
||||
using Type = T;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int8>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt8>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int16>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt16>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int32>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt32>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int64>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt64>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
vtkm::cont::VariantArrayHandle CreateVariantArrayHandle(const std::vector<T>& vec)
|
||||
{
|
||||
switch (vtkm::VecTraits<T>::NUM_COMPONENTS)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
using CommonType = typename ClosestCommonType<T>::Type;
|
||||
constexpr bool not_same = !std::is_same<T, CommonType>::value;
|
||||
if (not_same)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Type " << vtkm::io::internal::DataTypeName<T>::Name()
|
||||
<< " is currently unsupported. Converting to "
|
||||
<< vtkm::io::internal::DataTypeName<CommonType>::Name()
|
||||
<< ".");
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<CommonType> output;
|
||||
output.Allocate(static_cast<vtkm::Id>(vec.size()));
|
||||
auto portal = output.WritePortal();
|
||||
for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i)
|
||||
{
|
||||
portal.Set(i, static_cast<CommonType>(vec[static_cast<std::size_t>(i)]));
|
||||
}
|
||||
|
||||
return vtkm::cont::VariantArrayHandle(output);
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
case 9:
|
||||
{
|
||||
constexpr auto numComps = vtkm::VecTraits<T>::NUM_COMPONENTS;
|
||||
|
||||
using InComponentType = typename vtkm::VecTraits<T>::ComponentType;
|
||||
using OutComponentType = typename ClosestFloat<InComponentType>::Type;
|
||||
using CommonType = vtkm::Vec<OutComponentType, numComps>;
|
||||
constexpr bool not_same = !std::is_same<T, CommonType>::value;
|
||||
if (not_same)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Type " << vtkm::io::internal::DataTypeName<InComponentType>::Name() << "["
|
||||
<< vtkm::VecTraits<T>::GetNumberOfComponents(T())
|
||||
<< "] "
|
||||
<< "is currently unsupported. Converting to "
|
||||
<< vtkm::io::internal::DataTypeName<OutComponentType>::Name()
|
||||
<< "["
|
||||
<< numComps
|
||||
<< "].");
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<CommonType> output;
|
||||
output.Allocate(static_cast<vtkm::Id>(vec.size()));
|
||||
auto portal = output.WritePortal();
|
||||
for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i)
|
||||
{
|
||||
CommonType outval = CommonType();
|
||||
for (vtkm::IdComponent j = 0; j < numComps; ++j)
|
||||
{
|
||||
outval[j] = static_cast<OutComponentType>(
|
||||
vtkm::VecTraits<T>::GetComponent(vec[static_cast<std::size_t>(i)], j));
|
||||
}
|
||||
portal.Set(i, outval);
|
||||
}
|
||||
|
||||
return vtkm::cont::VariantArrayHandle(output);
|
||||
}
|
||||
default:
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Only 1, 2, 3, or 9 components supported. Skipping.");
|
||||
return vtkm::cont::VariantArrayHandle(vtkm::cont::ArrayHandle<vtkm::Float32>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKDataSetReaderBase::VTKDataSetReaderBase(const char* fileName)
|
||||
: DataFile(new internal::VTKDataSetFile)
|
||||
, DataSet()
|
||||
, Loaded(false)
|
||||
{
|
||||
this->DataFile->FileName = fileName;
|
||||
}
|
||||
|
||||
VTKDataSetReaderBase::VTKDataSetReaderBase(const std::string& fileName)
|
||||
: DataFile(new internal::VTKDataSetFile)
|
||||
, DataSet()
|
||||
, Loaded(false)
|
||||
{
|
||||
this->DataFile->FileName = fileName;
|
||||
}
|
||||
|
||||
VTKDataSetReaderBase::~VTKDataSetReaderBase()
|
||||
{
|
||||
}
|
||||
|
||||
const vtkm::cont::DataSet& VTKDataSetReaderBase::ReadDataSet()
|
||||
{
|
||||
if (!this->Loaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->OpenFile();
|
||||
this->ReadHeader();
|
||||
this->Read();
|
||||
this->CloseFile();
|
||||
this->Loaded = true;
|
||||
}
|
||||
catch (std::ifstream::failure& e)
|
||||
{
|
||||
std::string message("IO Error: ");
|
||||
throw vtkm::io::ErrorIO(message + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return this->DataSet;
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::PrintSummary(std::ostream& out) const
|
||||
{
|
||||
out << "VTKDataSetReader" << std::endl;
|
||||
PrintVTKDataFileSummary(*this->DataFile.get(), out);
|
||||
this->DataSet.PrintSummary(out);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadPoints()
|
||||
{
|
||||
std::string dataType;
|
||||
std::size_t numPoints;
|
||||
this->DataFile->Stream >> numPoints >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle points =
|
||||
this->DoReadArrayVariant(vtkm::cont::Field::Association::POINTS, dataType, numPoints, 3);
|
||||
|
||||
this->DataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", points));
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices)
|
||||
{
|
||||
vtkm::Id numCells, numInts;
|
||||
this->DataFile->Stream >> numCells >> numInts >> std::ws;
|
||||
|
||||
connectivity.Allocate(numInts - numCells);
|
||||
numIndices.Allocate(numCells);
|
||||
|
||||
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numInts));
|
||||
this->ReadArray(buffer);
|
||||
|
||||
vtkm::Int32* buffp = &buffer[0];
|
||||
auto connectivityPortal = connectivity.WritePortal();
|
||||
auto numIndicesPortal = numIndices.WritePortal();
|
||||
for (vtkm::Id i = 0, connInd = 0; i < numCells; ++i)
|
||||
{
|
||||
vtkm::IdComponent numInds = static_cast<vtkm::IdComponent>(*buffp++);
|
||||
numIndicesPortal.Set(i, numInds);
|
||||
for (vtkm::IdComponent j = 0; j < numInds; ++j, ++connInd)
|
||||
{
|
||||
connectivityPortal.Set(connInd, static_cast<vtkm::Id>(*buffp++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadShapes(vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes)
|
||||
{
|
||||
std::string tag;
|
||||
vtkm::Id numCells;
|
||||
this->DataFile->Stream >> tag >> numCells >> std::ws;
|
||||
internal::parseAssert(tag == "CELL_TYPES");
|
||||
|
||||
shapes.Allocate(numCells);
|
||||
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numCells));
|
||||
this->ReadArray(buffer);
|
||||
|
||||
vtkm::Int32* buffp = &buffer[0];
|
||||
auto shapesPortal = shapes.WritePortal();
|
||||
for (vtkm::Id i = 0; i < numCells; ++i)
|
||||
{
|
||||
shapesPortal.Set(i, static_cast<vtkm::UInt8>(*buffp++));
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadAttributes()
|
||||
{
|
||||
if (this->DataFile->Stream.eof())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY;
|
||||
std::size_t size;
|
||||
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
while (!this->DataFile->Stream.eof())
|
||||
{
|
||||
if (tag == "POINT_DATA")
|
||||
{
|
||||
association = vtkm::cont::Field::Association::POINTS;
|
||||
}
|
||||
else if (tag == "CELL_DATA")
|
||||
{
|
||||
association = vtkm::cont::Field::Association::CELL_SET;
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::parseAssert(false);
|
||||
}
|
||||
|
||||
this->DataFile->Stream >> size;
|
||||
while (!this->DataFile->Stream.eof())
|
||||
{
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "SCALARS")
|
||||
{
|
||||
this->ReadScalars(association, size);
|
||||
}
|
||||
else if (tag == "COLOR_SCALARS")
|
||||
{
|
||||
this->ReadColorScalars(association, size);
|
||||
}
|
||||
else if (tag == "LOOKUP_TABLE")
|
||||
{
|
||||
this->ReadLookupTable();
|
||||
}
|
||||
else if (tag == "VECTORS" || tag == "NORMALS")
|
||||
{
|
||||
this->ReadVectors(association, size);
|
||||
}
|
||||
else if (tag == "TEXTURE_COORDINATES")
|
||||
{
|
||||
this->ReadTextureCoordinates(association, size);
|
||||
}
|
||||
else if (tag == "TENSORS")
|
||||
{
|
||||
this->ReadTensors(association, size);
|
||||
}
|
||||
else if (tag == "FIELD")
|
||||
{
|
||||
this->ReadFields(association, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::CloseFile()
|
||||
{
|
||||
this->DataFile->Stream.close();
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::OpenFile()
|
||||
{
|
||||
this->DataFile->Stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
try
|
||||
{
|
||||
this->DataFile->Stream.open(this->DataFile->FileName.c_str(),
|
||||
std::ios_base::in | std::ios_base::binary);
|
||||
}
|
||||
catch (std::ifstream::failure&)
|
||||
{
|
||||
std::string message("could not open file \"" + this->DataFile->FileName + "\"");
|
||||
throw vtkm::io::ErrorIO(message);
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadHeader()
|
||||
{
|
||||
char vstring[] = "# vtk DataFile Version";
|
||||
const std::size_t vlen = sizeof(vstring);
|
||||
|
||||
// Read version line
|
||||
char vbuf[vlen];
|
||||
this->DataFile->Stream.read(vbuf, vlen - 1);
|
||||
vbuf[vlen - 1] = '\0';
|
||||
if (std::string(vbuf) != std::string(vstring))
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect file format.");
|
||||
}
|
||||
|
||||
char dot;
|
||||
this->DataFile->Stream >> this->DataFile->Version[0] >> dot >> this->DataFile->Version[1];
|
||||
// skip rest of the line
|
||||
std::string skip;
|
||||
std::getline(this->DataFile->Stream, skip);
|
||||
|
||||
if ((this->DataFile->Version[0] > 4) ||
|
||||
(this->DataFile->Version[0] == 4 && this->DataFile->Version[1] > 2))
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Reader may not correctly read >v4.2 files. Reading version "
|
||||
<< this->DataFile->Version[0]
|
||||
<< "."
|
||||
<< this->DataFile->Version[1]
|
||||
<< ".\n");
|
||||
}
|
||||
|
||||
// Read title line
|
||||
std::getline(this->DataFile->Stream, this->DataFile->Title);
|
||||
|
||||
// Read format line
|
||||
this->DataFile->IsBinary = false;
|
||||
std::string format;
|
||||
this->DataFile->Stream >> format >> std::ws;
|
||||
if (format == "BINARY")
|
||||
{
|
||||
this->DataFile->IsBinary = true;
|
||||
}
|
||||
else if (format != "ASCII")
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Unsupported Format.");
|
||||
}
|
||||
|
||||
// Read structure line
|
||||
std::string tag, structStr;
|
||||
this->DataFile->Stream >> tag >> structStr >> std::ws;
|
||||
internal::parseAssert(tag == "DATASET");
|
||||
|
||||
this->DataFile->Structure = vtkm::io::internal::DataSetStructureId(structStr);
|
||||
if (this->DataFile->Structure == vtkm::io::internal::DATASET_UNKNOWN)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VTKDataSetReaderBase::AddField(const std::string& name,
|
||||
vtkm::cont::Field::Association association,
|
||||
vtkm::cont::VariantArrayHandle& data)
|
||||
{
|
||||
if (data.GetNumberOfValues() > 0)
|
||||
{
|
||||
switch (association)
|
||||
{
|
||||
case vtkm::cont::Field::Association::POINTS:
|
||||
case vtkm::cont::Field::Association::WHOLE_MESH:
|
||||
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
|
||||
break;
|
||||
case vtkm::cont::Field::Association::CELL_SET:
|
||||
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
|
||||
break;
|
||||
default:
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Not recording field '" << name << "' because it has an unknown association");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadScalars(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements)
|
||||
{
|
||||
std::string dataName, dataType, lookupTableName;
|
||||
vtkm::IdComponent numComponents = 1;
|
||||
this->DataFile->Stream >> dataName >> dataType;
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag != "LOOKUP_TABLE")
|
||||
{
|
||||
try
|
||||
{
|
||||
numComponents = std::stoi(tag);
|
||||
}
|
||||
catch (std::invalid_argument&)
|
||||
{
|
||||
internal::parseAssert(false);
|
||||
}
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
internal::parseAssert(tag == "LOOKUP_TABLE");
|
||||
this->DataFile->Stream >> lookupTableName >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadColorScalars(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Support for COLOR_SCALARS is not implemented. Skipping.");
|
||||
|
||||
std::string dataName;
|
||||
vtkm::IdComponent numComponents;
|
||||
this->DataFile->Stream >> dataName >> numComponents >> std::ws;
|
||||
std::string dataType = this->DataFile->IsBinary ? "unsigned_char" : "float";
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadLookupTable()
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Support for LOOKUP_TABLE is not implemented. Skipping.");
|
||||
|
||||
std::string dataName;
|
||||
std::size_t numEntries;
|
||||
this->DataFile->Stream >> dataName >> numEntries >> std::ws;
|
||||
this->SkipArray(numEntries, vtkm::Vec<vtkm::io::internal::ColorChannel8, 4>());
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadTextureCoordinates(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements)
|
||||
{
|
||||
std::string dataName;
|
||||
vtkm::IdComponent numComponents;
|
||||
std::string dataType;
|
||||
this->DataFile->Stream >> dataName >> numComponents >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadVectors(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements)
|
||||
{
|
||||
std::string dataName;
|
||||
std::string dataType;
|
||||
this->DataFile->Stream >> dataName >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, 3);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadTensors(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements)
|
||||
{
|
||||
std::string dataName;
|
||||
std::string dataType;
|
||||
this->DataFile->Stream >> dataName >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, 9);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadFields(vtkm::cont::Field::Association association,
|
||||
std::size_t expectedNumElements)
|
||||
{
|
||||
std::string dataName;
|
||||
vtkm::Id numArrays;
|
||||
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
|
||||
for (vtkm::Id i = 0; i < numArrays; ++i)
|
||||
{
|
||||
std::size_t numTuples;
|
||||
vtkm::IdComponent numComponents;
|
||||
std::string arrayName, dataType;
|
||||
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
|
||||
if (numTuples == expectedNumElements)
|
||||
{
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numTuples, numComponents);
|
||||
this->AddField(arrayName, association, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Field " << arrayName
|
||||
<< "'s size does not match expected number of elements. Skipping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadGlobalFields(std::vector<vtkm::Float32>* visitBounds)
|
||||
{
|
||||
std::string dataName;
|
||||
vtkm::Id numArrays;
|
||||
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
|
||||
for (vtkm::Id i = 0; i < numArrays; ++i)
|
||||
{
|
||||
std::size_t numTuples;
|
||||
vtkm::IdComponent numComponents;
|
||||
std::string arrayName, dataType;
|
||||
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
|
||||
if (arrayName == "avtOriginalBounds" && visitBounds)
|
||||
{
|
||||
visitBounds->resize(6);
|
||||
internal::parseAssert(numComponents == 1 && numTuples == 6);
|
||||
// parse the bounds and fill the bounds vector
|
||||
this->ReadArray(*visitBounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Support for global field " << arrayName << " not implemented. Skipping.");
|
||||
this->DoSkipArrayVariant(dataType, numTuples, numComponents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VTKDataSetReaderBase::SkipArrayVariant
|
||||
{
|
||||
public:
|
||||
SkipArrayVariant(VTKDataSetReaderBase* reader, std::size_t numElements)
|
||||
: Reader(reader)
|
||||
, NumElements(numElements)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(T) const
|
||||
{
|
||||
this->Reader->SkipArray(this->NumElements, T());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(vtkm::IdComponent numComponents, T) const
|
||||
{
|
||||
this->Reader->SkipArray(this->NumElements * static_cast<std::size_t>(numComponents), T());
|
||||
}
|
||||
|
||||
protected:
|
||||
VTKDataSetReaderBase* Reader;
|
||||
std::size_t NumElements;
|
||||
};
|
||||
|
||||
class VTKDataSetReaderBase::ReadArrayVariant : public SkipArrayVariant
|
||||
{
|
||||
public:
|
||||
ReadArrayVariant(VTKDataSetReaderBase* reader,
|
||||
vtkm::cont::Field::Association association,
|
||||
std::size_t numElements,
|
||||
vtkm::cont::VariantArrayHandle& data)
|
||||
: SkipArrayVariant(reader, numElements)
|
||||
, Association(association)
|
||||
, Data(&data)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(T) const
|
||||
{
|
||||
std::vector<T> buffer(this->NumElements);
|
||||
this->Reader->ReadArray(buffer);
|
||||
if ((this->Association != vtkm::cont::Field::Association::CELL_SET) ||
|
||||
(this->Reader->GetCellsPermutation().GetNumberOfValues() < 1))
|
||||
{
|
||||
*this->Data = CreateVariantArrayHandle(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are reading data associated with a cell set, we need to (sometimes) permute the
|
||||
// data due to differences between VTK and VTK-m cell shapes.
|
||||
auto permutation = this->Reader->GetCellsPermutation().ReadPortal();
|
||||
vtkm::Id outSize = permutation.GetNumberOfValues();
|
||||
std::vector<T> permutedBuffer(static_cast<std::size_t>(outSize));
|
||||
for (vtkm::Id outIndex = 0; outIndex < outSize; outIndex++)
|
||||
{
|
||||
std::size_t inIndex = static_cast<std::size_t>(permutation.Get(outIndex));
|
||||
permutedBuffer[static_cast<std::size_t>(outIndex)] = buffer[inIndex];
|
||||
}
|
||||
*this->Data = CreateVariantArrayHandle(permutedBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(vtkm::IdComponent numComponents, T) const
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for " << numComponents << " components not implemented. Skipping.");
|
||||
SkipArrayVariant::operator()(numComponents, T());
|
||||
}
|
||||
|
||||
private:
|
||||
vtkm::cont::Field::Association Association;
|
||||
vtkm::cont::VariantArrayHandle* Data;
|
||||
};
|
||||
|
||||
void VTKDataSetReaderBase::DoSkipArrayVariant(std::string dataType,
|
||||
std::size_t numElements,
|
||||
vtkm::IdComponent numComponents)
|
||||
{
|
||||
// string is unsupported for SkipArrayVariant, so it requires some
|
||||
// special handling
|
||||
if (dataType == "string")
|
||||
{
|
||||
const vtkm::Id stringCount = numComponents * static_cast<vtkm::Id>(numElements);
|
||||
for (vtkm::Id i = 0; i < stringCount; ++i)
|
||||
{
|
||||
std::string trash;
|
||||
this->DataFile->Stream >> trash;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
|
||||
vtkm::io::internal::SelectTypeAndCall(
|
||||
typeId, numComponents, SkipArrayVariant(this, numElements));
|
||||
}
|
||||
}
|
||||
|
||||
vtkm::cont::VariantArrayHandle VTKDataSetReaderBase::DoReadArrayVariant(
|
||||
vtkm::cont::Field::Association association,
|
||||
std::string dataType,
|
||||
std::size_t numElements,
|
||||
vtkm::IdComponent numComponents)
|
||||
{
|
||||
// Create empty data to start so that the return can check if data were actually read
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> empty;
|
||||
vtkm::cont::VariantArrayHandle data(empty);
|
||||
|
||||
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
|
||||
vtkm::io::internal::SelectTypeAndCall(
|
||||
typeId, numComponents, ReadArrayVariant(this, association, numElements, data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::ReadArray(std::vector<vtkm::io::internal::DummyBitType>& buffer)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for data type 'bit' is not implemented. Skipping.");
|
||||
this->SkipArray(buffer.size(), vtkm::io::internal::DummyBitType());
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::SkipArray(std::size_t numElements,
|
||||
vtkm::io::internal::DummyBitType,
|
||||
vtkm::IdComponent numComponents)
|
||||
{
|
||||
if (this->DataFile->IsBinary)
|
||||
{
|
||||
numElements = (numElements + 7) / 8;
|
||||
this->DataFile->Stream.seekg(static_cast<std::streamoff>(numElements), std::ios_base::cur);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < numElements; ++i)
|
||||
{
|
||||
vtkm::UInt16 val;
|
||||
this->DataFile->Stream >> val;
|
||||
}
|
||||
}
|
||||
this->DataFile->Stream >> std::ws;
|
||||
this->SkipArrayMetaData(numComponents);
|
||||
}
|
||||
|
||||
void VTKDataSetReaderBase::SkipArrayMetaData(vtkm::IdComponent numComponents)
|
||||
{
|
||||
if (!this->DataFile->Stream.good())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto begining = this->DataFile->Stream.tellg();
|
||||
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag != "METADATA")
|
||||
{
|
||||
this->DataFile->Stream.seekg(begining);
|
||||
return;
|
||||
}
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "METADATA is not supported. Attempting to Skip.");
|
||||
|
||||
this->DataFile->Stream >> tag >> std::ws;
|
||||
if (tag == "COMPONENT_NAMES")
|
||||
{
|
||||
std::string name;
|
||||
for (vtkm::IdComponent i = 0; i < numComponents; ++i)
|
||||
{
|
||||
this->DataFile->Stream >> name >> std::ws;
|
||||
}
|
||||
}
|
||||
else if (tag == "INFORMATION")
|
||||
{
|
||||
int numKeys = 0;
|
||||
this->DataFile->Stream >> numKeys >> std::ws;
|
||||
|
||||
// Skipping INFORMATION is tricky. The reader needs to be aware of the types of the
|
||||
// information, which is not provided in the file.
|
||||
// Here we will just skip until an empty line is found.
|
||||
// However, if there are no keys, then there is nothing to read (and the stream tends
|
||||
// to skip over empty lines.
|
||||
if (numKeys > 0)
|
||||
{
|
||||
std::string line;
|
||||
do
|
||||
{
|
||||
std::getline(this->DataFile->Stream, line);
|
||||
} while (this->DataFile->Stream.good() && !line.empty());
|
||||
|
||||
// Eat any remaining whitespace after the INFORMATION to be ready to read the next token
|
||||
this->DataFile->Stream >> std::ws;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::parseAssert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -10,25 +10,16 @@
|
||||
#ifndef vtk_m_io_VTKDataSetReaderBase_h
|
||||
#define vtk_m_io_VTKDataSetReaderBase_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
#include <vtkm/io/vtkm_io_export.h>
|
||||
|
||||
#include <vtkm/io/internal/Endian.h>
|
||||
#include <vtkm/io/internal/VTKDataSetCells.h>
|
||||
#include <vtkm/io/internal/VTKDataSetStructures.h>
|
||||
#include <vtkm/io/internal/VTKDataSetTypes.h>
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/cont/Logging.h>
|
||||
#include <vtkm/cont/VariantArrayHandle.h>
|
||||
#include <vtkm/internal/ExportMacros.h>
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -48,16 +39,6 @@ struct VTKDataSetFile
|
||||
std::ifstream Stream;
|
||||
};
|
||||
|
||||
inline void PrintVTKDataFileSummary(const VTKDataSetFile& df, std::ostream& out)
|
||||
{
|
||||
out << "\tFile: " << df.FileName << std::endl;
|
||||
out << "\tVersion: " << df.Version[0] << "." << df.Version[0] << std::endl;
|
||||
out << "\tTitle: " << df.Title << std::endl;
|
||||
out << "\tFormat: " << (df.IsBinary ? "BINARY" : "ASCII") << std::endl;
|
||||
out << "\tDataSet type: " << vtkm::io::internal::DataSetStructureString(df.Structure)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
inline void parseAssert(bool condition)
|
||||
{
|
||||
if (!condition)
|
||||
@ -82,166 +63,6 @@ struct StreamIOType<vtkm::UInt8>
|
||||
using Type = vtkm::UInt16;
|
||||
};
|
||||
|
||||
// Since Fields and DataSets store data in the default VariantArrayHandle, convert
|
||||
// the data to the closest type supported by default. The following will
|
||||
// need to be updated if VariantArrayHandle or TypeListCommon changes.
|
||||
template <typename T>
|
||||
struct ClosestCommonType
|
||||
{
|
||||
using Type = T;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::Int8>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt8>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::Int16>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt16>
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt32>
|
||||
{
|
||||
using Type = vtkm::Int64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestCommonType<vtkm::UInt64>
|
||||
{
|
||||
using Type = vtkm::Int64;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ClosestFloat
|
||||
{
|
||||
using Type = T;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int8>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt8>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int16>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt16>
|
||||
{
|
||||
using Type = vtkm::Float32;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int32>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt32>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::Int64>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
template <>
|
||||
struct ClosestFloat<vtkm::UInt64>
|
||||
{
|
||||
using Type = vtkm::Float64;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
vtkm::cont::VariantArrayHandle CreateVariantArrayHandle(const std::vector<T>& vec)
|
||||
{
|
||||
switch (vtkm::VecTraits<T>::NUM_COMPONENTS)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
using CommonType = typename ClosestCommonType<T>::Type;
|
||||
constexpr bool not_same = !std::is_same<T, CommonType>::value;
|
||||
if (not_same)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Type " << vtkm::io::internal::DataTypeName<T>::Name()
|
||||
<< " is currently unsupported. Converting to "
|
||||
<< vtkm::io::internal::DataTypeName<CommonType>::Name()
|
||||
<< ".");
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<CommonType> output;
|
||||
output.Allocate(static_cast<vtkm::Id>(vec.size()));
|
||||
auto portal = output.WritePortal();
|
||||
for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i)
|
||||
{
|
||||
portal.Set(i, static_cast<CommonType>(vec[static_cast<std::size_t>(i)]));
|
||||
}
|
||||
|
||||
return vtkm::cont::VariantArrayHandle(output);
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
case 9:
|
||||
{
|
||||
constexpr auto numComps = vtkm::VecTraits<T>::NUM_COMPONENTS;
|
||||
|
||||
using InComponentType = typename vtkm::VecTraits<T>::ComponentType;
|
||||
using OutComponentType = typename ClosestFloat<InComponentType>::Type;
|
||||
using CommonType = vtkm::Vec<OutComponentType, numComps>;
|
||||
constexpr bool not_same = !std::is_same<T, CommonType>::value;
|
||||
if (not_same)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Type " << vtkm::io::internal::DataTypeName<InComponentType>::Name() << "["
|
||||
<< vtkm::VecTraits<T>::GetNumberOfComponents(T())
|
||||
<< "] "
|
||||
<< "is currently unsupported. Converting to "
|
||||
<< vtkm::io::internal::DataTypeName<OutComponentType>::Name()
|
||||
<< "["
|
||||
<< numComps
|
||||
<< "].");
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<CommonType> output;
|
||||
output.Allocate(static_cast<vtkm::Id>(vec.size()));
|
||||
auto portal = output.WritePortal();
|
||||
for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i)
|
||||
{
|
||||
CommonType outval = CommonType();
|
||||
for (vtkm::IdComponent j = 0; j < numComps; ++j)
|
||||
{
|
||||
outval[j] = static_cast<OutComponentType>(
|
||||
vtkm::VecTraits<T>::GetComponent(vec[static_cast<std::size_t>(i)], j));
|
||||
}
|
||||
portal.Set(i, outval);
|
||||
}
|
||||
|
||||
return vtkm::cont::VariantArrayHandle(output);
|
||||
}
|
||||
default:
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Only 1, 2, 3, or 9 components supported. Skipping.");
|
||||
return vtkm::cont::VariantArrayHandle(vtkm::cont::ArrayHandle<vtkm::Float32>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline vtkm::cont::DynamicCellSet CreateCellSetStructured(const vtkm::Id3& dim)
|
||||
{
|
||||
if (dim[0] > 1 && dim[1] > 1 && dim[2] > 1)
|
||||
@ -272,564 +93,102 @@ inline vtkm::cont::DynamicCellSet CreateCellSetStructured(const vtkm::Id3& dim)
|
||||
|
||||
} // namespace internal
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKDataSetReaderBase
|
||||
{
|
||||
protected:
|
||||
std::unique_ptr<internal::VTKDataSetFile> DataFile;
|
||||
vtkm::cont::DataSet DataSet;
|
||||
|
||||
private:
|
||||
bool Loaded;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> CellsPermutation;
|
||||
|
||||
friend class VTKDataSetReader;
|
||||
|
||||
public:
|
||||
explicit VTKDataSetReaderBase(const char* fileName)
|
||||
: DataFile(new internal::VTKDataSetFile)
|
||||
, DataSet()
|
||||
, Loaded(false)
|
||||
{
|
||||
this->DataFile->FileName = fileName;
|
||||
}
|
||||
explicit VTKM_CONT VTKDataSetReaderBase(const char* fileName);
|
||||
|
||||
explicit VTKDataSetReaderBase(const std::string& fileName)
|
||||
: DataFile(new internal::VTKDataSetFile)
|
||||
, DataSet()
|
||||
, Loaded(false)
|
||||
{
|
||||
this->DataFile->FileName = fileName;
|
||||
}
|
||||
explicit VTKM_CONT VTKDataSetReaderBase(const std::string& fileName);
|
||||
|
||||
virtual ~VTKDataSetReaderBase() {}
|
||||
virtual VTKM_CONT ~VTKDataSetReaderBase();
|
||||
|
||||
const vtkm::cont::DataSet& ReadDataSet()
|
||||
{
|
||||
if (!this->Loaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->OpenFile();
|
||||
this->ReadHeader();
|
||||
this->Read();
|
||||
this->CloseFile();
|
||||
this->Loaded = true;
|
||||
}
|
||||
catch (std::ifstream::failure& e)
|
||||
{
|
||||
std::string message("IO Error: ");
|
||||
throw vtkm::io::ErrorIO(message + e.what());
|
||||
}
|
||||
}
|
||||
VTKDataSetReaderBase(const VTKDataSetReaderBase&) = delete;
|
||||
void operator=(const VTKDataSetReaderBase&) = delete;
|
||||
|
||||
return this->DataSet;
|
||||
}
|
||||
const VTKM_CONT vtkm::cont::DataSet& ReadDataSet();
|
||||
|
||||
const vtkm::cont::DataSet& GetDataSet() const { return this->DataSet; }
|
||||
|
||||
virtual void PrintSummary(std::ostream& out) const
|
||||
{
|
||||
out << "VTKDataSetReader" << std::endl;
|
||||
PrintVTKDataFileSummary(*this->DataFile.get(), out);
|
||||
this->DataSet.PrintSummary(out);
|
||||
}
|
||||
virtual VTKM_CONT void PrintSummary(std::ostream& out) const;
|
||||
|
||||
protected:
|
||||
void ReadPoints()
|
||||
{
|
||||
std::string dataType;
|
||||
std::size_t numPoints;
|
||||
this->DataFile->Stream >> numPoints >> dataType >> std::ws;
|
||||
VTKM_CONT void ReadPoints();
|
||||
|
||||
vtkm::cont::VariantArrayHandle points =
|
||||
this->DoReadArrayVariant(vtkm::cont::Field::Association::POINTS, dataType, numPoints, 3);
|
||||
VTKM_CONT void ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices);
|
||||
|
||||
this->DataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", points));
|
||||
}
|
||||
VTKM_CONT void ReadShapes(vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes);
|
||||
|
||||
void ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices)
|
||||
{
|
||||
vtkm::Id numCells, numInts;
|
||||
this->DataFile->Stream >> numCells >> numInts >> std::ws;
|
||||
|
||||
connectivity.Allocate(numInts - numCells);
|
||||
numIndices.Allocate(numCells);
|
||||
|
||||
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numInts));
|
||||
this->ReadArray(buffer);
|
||||
|
||||
vtkm::Int32* buffp = &buffer[0];
|
||||
auto connectivityPortal = connectivity.WritePortal();
|
||||
auto numIndicesPortal = numIndices.WritePortal();
|
||||
for (vtkm::Id i = 0, connInd = 0; i < numCells; ++i)
|
||||
{
|
||||
vtkm::IdComponent numInds = static_cast<vtkm::IdComponent>(*buffp++);
|
||||
numIndicesPortal.Set(i, numInds);
|
||||
for (vtkm::IdComponent j = 0; j < numInds; ++j, ++connInd)
|
||||
{
|
||||
connectivityPortal.Set(connInd, static_cast<vtkm::Id>(*buffp++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReadShapes(vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes)
|
||||
{
|
||||
std::string tag;
|
||||
vtkm::Id numCells;
|
||||
this->DataFile->Stream >> tag >> numCells >> std::ws;
|
||||
internal::parseAssert(tag == "CELL_TYPES");
|
||||
|
||||
shapes.Allocate(numCells);
|
||||
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numCells));
|
||||
this->ReadArray(buffer);
|
||||
|
||||
vtkm::Int32* buffp = &buffer[0];
|
||||
auto shapesPortal = shapes.WritePortal();
|
||||
for (vtkm::Id i = 0; i < numCells; ++i)
|
||||
{
|
||||
shapesPortal.Set(i, static_cast<vtkm::UInt8>(*buffp++));
|
||||
}
|
||||
}
|
||||
|
||||
void ReadAttributes()
|
||||
{
|
||||
if (this->DataFile->Stream.eof())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY;
|
||||
std::size_t size;
|
||||
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
while (!this->DataFile->Stream.eof())
|
||||
{
|
||||
if (tag == "POINT_DATA")
|
||||
{
|
||||
association = vtkm::cont::Field::Association::POINTS;
|
||||
}
|
||||
else if (tag == "CELL_DATA")
|
||||
{
|
||||
association = vtkm::cont::Field::Association::CELL_SET;
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::parseAssert(false);
|
||||
}
|
||||
|
||||
this->DataFile->Stream >> size;
|
||||
while (!this->DataFile->Stream.eof())
|
||||
{
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "SCALARS")
|
||||
{
|
||||
this->ReadScalars(association, size);
|
||||
}
|
||||
else if (tag == "COLOR_SCALARS")
|
||||
{
|
||||
this->ReadColorScalars(association, size);
|
||||
}
|
||||
else if (tag == "LOOKUP_TABLE")
|
||||
{
|
||||
this->ReadLookupTable();
|
||||
}
|
||||
else if (tag == "VECTORS" || tag == "NORMALS")
|
||||
{
|
||||
this->ReadVectors(association, size);
|
||||
}
|
||||
else if (tag == "TEXTURE_COORDINATES")
|
||||
{
|
||||
this->ReadTextureCoordinates(association, size);
|
||||
}
|
||||
else if (tag == "TENSORS")
|
||||
{
|
||||
this->ReadTensors(association, size);
|
||||
}
|
||||
else if (tag == "FIELD")
|
||||
{
|
||||
this->ReadFields(association, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VTKM_CONT void ReadAttributes();
|
||||
|
||||
void SetCellsPermutation(const vtkm::cont::ArrayHandle<vtkm::Id>& permutation)
|
||||
{
|
||||
this->CellsPermutation = permutation;
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> GetCellsPermutation() const { return this->CellsPermutation; }
|
||||
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> GetCellsPermutation() const
|
||||
{
|
||||
return this->CellsPermutation;
|
||||
}
|
||||
|
||||
void TransferDataFile(VTKDataSetReaderBase& reader)
|
||||
VTKM_CONT void TransferDataFile(VTKDataSetReaderBase& reader)
|
||||
{
|
||||
reader.DataFile.swap(this->DataFile);
|
||||
this->DataFile.reset(nullptr);
|
||||
}
|
||||
|
||||
virtual void CloseFile() { this->DataFile->Stream.close(); }
|
||||
VTKM_CONT virtual void CloseFile();
|
||||
|
||||
VTKM_CONT virtual void Read() = 0;
|
||||
|
||||
private:
|
||||
void OpenFile()
|
||||
{
|
||||
this->DataFile->Stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
try
|
||||
{
|
||||
this->DataFile->Stream.open(this->DataFile->FileName.c_str(),
|
||||
std::ios_base::in | std::ios_base::binary);
|
||||
}
|
||||
catch (std::ifstream::failure&)
|
||||
{
|
||||
std::string message("could not open file \"" + this->DataFile->FileName + "\"");
|
||||
throw vtkm::io::ErrorIO(message);
|
||||
}
|
||||
}
|
||||
|
||||
void ReadHeader()
|
||||
{
|
||||
char vstring[] = "# vtk DataFile Version";
|
||||
const std::size_t vlen = sizeof(vstring);
|
||||
|
||||
// Read version line
|
||||
char vbuf[vlen];
|
||||
this->DataFile->Stream.read(vbuf, vlen - 1);
|
||||
vbuf[vlen - 1] = '\0';
|
||||
if (std::string(vbuf) != std::string(vstring))
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect file format.");
|
||||
}
|
||||
|
||||
char dot;
|
||||
this->DataFile->Stream >> this->DataFile->Version[0] >> dot >> this->DataFile->Version[1];
|
||||
// skip rest of the line
|
||||
std::string skip;
|
||||
std::getline(this->DataFile->Stream, skip);
|
||||
|
||||
if ((this->DataFile->Version[0] > 4) ||
|
||||
(this->DataFile->Version[0] == 4 && this->DataFile->Version[1] > 2))
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Reader may not correctly read >v4.2 files. Reading version "
|
||||
<< this->DataFile->Version[0]
|
||||
<< "."
|
||||
<< this->DataFile->Version[1]
|
||||
<< ".\n");
|
||||
}
|
||||
|
||||
// Read title line
|
||||
std::getline(this->DataFile->Stream, this->DataFile->Title);
|
||||
|
||||
// Read format line
|
||||
this->DataFile->IsBinary = false;
|
||||
std::string format;
|
||||
this->DataFile->Stream >> format >> std::ws;
|
||||
if (format == "BINARY")
|
||||
{
|
||||
this->DataFile->IsBinary = true;
|
||||
}
|
||||
else if (format != "ASCII")
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Unsupported Format.");
|
||||
}
|
||||
|
||||
// Read structure line
|
||||
std::string tag, structStr;
|
||||
this->DataFile->Stream >> tag >> structStr >> std::ws;
|
||||
internal::parseAssert(tag == "DATASET");
|
||||
|
||||
this->DataFile->Structure = vtkm::io::internal::DataSetStructureId(structStr);
|
||||
if (this->DataFile->Structure == vtkm::io::internal::DATASET_UNKNOWN)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Read() = 0;
|
||||
|
||||
void AddField(const std::string& name,
|
||||
VTKM_CONT void OpenFile();
|
||||
VTKM_CONT void ReadHeader();
|
||||
VTKM_CONT void AddField(const std::string& name,
|
||||
vtkm::cont::Field::Association association,
|
||||
vtkm::cont::VariantArrayHandle& data)
|
||||
{
|
||||
if (data.GetNumberOfValues() > 0)
|
||||
{
|
||||
switch (association)
|
||||
{
|
||||
case vtkm::cont::Field::Association::POINTS:
|
||||
case vtkm::cont::Field::Association::WHOLE_MESH:
|
||||
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
|
||||
break;
|
||||
case vtkm::cont::Field::Association::CELL_SET:
|
||||
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
|
||||
break;
|
||||
default:
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Not recording field '" << name << "' because it has an unknown association");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReadScalars(vtkm::cont::Field::Association association, std::size_t numElements)
|
||||
{
|
||||
std::string dataName, dataType, lookupTableName;
|
||||
vtkm::IdComponent numComponents = 1;
|
||||
this->DataFile->Stream >> dataName >> dataType;
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag != "LOOKUP_TABLE")
|
||||
{
|
||||
try
|
||||
{
|
||||
numComponents = std::stoi(tag);
|
||||
}
|
||||
catch (std::invalid_argument&)
|
||||
{
|
||||
internal::parseAssert(false);
|
||||
}
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
internal::parseAssert(tag == "LOOKUP_TABLE");
|
||||
this->DataFile->Stream >> lookupTableName >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void ReadColorScalars(vtkm::cont::Field::Association association, std::size_t numElements)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for COLOR_SCALARS is not implemented. Skipping.");
|
||||
|
||||
std::string dataName;
|
||||
vtkm::IdComponent numComponents;
|
||||
this->DataFile->Stream >> dataName >> numComponents >> std::ws;
|
||||
std::string dataType = this->DataFile->IsBinary ? "unsigned_char" : "float";
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void ReadLookupTable()
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for LOOKUP_TABLE is not implemented. Skipping.");
|
||||
|
||||
std::string dataName;
|
||||
std::size_t numEntries;
|
||||
this->DataFile->Stream >> dataName >> numEntries >> std::ws;
|
||||
this->SkipArray(numEntries, vtkm::Vec<vtkm::io::internal::ColorChannel8, 4>());
|
||||
}
|
||||
|
||||
void ReadTextureCoordinates(vtkm::cont::Field::Association association, std::size_t numElements)
|
||||
{
|
||||
std::string dataName;
|
||||
vtkm::IdComponent numComponents;
|
||||
std::string dataType;
|
||||
this->DataFile->Stream >> dataName >> numComponents >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void ReadVectors(vtkm::cont::Field::Association association, std::size_t numElements)
|
||||
{
|
||||
std::string dataName;
|
||||
std::string dataType;
|
||||
this->DataFile->Stream >> dataName >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, 3);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void ReadTensors(vtkm::cont::Field::Association association, std::size_t numElements)
|
||||
{
|
||||
std::string dataName;
|
||||
std::string dataType;
|
||||
this->DataFile->Stream >> dataName >> dataType >> std::ws;
|
||||
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numElements, 9);
|
||||
this->AddField(dataName, association, data);
|
||||
}
|
||||
|
||||
void ReadFields(vtkm::cont::Field::Association association, std::size_t expectedNumElements)
|
||||
{
|
||||
std::string dataName;
|
||||
vtkm::Id numArrays;
|
||||
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
|
||||
for (vtkm::Id i = 0; i < numArrays; ++i)
|
||||
{
|
||||
std::size_t numTuples;
|
||||
vtkm::IdComponent numComponents;
|
||||
std::string arrayName, dataType;
|
||||
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
|
||||
if (numTuples == expectedNumElements)
|
||||
{
|
||||
vtkm::cont::VariantArrayHandle data =
|
||||
this->DoReadArrayVariant(association, dataType, numTuples, numComponents);
|
||||
this->AddField(arrayName, association, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Field " << arrayName
|
||||
<< "'s size does not match expected number of elements. Skipping");
|
||||
}
|
||||
}
|
||||
}
|
||||
vtkm::cont::VariantArrayHandle& data);
|
||||
VTKM_CONT void ReadScalars(vtkm::cont::Field::Association association, std::size_t numElements);
|
||||
VTKM_CONT void ReadColorScalars(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements);
|
||||
VTKM_CONT void ReadLookupTable();
|
||||
VTKM_CONT void ReadTextureCoordinates(vtkm::cont::Field::Association association,
|
||||
std::size_t numElements);
|
||||
VTKM_CONT void ReadVectors(vtkm::cont::Field::Association association, std::size_t numElements);
|
||||
VTKM_CONT void ReadTensors(vtkm::cont::Field::Association association, std::size_t numElements);
|
||||
VTKM_CONT void ReadFields(vtkm::cont::Field::Association association,
|
||||
std::size_t expectedNumElements);
|
||||
|
||||
protected:
|
||||
void ReadGlobalFields(std::vector<vtkm::Float32>* visitBounds = nullptr)
|
||||
{
|
||||
std::string dataName;
|
||||
vtkm::Id numArrays;
|
||||
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
|
||||
for (vtkm::Id i = 0; i < numArrays; ++i)
|
||||
{
|
||||
std::size_t numTuples;
|
||||
vtkm::IdComponent numComponents;
|
||||
std::string arrayName, dataType;
|
||||
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
|
||||
if (arrayName == "avtOriginalBounds" && visitBounds)
|
||||
{
|
||||
visitBounds->resize(6);
|
||||
internal::parseAssert(numComponents == 1 && numTuples == 6);
|
||||
// parse the bounds and fill the bounds vector
|
||||
this->ReadArray(*visitBounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Support for global field " << arrayName << " not implemented. Skipping.");
|
||||
this->DoSkipArrayVariant(dataType, numTuples, numComponents);
|
||||
}
|
||||
}
|
||||
}
|
||||
VTKM_CONT void ReadGlobalFields(std::vector<vtkm::Float32>* visitBounds = nullptr);
|
||||
|
||||
private:
|
||||
class SkipArrayVariant
|
||||
{
|
||||
public:
|
||||
SkipArrayVariant(VTKDataSetReaderBase* reader, std::size_t numElements)
|
||||
: Reader(reader)
|
||||
, NumElements(numElements)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(T) const
|
||||
{
|
||||
this->Reader->SkipArray(this->NumElements, T());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(vtkm::IdComponent numComponents, T) const
|
||||
{
|
||||
this->Reader->SkipArray(this->NumElements * static_cast<std::size_t>(numComponents), T());
|
||||
}
|
||||
|
||||
protected:
|
||||
VTKDataSetReaderBase* Reader;
|
||||
std::size_t NumElements;
|
||||
};
|
||||
|
||||
class ReadArrayVariant : public SkipArrayVariant
|
||||
{
|
||||
public:
|
||||
ReadArrayVariant(VTKDataSetReaderBase* reader,
|
||||
vtkm::cont::Field::Association association,
|
||||
std::size_t numElements,
|
||||
vtkm::cont::VariantArrayHandle& data)
|
||||
: SkipArrayVariant(reader, numElements)
|
||||
, Association(association)
|
||||
, Data(&data)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(T) const
|
||||
{
|
||||
std::vector<T> buffer(this->NumElements);
|
||||
this->Reader->ReadArray(buffer);
|
||||
if ((this->Association != vtkm::cont::Field::Association::CELL_SET) ||
|
||||
(this->Reader->GetCellsPermutation().GetNumberOfValues() < 1))
|
||||
{
|
||||
*this->Data = internal::CreateVariantArrayHandle(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are reading data associated with a cell set, we need to (sometimes) permute the
|
||||
// data due to differences between VTK and VTK-m cell shapes.
|
||||
auto permutation = this->Reader->GetCellsPermutation().ReadPortal();
|
||||
vtkm::Id outSize = permutation.GetNumberOfValues();
|
||||
std::vector<T> permutedBuffer(static_cast<std::size_t>(outSize));
|
||||
for (vtkm::Id outIndex = 0; outIndex < outSize; outIndex++)
|
||||
{
|
||||
std::size_t inIndex = static_cast<std::size_t>(permutation.Get(outIndex));
|
||||
permutedBuffer[static_cast<std::size_t>(outIndex)] = buffer[inIndex];
|
||||
}
|
||||
*this->Data = internal::CreateVariantArrayHandle(permutedBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(vtkm::IdComponent numComponents, T) const
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for " << numComponents << " components not implemented. Skipping.");
|
||||
SkipArrayVariant::operator()(numComponents, T());
|
||||
}
|
||||
|
||||
private:
|
||||
vtkm::cont::Field::Association Association;
|
||||
vtkm::cont::VariantArrayHandle* Data;
|
||||
};
|
||||
class SkipArrayVariant;
|
||||
class ReadArrayVariant;
|
||||
|
||||
//Make the Array parsing methods protected so that derived classes
|
||||
//can call the methods.
|
||||
protected:
|
||||
void DoSkipArrayVariant(std::string dataType,
|
||||
VTKM_CONT void DoSkipArrayVariant(std::string dataType,
|
||||
std::size_t numElements,
|
||||
vtkm::IdComponent numComponents)
|
||||
{
|
||||
// string is unsupported for SkipArrayVariant, so it requires some
|
||||
// special handling
|
||||
if (dataType == "string")
|
||||
{
|
||||
const vtkm::Id stringCount = numComponents * static_cast<vtkm::Id>(numElements);
|
||||
for (vtkm::Id i = 0; i < stringCount; ++i)
|
||||
{
|
||||
std::string trash;
|
||||
this->DataFile->Stream >> trash;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
|
||||
vtkm::io::internal::SelectTypeAndCall(
|
||||
typeId, numComponents, SkipArrayVariant(this, numElements));
|
||||
}
|
||||
}
|
||||
|
||||
vtkm::cont::VariantArrayHandle DoReadArrayVariant(vtkm::cont::Field::Association association,
|
||||
vtkm::IdComponent numComponents);
|
||||
VTKM_CONT vtkm::cont::VariantArrayHandle DoReadArrayVariant(
|
||||
vtkm::cont::Field::Association association,
|
||||
std::string dataType,
|
||||
std::size_t numElements,
|
||||
vtkm::IdComponent numComponents)
|
||||
{
|
||||
// Create empty data to start so that the return can check if data were actually read
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> empty;
|
||||
vtkm::cont::VariantArrayHandle data(empty);
|
||||
|
||||
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
|
||||
vtkm::io::internal::SelectTypeAndCall(
|
||||
typeId, numComponents, ReadArrayVariant(this, association, numElements, data));
|
||||
|
||||
return data;
|
||||
}
|
||||
vtkm::IdComponent numComponents);
|
||||
|
||||
template <typename T>
|
||||
void ReadArray(std::vector<T>& buffer)
|
||||
VTKM_CONT void ReadArray(std::vector<T>& buffer)
|
||||
{
|
||||
using ComponentType = typename vtkm::VecTraits<T>::ComponentType;
|
||||
constexpr vtkm::IdComponent numComponents = vtkm::VecTraits<T>::NUM_COMPONENTS;
|
||||
@ -861,7 +220,8 @@ protected:
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent NumComponents>
|
||||
void ReadArray(std::vector<vtkm::Vec<vtkm::io::internal::DummyBitType, NumComponents>>& buffer)
|
||||
VTKM_CONT void ReadArray(
|
||||
std::vector<vtkm::Vec<vtkm::io::internal::DummyBitType, NumComponents>>& buffer)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for data type 'bit' is not implemented. Skipping.");
|
||||
@ -869,13 +229,7 @@ protected:
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
void ReadArray(std::vector<vtkm::io::internal::DummyBitType>& buffer)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Support for data type 'bit' is not implemented. Skipping.");
|
||||
this->SkipArray(buffer.size(), vtkm::io::internal::DummyBitType());
|
||||
buffer.clear();
|
||||
}
|
||||
VTKM_CONT void ReadArray(std::vector<vtkm::io::internal::DummyBitType>& buffer);
|
||||
|
||||
template <typename T>
|
||||
void SkipArray(std::size_t numElements, T)
|
||||
@ -912,99 +266,13 @@ protected:
|
||||
NumComponents);
|
||||
}
|
||||
|
||||
void SkipArray(std::size_t numElements,
|
||||
VTKM_CONT void SkipArray(std::size_t numElements,
|
||||
vtkm::io::internal::DummyBitType,
|
||||
vtkm::IdComponent numComponents = 1)
|
||||
{
|
||||
if (this->DataFile->IsBinary)
|
||||
{
|
||||
numElements = (numElements + 7) / 8;
|
||||
this->DataFile->Stream.seekg(static_cast<std::streamoff>(numElements), std::ios_base::cur);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < numElements; ++i)
|
||||
{
|
||||
vtkm::UInt16 val;
|
||||
this->DataFile->Stream >> val;
|
||||
}
|
||||
}
|
||||
this->DataFile->Stream >> std::ws;
|
||||
this->SkipArrayMetaData(numComponents);
|
||||
}
|
||||
vtkm::IdComponent numComponents = 1);
|
||||
|
||||
void SkipArrayMetaData(vtkm::IdComponent numComponents)
|
||||
{
|
||||
if (!this->DataFile->Stream.good())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto begining = this->DataFile->Stream.tellg();
|
||||
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag != "METADATA")
|
||||
{
|
||||
this->DataFile->Stream.seekg(begining);
|
||||
return;
|
||||
}
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "METADATA is not supported. Attempting to Skip.");
|
||||
|
||||
this->DataFile->Stream >> tag >> std::ws;
|
||||
if (tag == "COMPONENT_NAMES")
|
||||
{
|
||||
std::string name;
|
||||
for (vtkm::IdComponent i = 0; i < numComponents; ++i)
|
||||
{
|
||||
this->DataFile->Stream >> name >> std::ws;
|
||||
}
|
||||
}
|
||||
else if (tag == "INFORMATION")
|
||||
{
|
||||
int numKeys = 0;
|
||||
this->DataFile->Stream >> numKeys >> std::ws;
|
||||
|
||||
// Skipping INFORMATION is tricky. The reader needs to be aware of the types of the
|
||||
// information, which is not provided in the file.
|
||||
// Here we will just skip until an empty line is found.
|
||||
// However, if there are no keys, then there is nothing to read (and the stream tends
|
||||
// to skip over empty lines.
|
||||
if (numKeys > 0)
|
||||
{
|
||||
std::string line;
|
||||
do
|
||||
{
|
||||
std::getline(this->DataFile->Stream, line);
|
||||
} while (this->DataFile->Stream.good() && !line.empty());
|
||||
|
||||
// Eat any remaining whitespace after the INFORMATION to be ready to read the next token
|
||||
this->DataFile->Stream >> std::ws;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::parseAssert(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<internal::VTKDataSetFile> DataFile;
|
||||
vtkm::cont::DataSet DataSet;
|
||||
|
||||
private:
|
||||
bool Loaded;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> CellsPermutation;
|
||||
|
||||
friend class VTKDataSetReader;
|
||||
VTKM_CONT void SkipArrayMetaData(vtkm::IdComponent numComponents);
|
||||
};
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
|
||||
}
|
||||
} // vtkm::io
|
||||
|
||||
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::ColorChannel8)
|
||||
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::DummyBitType)
|
||||
|
||||
#endif // vtk_m_io_VTKDataSetReaderBase_h
|
||||
|
407
vtkm/io/VTKDataSetWriter.cxx
Normal file
407
vtkm/io/VTKDataSetWriter.cxx
Normal file
@ -0,0 +1,407 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKDataSetWriter.h>
|
||||
|
||||
#include <vtkm/CellShape.h>
|
||||
|
||||
#include <vtkm/cont/CellSetExplicit.h>
|
||||
#include <vtkm/cont/CellSetSingleType.h>
|
||||
#include <vtkm/cont/CellSetStructured.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/ErrorBadValue.h>
|
||||
#include <vtkm/cont/Field.h>
|
||||
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
|
||||
#include <vtkm/io/internal/VTKDataSetTypes.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct OutputPointsFunctor
|
||||
{
|
||||
private:
|
||||
std::ostream& out;
|
||||
|
||||
template <typename PortalType>
|
||||
VTKM_CONT void Output(const PortalType& portal) const
|
||||
{
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
|
||||
{
|
||||
const int VTKDims = 3; // VTK files always require 3 dims for points
|
||||
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
using VecType = typename vtkm::VecTraits<ValueType>;
|
||||
|
||||
const ValueType& value = portal.Get(index);
|
||||
|
||||
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
|
||||
for (vtkm::IdComponent c = 0; c < numComponents && c < VTKDims; c++)
|
||||
{
|
||||
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
|
||||
}
|
||||
for (vtkm::IdComponent c = numComponents; c < VTKDims; c++)
|
||||
{
|
||||
out << " 0";
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
OutputPointsFunctor(std::ostream& o)
|
||||
: out(o)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
|
||||
{
|
||||
this->Output(array.ReadPortal());
|
||||
}
|
||||
};
|
||||
|
||||
struct OutputFieldFunctor
|
||||
{
|
||||
private:
|
||||
std::ostream& out;
|
||||
|
||||
template <typename PortalType>
|
||||
VTKM_CONT void Output(const PortalType& portal) const
|
||||
{
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
|
||||
{
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
using VecType = typename vtkm::VecTraits<ValueType>;
|
||||
|
||||
const ValueType& value = portal.Get(index);
|
||||
|
||||
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
|
||||
for (vtkm::IdComponent c = 0; c < numComponents; c++)
|
||||
{
|
||||
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
OutputFieldFunctor(std::ostream& o)
|
||||
: out(o)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
|
||||
{
|
||||
this->Output(array.ReadPortal());
|
||||
}
|
||||
};
|
||||
|
||||
class GetDataTypeName
|
||||
{
|
||||
public:
|
||||
GetDataTypeName(std::string& name)
|
||||
: Name(&name)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ArrayHandleType>
|
||||
void operator()(const ArrayHandleType&) const
|
||||
{
|
||||
using DataType = typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::ComponentType;
|
||||
*this->Name = vtkm::io::internal::DataTypeName<DataType>::Name();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* Name;
|
||||
};
|
||||
|
||||
void WritePoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
///\todo: support other coordinate systems
|
||||
int cindex = 0;
|
||||
auto cdata = dataSet.GetCoordinateSystem(cindex).GetData();
|
||||
|
||||
vtkm::Id npoints = cdata.GetNumberOfValues();
|
||||
out << "POINTS " << npoints << " " << vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name()
|
||||
<< " " << '\n';
|
||||
|
||||
OutputPointsFunctor{ out }(cdata);
|
||||
}
|
||||
|
||||
template <class CellSetType>
|
||||
void WriteExplicitCells(std::ostream& out, const CellSetType& cellSet)
|
||||
{
|
||||
vtkm::Id nCells = cellSet.GetNumberOfCells();
|
||||
|
||||
vtkm::Id conn_length = 0;
|
||||
for (vtkm::Id i = 0; i < nCells; ++i)
|
||||
{
|
||||
conn_length += 1 + cellSet.GetNumberOfPointsInCell(i);
|
||||
}
|
||||
|
||||
out << "CELLS " << nCells << " " << conn_length << '\n';
|
||||
|
||||
for (vtkm::Id i = 0; i < nCells; ++i)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> ids;
|
||||
vtkm::Id nids = cellSet.GetNumberOfPointsInCell(i);
|
||||
cellSet.GetIndices(i, ids);
|
||||
out << nids;
|
||||
auto IdPortal = ids.ReadPortal();
|
||||
for (int j = 0; j < nids; ++j)
|
||||
out << " " << IdPortal.Get(j);
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
out << "CELL_TYPES " << nCells << '\n';
|
||||
for (vtkm::Id i = 0; i < nCells; ++i)
|
||||
{
|
||||
vtkm::Id shape = cellSet.GetCellShape(i);
|
||||
out << shape << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void WriteVertexCells(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
vtkm::Id nCells = dataSet.GetCoordinateSystem(0).GetNumberOfPoints();
|
||||
|
||||
out << "CELLS " << nCells << " " << nCells * 2 << '\n';
|
||||
for (int i = 0; i < nCells; i++)
|
||||
{
|
||||
out << "1 " << i << '\n';
|
||||
}
|
||||
out << "CELL_TYPES " << nCells << '\n';
|
||||
for (int i = 0; i < nCells; i++)
|
||||
{
|
||||
out << vtkm::CELL_SHAPE_VERTEX << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void WritePointFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
bool wrote_header = false;
|
||||
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
|
||||
{
|
||||
const vtkm::cont::Field field = dataSet.GetField(f);
|
||||
|
||||
if (field.GetAssociation() != vtkm::cont::Field::Association::POINTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
vtkm::Id npoints = field.GetNumberOfValues();
|
||||
int ncomps = field.GetData().GetNumberOfComponents();
|
||||
if (ncomps > 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!wrote_header)
|
||||
{
|
||||
out << "POINT_DATA " << npoints << '\n';
|
||||
wrote_header = true;
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
|
||||
GetDataTypeName(typeName));
|
||||
std::string name = field.GetName();
|
||||
for (auto& c : name)
|
||||
{
|
||||
if (std::isspace(c))
|
||||
{
|
||||
c = '_';
|
||||
}
|
||||
}
|
||||
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
|
||||
out << "LOOKUP_TABLE default" << '\n';
|
||||
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
|
||||
OutputFieldFunctor(out));
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCellFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
bool wrote_header = false;
|
||||
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
|
||||
{
|
||||
const vtkm::cont::Field field = dataSet.GetField(f);
|
||||
if (!field.IsFieldCell())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
vtkm::Id ncells = field.GetNumberOfValues();
|
||||
int ncomps = field.GetData().GetNumberOfComponents();
|
||||
if (ncomps > 4)
|
||||
continue;
|
||||
|
||||
if (!wrote_header)
|
||||
{
|
||||
out << "CELL_DATA " << ncells << '\n';
|
||||
wrote_header = true;
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
|
||||
GetDataTypeName(typeName));
|
||||
|
||||
std::string name = field.GetName();
|
||||
for (auto& c : name)
|
||||
{
|
||||
if (std::isspace(c))
|
||||
{
|
||||
c = '_';
|
||||
}
|
||||
}
|
||||
|
||||
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
|
||||
out << "LOOKUP_TABLE default" << '\n';
|
||||
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
|
||||
OutputFieldFunctor(out));
|
||||
}
|
||||
}
|
||||
|
||||
void WriteDataSetAsPoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
out << "DATASET UNSTRUCTURED_GRID" << '\n';
|
||||
WritePoints(out, dataSet);
|
||||
WriteVertexCells(out, dataSet);
|
||||
}
|
||||
|
||||
template <class CellSetType>
|
||||
void WriteDataSetAsUnstructured(std::ostream& out,
|
||||
const vtkm::cont::DataSet& dataSet,
|
||||
const CellSetType& cellSet)
|
||||
{
|
||||
out << "DATASET UNSTRUCTURED_GRID" << '\n';
|
||||
WritePoints(out, dataSet);
|
||||
WriteExplicitCells(out, cellSet);
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent DIM>
|
||||
void WriteDataSetAsStructured(std::ostream& out,
|
||||
const vtkm::cont::DataSet& dataSet,
|
||||
const vtkm::cont::CellSetStructured<DIM>& cellSet)
|
||||
{
|
||||
///\todo: support uniform/rectilinear
|
||||
out << "DATASET STRUCTURED_GRID" << '\n';
|
||||
|
||||
auto pointDimensions = cellSet.GetPointDimensions();
|
||||
using VTraits = vtkm::VecTraits<decltype(pointDimensions)>;
|
||||
|
||||
out << "DIMENSIONS ";
|
||||
out << VTraits::GetComponent(pointDimensions, 0) << " ";
|
||||
out << (DIM > 1 ? VTraits::GetComponent(pointDimensions, 1) : 1) << " ";
|
||||
out << (DIM > 2 ? VTraits::GetComponent(pointDimensions, 2) : 1) << " ";
|
||||
|
||||
WritePoints(out, dataSet);
|
||||
}
|
||||
|
||||
void Write(std::ostream& out, const vtkm::cont::DataSet& dataSet, bool just_points = false)
|
||||
{
|
||||
// The Paraview parser cannot handle scientific notation:
|
||||
out << std::fixed;
|
||||
out << "# vtk DataFile Version 3.0" << '\n';
|
||||
out << "vtk output" << '\n';
|
||||
out << "ASCII" << '\n';
|
||||
|
||||
if (just_points)
|
||||
{
|
||||
WriteDataSetAsPoints(out, dataSet);
|
||||
WritePointFields(out, dataSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::cont::DynamicCellSet cellSet = dataSet.GetCellSet();
|
||||
if (cellSet.IsType<vtkm::cont::CellSetExplicit<>>())
|
||||
{
|
||||
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetExplicit<>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetStructured<1>>())
|
||||
{
|
||||
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<1>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
|
||||
{
|
||||
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<2>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
|
||||
{
|
||||
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<3>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetSingleType<>>())
|
||||
{
|
||||
// these function just like explicit cell sets
|
||||
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetSingleType<>>());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
|
||||
}
|
||||
|
||||
WritePointFields(out, dataSet);
|
||||
WriteCellFields(out, dataSet);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKDataSetWriter::VTKDataSetWriter(const char* fileName)
|
||||
: FileName(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKDataSetWriter::VTKDataSetWriter(const std::string& fileName)
|
||||
: FileName(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
void VTKDataSetWriter::WriteDataSet(const vtkm::cont::DataSet& dataSet, bool just_points) const
|
||||
{
|
||||
if (dataSet.GetNumberOfCoordinateSystems() < 1)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue(
|
||||
"DataSet has no coordinate system, which is not supported by VTK file format.");
|
||||
}
|
||||
try
|
||||
{
|
||||
std::ofstream fileStream(this->FileName.c_str(), std::fstream::trunc);
|
||||
Write(fileStream, dataSet, just_points);
|
||||
fileStream.close();
|
||||
}
|
||||
catch (std::ofstream::failure& error)
|
||||
{
|
||||
throw vtkm::io::ErrorIO(error.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -10,400 +10,22 @@
|
||||
#ifndef vtk_m_io_DataSetWriter_h
|
||||
#define vtk_m_io_DataSetWriter_h
|
||||
|
||||
#include <cctype>
|
||||
#include <vtkm/CellShape.h>
|
||||
|
||||
#include <vtkm/cont/CellSetExplicit.h>
|
||||
#include <vtkm/cont/CellSetSingleType.h>
|
||||
#include <vtkm/cont/CellSetStructured.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/ErrorBadValue.h>
|
||||
#include <vtkm/cont/Field.h>
|
||||
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
|
||||
#include <vtkm/io/internal/VTKDataSetTypes.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vtkm/io/vtkm_io_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct OutputPointsFunctor
|
||||
{
|
||||
private:
|
||||
std::ostream& out;
|
||||
|
||||
template <typename PortalType>
|
||||
VTKM_CONT void Output(const PortalType& portal) const
|
||||
{
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
|
||||
{
|
||||
const int VTKDims = 3; // VTK files always require 3 dims for points
|
||||
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
using VecType = typename vtkm::VecTraits<ValueType>;
|
||||
|
||||
const ValueType& value = portal.Get(index);
|
||||
|
||||
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
|
||||
for (vtkm::IdComponent c = 0; c < numComponents && c < VTKDims; c++)
|
||||
{
|
||||
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
|
||||
}
|
||||
for (vtkm::IdComponent c = numComponents; c < VTKDims; c++)
|
||||
{
|
||||
out << " 0";
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
OutputPointsFunctor(std::ostream& o)
|
||||
: out(o)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
|
||||
{
|
||||
this->Output(array.ReadPortal());
|
||||
}
|
||||
};
|
||||
|
||||
struct OutputFieldFunctor
|
||||
{
|
||||
private:
|
||||
std::ostream& out;
|
||||
|
||||
template <typename PortalType>
|
||||
VTKM_CONT void Output(const PortalType& portal) const
|
||||
{
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
|
||||
{
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
using VecType = typename vtkm::VecTraits<ValueType>;
|
||||
|
||||
const ValueType& value = portal.Get(index);
|
||||
|
||||
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
|
||||
for (vtkm::IdComponent c = 0; c < numComponents; c++)
|
||||
{
|
||||
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
|
||||
}
|
||||
out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
OutputFieldFunctor(std::ostream& o)
|
||||
: out(o)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
|
||||
{
|
||||
this->Output(array.ReadPortal());
|
||||
}
|
||||
};
|
||||
|
||||
class GetDataTypeName
|
||||
struct VTKM_IO_EXPORT VTKDataSetWriter
|
||||
{
|
||||
public:
|
||||
GetDataTypeName(std::string& name)
|
||||
: Name(&name)
|
||||
{
|
||||
}
|
||||
VTKM_CONT VTKDataSetWriter(const char* fileName);
|
||||
VTKM_CONT VTKDataSetWriter(const std::string& fileName);
|
||||
|
||||
template <typename ArrayHandleType>
|
||||
void operator()(const ArrayHandleType&) const
|
||||
{
|
||||
using DataType = typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::ComponentType;
|
||||
*this->Name = vtkm::io::internal::DataTypeName<DataType>::Name();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* Name;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct VTKDataSetWriter
|
||||
{
|
||||
private:
|
||||
static void WritePoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
///\todo: support other coordinate systems
|
||||
int cindex = 0;
|
||||
auto cdata = dataSet.GetCoordinateSystem(cindex).GetData();
|
||||
|
||||
vtkm::Id npoints = cdata.GetNumberOfValues();
|
||||
out << "POINTS " << npoints << " "
|
||||
<< vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name() << " " << '\n';
|
||||
|
||||
detail::OutputPointsFunctor{ out }(cdata);
|
||||
}
|
||||
|
||||
template <class CellSetType>
|
||||
static void WriteExplicitCells(std::ostream& out, const CellSetType& cellSet)
|
||||
{
|
||||
vtkm::Id nCells = cellSet.GetNumberOfCells();
|
||||
|
||||
vtkm::Id conn_length = 0;
|
||||
for (vtkm::Id i = 0; i < nCells; ++i)
|
||||
{
|
||||
conn_length += 1 + cellSet.GetNumberOfPointsInCell(i);
|
||||
}
|
||||
|
||||
out << "CELLS " << nCells << " " << conn_length << '\n';
|
||||
|
||||
for (vtkm::Id i = 0; i < nCells; ++i)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> ids;
|
||||
vtkm::Id nids = cellSet.GetNumberOfPointsInCell(i);
|
||||
cellSet.GetIndices(i, ids);
|
||||
out << nids;
|
||||
auto IdPortal = ids.ReadPortal();
|
||||
for (int j = 0; j < nids; ++j)
|
||||
out << " " << IdPortal.Get(j);
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
out << "CELL_TYPES " << nCells << '\n';
|
||||
for (vtkm::Id i = 0; i < nCells; ++i)
|
||||
{
|
||||
vtkm::Id shape = cellSet.GetCellShape(i);
|
||||
out << shape << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteVertexCells(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
vtkm::Id nCells = dataSet.GetCoordinateSystem(0).GetNumberOfPoints();
|
||||
|
||||
out << "CELLS " << nCells << " " << nCells * 2 << '\n';
|
||||
for (int i = 0; i < nCells; i++)
|
||||
{
|
||||
out << "1 " << i << '\n';
|
||||
}
|
||||
out << "CELL_TYPES " << nCells << '\n';
|
||||
for (int i = 0; i < nCells; i++)
|
||||
{
|
||||
out << vtkm::CELL_SHAPE_VERTEX << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static void WritePointFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
bool wrote_header = false;
|
||||
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
|
||||
{
|
||||
const vtkm::cont::Field field = dataSet.GetField(f);
|
||||
|
||||
if (field.GetAssociation() != vtkm::cont::Field::Association::POINTS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
vtkm::Id npoints = field.GetNumberOfValues();
|
||||
int ncomps = field.GetData().GetNumberOfComponents();
|
||||
if (ncomps > 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!wrote_header)
|
||||
{
|
||||
out << "POINT_DATA " << npoints << '\n';
|
||||
wrote_header = true;
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
|
||||
detail::GetDataTypeName(typeName));
|
||||
std::string name = field.GetName();
|
||||
for (auto& c : name)
|
||||
{
|
||||
if (std::isspace(c))
|
||||
{
|
||||
c = '_';
|
||||
}
|
||||
}
|
||||
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
|
||||
out << "LOOKUP_TABLE default" << '\n';
|
||||
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
|
||||
detail::OutputFieldFunctor(out));
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteCellFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
bool wrote_header = false;
|
||||
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
|
||||
{
|
||||
const vtkm::cont::Field field = dataSet.GetField(f);
|
||||
if (!field.IsFieldCell())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
vtkm::Id ncells = field.GetNumberOfValues();
|
||||
int ncomps = field.GetData().GetNumberOfComponents();
|
||||
if (ncomps > 4)
|
||||
continue;
|
||||
|
||||
if (!wrote_header)
|
||||
{
|
||||
out << "CELL_DATA " << ncells << '\n';
|
||||
wrote_header = true;
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
|
||||
detail::GetDataTypeName(typeName));
|
||||
|
||||
std::string name = field.GetName();
|
||||
for (auto& c : name)
|
||||
{
|
||||
if (std::isspace(c))
|
||||
{
|
||||
c = '_';
|
||||
}
|
||||
}
|
||||
|
||||
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
|
||||
out << "LOOKUP_TABLE default" << '\n';
|
||||
|
||||
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
|
||||
detail::OutputFieldFunctor(out));
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteDataSetAsPoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
|
||||
{
|
||||
out << "DATASET UNSTRUCTURED_GRID" << '\n';
|
||||
WritePoints(out, dataSet);
|
||||
WriteVertexCells(out, dataSet);
|
||||
}
|
||||
|
||||
template <class CellSetType>
|
||||
static void WriteDataSetAsUnstructured(std::ostream& out,
|
||||
const vtkm::cont::DataSet& dataSet,
|
||||
const CellSetType& cellSet)
|
||||
{
|
||||
out << "DATASET UNSTRUCTURED_GRID" << '\n';
|
||||
WritePoints(out, dataSet);
|
||||
WriteExplicitCells(out, cellSet);
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent DIM>
|
||||
static void WriteDataSetAsStructured(std::ostream& out,
|
||||
const vtkm::cont::DataSet& dataSet,
|
||||
const vtkm::cont::CellSetStructured<DIM>& cellSet)
|
||||
{
|
||||
///\todo: support uniform/rectilinear
|
||||
out << "DATASET STRUCTURED_GRID" << '\n';
|
||||
|
||||
auto pointDimensions = cellSet.GetPointDimensions();
|
||||
using VTraits = vtkm::VecTraits<decltype(pointDimensions)>;
|
||||
|
||||
out << "DIMENSIONS ";
|
||||
out << VTraits::GetComponent(pointDimensions, 0) << " ";
|
||||
out << (DIM > 1 ? VTraits::GetComponent(pointDimensions, 1) : 1) << " ";
|
||||
out << (DIM > 2 ? VTraits::GetComponent(pointDimensions, 2) : 1) << " ";
|
||||
|
||||
WritePoints(out, dataSet);
|
||||
}
|
||||
|
||||
static void Write(std::ostream& out, const vtkm::cont::DataSet& dataSet, bool just_points = false)
|
||||
{
|
||||
// The Paraview parser cannot handle scientific notation:
|
||||
out << std::fixed;
|
||||
out << "# vtk DataFile Version 3.0" << '\n';
|
||||
out << "vtk output" << '\n';
|
||||
out << "ASCII" << '\n';
|
||||
|
||||
if (just_points)
|
||||
{
|
||||
WriteDataSetAsPoints(out, dataSet);
|
||||
WritePointFields(out, dataSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::cont::DynamicCellSet cellSet = dataSet.GetCellSet();
|
||||
if (cellSet.IsType<vtkm::cont::CellSetExplicit<>>())
|
||||
{
|
||||
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetExplicit<>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetStructured<1>>())
|
||||
{
|
||||
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<1>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
|
||||
{
|
||||
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<2>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
|
||||
{
|
||||
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<3>>());
|
||||
}
|
||||
else if (cellSet.IsType<vtkm::cont::CellSetSingleType<>>())
|
||||
{
|
||||
// these function just like explicit cell sets
|
||||
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetSingleType<>>());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
|
||||
}
|
||||
|
||||
WritePointFields(out, dataSet);
|
||||
WriteCellFields(out, dataSet);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
explicit VTKDataSetWriter(const std::string& filename)
|
||||
: FileName(filename)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void WriteDataSet(const vtkm::cont::DataSet& dataSet, bool just_points = false) const
|
||||
{
|
||||
if (dataSet.GetNumberOfCoordinateSystems() < 1)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue(
|
||||
"DataSet has no coordinate system, which is not supported by VTK file format.");
|
||||
}
|
||||
try
|
||||
{
|
||||
std::ofstream fileStream(this->FileName.c_str(), std::fstream::trunc);
|
||||
this->Write(fileStream, dataSet, just_points);
|
||||
fileStream.close();
|
||||
}
|
||||
catch (std::ofstream::failure& error)
|
||||
{
|
||||
throw vtkm::io::ErrorIO(error.what());
|
||||
}
|
||||
}
|
||||
VTKM_CONT void WriteDataSet(const vtkm::cont::DataSet& dataSet, bool just_points = false) const;
|
||||
|
||||
private:
|
||||
std::string FileName;
|
||||
|
152
vtkm/io/VTKPolyDataReader.cxx
Normal file
152
vtkm/io/VTKPolyDataReader.cxx
Normal file
@ -0,0 +1,152 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKPolyDataReader.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
inline vtkm::cont::ArrayHandle<T> ConcatinateArrayHandles(
|
||||
const std::vector<vtkm::cont::ArrayHandle<T>>& arrays)
|
||||
{
|
||||
vtkm::Id size = 0;
|
||||
for (std::size_t i = 0; i < arrays.size(); ++i)
|
||||
{
|
||||
size += arrays[i].GetNumberOfValues();
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T> out;
|
||||
out.Allocate(size);
|
||||
|
||||
auto outp = vtkm::cont::ArrayPortalToIteratorBegin(out.WritePortal());
|
||||
for (std::size_t i = 0; i < arrays.size(); ++i)
|
||||
{
|
||||
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(arrays[i].ReadPortal()),
|
||||
vtkm::cont::ArrayPortalToIteratorEnd(arrays[i].ReadPortal()),
|
||||
outp);
|
||||
using DifferenceType = typename std::iterator_traits<decltype(outp)>::difference_type;
|
||||
std::advance(outp, static_cast<DifferenceType>(arrays[i].GetNumberOfValues()));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKPolyDataReader::VTKPolyDataReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKPolyDataReader::VTKPolyDataReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
void VTKPolyDataReader::Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_POLYDATA)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read the points
|
||||
internal::parseAssert(tag == "POINTS");
|
||||
this->ReadPoints();
|
||||
|
||||
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
|
||||
|
||||
// Read the cellset
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::Id>> connectivityArrays;
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::IdComponent>> numIndicesArrays;
|
||||
std::vector<vtkm::UInt8> shapesBuffer;
|
||||
while (!this->DataFile->Stream.eof())
|
||||
{
|
||||
vtkm::UInt8 shape = vtkm::CELL_SHAPE_EMPTY;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "VERTICES")
|
||||
{
|
||||
shape = vtkm::io::internal::CELL_SHAPE_POLY_VERTEX;
|
||||
}
|
||||
else if (tag == "LINES")
|
||||
{
|
||||
shape = vtkm::io::internal::CELL_SHAPE_POLY_LINE;
|
||||
}
|
||||
else if (tag == "POLYGONS")
|
||||
{
|
||||
shape = vtkm::CELL_SHAPE_POLYGON;
|
||||
}
|
||||
else if (tag == "TRIANGLE_STRIPS")
|
||||
{
|
||||
shape = vtkm::io::internal::CELL_SHAPE_TRIANGLE_STRIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->DataFile->Stream.seekg(-static_cast<std::streamoff>(tag.length()), std::ios_base::cur);
|
||||
break;
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> cellConnectivity;
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> cellNumIndices;
|
||||
this->ReadCells(cellConnectivity, cellNumIndices);
|
||||
|
||||
connectivityArrays.push_back(cellConnectivity);
|
||||
numIndicesArrays.push_back(cellNumIndices);
|
||||
shapesBuffer.insert(
|
||||
shapesBuffer.end(), static_cast<std::size_t>(cellNumIndices.GetNumberOfValues()), shape);
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity = ConcatinateArrayHandles(connectivityArrays);
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices = ConcatinateArrayHandles(numIndicesArrays);
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
|
||||
shapes.Allocate(static_cast<vtkm::Id>(shapesBuffer.size()));
|
||||
std::copy(shapesBuffer.begin(),
|
||||
shapesBuffer.end(),
|
||||
vtkm::cont::ArrayPortalToIteratorBegin(shapes.WritePortal()));
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
|
||||
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
|
||||
this->SetCellsPermutation(permutation);
|
||||
|
||||
if (vtkm::io::internal::IsSingleShape(shapes))
|
||||
{
|
||||
vtkm::cont::CellSetSingleType<> cellSet;
|
||||
cellSet.Fill(
|
||||
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
|
||||
vtkm::cont::CellSetExplicit<> cellSet;
|
||||
cellSet.Fill(numPoints, shapes, connectivity, offsets);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -11,6 +11,7 @@
|
||||
#define vtk_m_io_VTKPolyDataReader_h
|
||||
|
||||
#include <vtkm/io/VTKDataSetReaderBase.h>
|
||||
#include <vtkm/io/internal/VTKDataSetCells.h>
|
||||
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
|
||||
@ -21,147 +22,15 @@ namespace vtkm
|
||||
namespace io
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
inline vtkm::cont::ArrayHandle<T> ConcatinateArrayHandles(
|
||||
const std::vector<vtkm::cont::ArrayHandle<T>>& arrays)
|
||||
{
|
||||
vtkm::Id size = 0;
|
||||
for (std::size_t i = 0; i < arrays.size(); ++i)
|
||||
{
|
||||
size += arrays[i].GetNumberOfValues();
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T> out;
|
||||
out.Allocate(size);
|
||||
|
||||
auto outp = vtkm::cont::ArrayPortalToIteratorBegin(out.WritePortal());
|
||||
for (std::size_t i = 0; i < arrays.size(); ++i)
|
||||
{
|
||||
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(arrays[i].ReadPortal()),
|
||||
vtkm::cont::ArrayPortalToIteratorEnd(arrays[i].ReadPortal()),
|
||||
outp);
|
||||
using DifferenceType = typename std::iterator_traits<decltype(outp)>::difference_type;
|
||||
std::advance(outp, static_cast<DifferenceType>(arrays[i].GetNumberOfValues()));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKPolyDataReader : public VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKPolyDataReader : public VTKDataSetReaderBase
|
||||
{
|
||||
public:
|
||||
explicit VTKPolyDataReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
explicit VTKM_CONT VTKPolyDataReader(const char* fileName);
|
||||
explicit VTKM_CONT VTKPolyDataReader(const std::string& fileName);
|
||||
|
||||
private:
|
||||
virtual void Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_POLYDATA)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read the points
|
||||
internal::parseAssert(tag == "POINTS");
|
||||
this->ReadPoints();
|
||||
|
||||
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
|
||||
|
||||
// Read the cellset
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::Id>> connectivityArrays;
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::IdComponent>> numIndicesArrays;
|
||||
std::vector<vtkm::UInt8> shapesBuffer;
|
||||
while (!this->DataFile->Stream.eof())
|
||||
{
|
||||
vtkm::UInt8 shape = vtkm::CELL_SHAPE_EMPTY;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "VERTICES")
|
||||
{
|
||||
shape = vtkm::io::internal::CELL_SHAPE_POLY_VERTEX;
|
||||
}
|
||||
else if (tag == "LINES")
|
||||
{
|
||||
shape = vtkm::io::internal::CELL_SHAPE_POLY_LINE;
|
||||
}
|
||||
else if (tag == "POLYGONS")
|
||||
{
|
||||
shape = vtkm::CELL_SHAPE_POLYGON;
|
||||
}
|
||||
else if (tag == "TRIANGLE_STRIPS")
|
||||
{
|
||||
shape = vtkm::io::internal::CELL_SHAPE_TRIANGLE_STRIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->DataFile->Stream.seekg(-static_cast<std::streamoff>(tag.length()),
|
||||
std::ios_base::cur);
|
||||
break;
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> cellConnectivity;
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> cellNumIndices;
|
||||
this->ReadCells(cellConnectivity, cellNumIndices);
|
||||
|
||||
connectivityArrays.push_back(cellConnectivity);
|
||||
numIndicesArrays.push_back(cellNumIndices);
|
||||
shapesBuffer.insert(
|
||||
shapesBuffer.end(), static_cast<std::size_t>(cellNumIndices.GetNumberOfValues()), shape);
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity =
|
||||
internal::ConcatinateArrayHandles(connectivityArrays);
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices =
|
||||
internal::ConcatinateArrayHandles(numIndicesArrays);
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
|
||||
shapes.Allocate(static_cast<vtkm::Id>(shapesBuffer.size()));
|
||||
std::copy(shapesBuffer.begin(),
|
||||
shapesBuffer.end(),
|
||||
vtkm::cont::ArrayPortalToIteratorBegin(shapes.WritePortal()));
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
|
||||
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
|
||||
this->SetCellsPermutation(permutation);
|
||||
|
||||
if (vtkm::io::internal::IsSingleShape(shapes))
|
||||
{
|
||||
vtkm::cont::CellSetSingleType<> cellSet;
|
||||
cellSet.Fill(
|
||||
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
|
||||
vtkm::cont::CellSetExplicit<> cellSet;
|
||||
cellSet.Fill(numPoints, shapes, connectivity, offsets);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
void Read() override;
|
||||
};
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
|
95
vtkm/io/VTKRectilinearGridReader.cxx
Normal file
95
vtkm/io/VTKRectilinearGridReader.cxx
Normal file
@ -0,0 +1,95 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKRectilinearGridReader.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKRectilinearGridReader::VTKRectilinearGridReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKRectilinearGridReader::VTKRectilinearGridReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
void VTKRectilinearGridReader::Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_RECTILINEAR_GRID)
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read structured grid specific meta-data
|
||||
internal::parseAssert(tag == "DIMENSIONS");
|
||||
vtkm::Id3 dim;
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
|
||||
//Read the points.
|
||||
std::string dataType;
|
||||
std::size_t numPoints[3];
|
||||
vtkm::cont::VariantArrayHandle X, Y, Z;
|
||||
|
||||
// Always read coordinates as vtkm::FloatDefault
|
||||
std::string readDataType = vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name();
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[0] >> dataType >> std::ws;
|
||||
if (tag != "X_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("X_COORDINATES tag not found");
|
||||
X = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[0], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[1] >> dataType >> std::ws;
|
||||
if (tag != "Y_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("Y_COORDINATES tag not found");
|
||||
Y = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[1], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[2] >> dataType >> std::ws;
|
||||
if (tag != "Z_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("Z_COORDINATES tag not found");
|
||||
Z = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[2], 1);
|
||||
|
||||
if (dim != vtkm::Id3(static_cast<vtkm::Id>(numPoints[0]),
|
||||
static_cast<vtkm::Id>(numPoints[1]),
|
||||
static_cast<vtkm::Id>(numPoints[2])))
|
||||
throw vtkm::io::ErrorIO("DIMENSIONS not equal to number of points");
|
||||
|
||||
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>
|
||||
coords;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Xc, Yc, Zc;
|
||||
X.CopyTo(Xc);
|
||||
Y.CopyTo(Yc);
|
||||
Z.CopyTo(Zc);
|
||||
coords = vtkm::cont::make_ArrayHandleCartesianProduct(Xc, Yc, Zc);
|
||||
vtkm::cont::CoordinateSystem coordSys("coordinates", coords);
|
||||
this->DataSet.AddCoordinateSystem(coordSys);
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -17,89 +17,15 @@ namespace vtkm
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKRectilinearGridReader : public VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKRectilinearGridReader : public VTKDataSetReaderBase
|
||||
{
|
||||
public:
|
||||
explicit VTKRectilinearGridReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
explicit VTKM_CONT VTKRectilinearGridReader(const char* fileName);
|
||||
explicit VTKM_CONT VTKRectilinearGridReader(const std::string& fileName);
|
||||
|
||||
private:
|
||||
virtual void Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_RECTILINEAR_GRID)
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read structured grid specific meta-data
|
||||
internal::parseAssert(tag == "DIMENSIONS");
|
||||
vtkm::Id3 dim;
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
|
||||
//Read the points.
|
||||
std::string dataType;
|
||||
std::size_t numPoints[3];
|
||||
vtkm::cont::VariantArrayHandle X, Y, Z;
|
||||
|
||||
// Always read coordinates as vtkm::FloatDefault
|
||||
std::string readDataType = vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name();
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[0] >> dataType >> std::ws;
|
||||
if (tag != "X_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("X_COORDINATES tag not found");
|
||||
X =
|
||||
this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[0], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[1] >> dataType >> std::ws;
|
||||
if (tag != "Y_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("Y_COORDINATES tag not found");
|
||||
Y =
|
||||
this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[1], 1);
|
||||
|
||||
this->DataFile->Stream >> tag >> numPoints[2] >> dataType >> std::ws;
|
||||
if (tag != "Z_COORDINATES")
|
||||
throw vtkm::io::ErrorIO("Z_COORDINATES tag not found");
|
||||
Z =
|
||||
this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[2], 1);
|
||||
|
||||
if (dim != vtkm::Id3(static_cast<vtkm::Id>(numPoints[0]),
|
||||
static_cast<vtkm::Id>(numPoints[1]),
|
||||
static_cast<vtkm::Id>(numPoints[2])))
|
||||
throw vtkm::io::ErrorIO("DIMENSIONS not equal to number of points");
|
||||
|
||||
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>
|
||||
coords;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Xc, Yc, Zc;
|
||||
X.CopyTo(Xc);
|
||||
Y.CopyTo(Yc);
|
||||
Z.CopyTo(Zc);
|
||||
coords = vtkm::cont::make_ArrayHandleCartesianProduct(Xc, Yc, Zc);
|
||||
vtkm::cont::CoordinateSystem coordSys("coordinates", coords);
|
||||
this->DataSet.AddCoordinateSystem(coordSys);
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
VTKM_CONT void Read() override;
|
||||
};
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
|
62
vtkm/io/VTKStructuredGridReader.cxx
Normal file
62
vtkm/io/VTKStructuredGridReader.cxx
Normal file
@ -0,0 +1,62 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKStructuredGridReader.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKStructuredGridReader::VTKStructuredGridReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKStructuredGridReader::VTKStructuredGridReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
void VTKStructuredGridReader::Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_GRID)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
std::string tag;
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read structured grid specific meta-data
|
||||
internal::parseAssert(tag == "DIMENSIONS");
|
||||
vtkm::Id3 dim;
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
|
||||
// Read the points
|
||||
this->DataFile->Stream >> tag;
|
||||
internal::parseAssert(tag == "POINTS");
|
||||
this->ReadPoints();
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -17,53 +17,15 @@ namespace vtkm
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKStructuredGridReader : public VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKStructuredGridReader : public VTKDataSetReaderBase
|
||||
{
|
||||
public:
|
||||
explicit VTKStructuredGridReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
explicit VTKM_CONT VTKStructuredGridReader(const char* fileName);
|
||||
explicit VTKM_CONT VTKStructuredGridReader(const std::string& fileName);
|
||||
|
||||
private:
|
||||
virtual void Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_GRID)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
std::string tag;
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read structured grid specific meta-data
|
||||
internal::parseAssert(tag == "DIMENSIONS");
|
||||
vtkm::Id3 dim;
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
|
||||
// Read the points
|
||||
this->DataFile->Stream >> tag;
|
||||
internal::parseAssert(tag == "POINTS");
|
||||
this->ReadPoints();
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
VTKM_CONT void Read() override;
|
||||
};
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
|
79
vtkm/io/VTKStructuredPointsReader.cxx
Normal file
79
vtkm/io/VTKStructuredPointsReader.cxx
Normal file
@ -0,0 +1,79 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKStructuredPointsReader.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKStructuredPointsReader::VTKStructuredPointsReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKStructuredPointsReader::VTKStructuredPointsReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
void VTKStructuredPointsReader::Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_POINTS)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
std::string tag;
|
||||
|
||||
// Read structured points specific meta-data
|
||||
vtkm::Id3 dim;
|
||||
vtkm::Vec3f_32 origin, spacing;
|
||||
|
||||
//Two ways the file can describe the dimensions. The proper way is by
|
||||
//using the DIMENSIONS keyword, but VisIt written VTK files spicify data
|
||||
//bounds instead, as a FIELD
|
||||
std::vector<vtkm::Float32> visitBounds;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields(&visitBounds);
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
if (visitBounds.empty())
|
||||
{
|
||||
internal::parseAssert(tag == "DIMENSIONS");
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
internal::parseAssert(tag == "SPACING");
|
||||
this->DataFile->Stream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
|
||||
if (!visitBounds.empty())
|
||||
{
|
||||
//now with spacing and physical bounds we can back compute the dimensions
|
||||
dim[0] = static_cast<vtkm::Id>((visitBounds[1] - visitBounds[0]) / spacing[0]);
|
||||
dim[1] = static_cast<vtkm::Id>((visitBounds[3] - visitBounds[2]) / spacing[1]);
|
||||
dim[2] = static_cast<vtkm::Id>((visitBounds[5] - visitBounds[4]) / spacing[2]);
|
||||
}
|
||||
|
||||
this->DataFile->Stream >> tag >> origin[0] >> origin[1] >> origin[2] >> std::ws;
|
||||
internal::parseAssert(tag == "ORIGIN");
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
this->DataSet.AddCoordinateSystem(
|
||||
vtkm::cont::CoordinateSystem("coordinates", dim, origin, spacing));
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::io
|
@ -17,70 +17,15 @@ namespace vtkm
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKStructuredPointsReader : public VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKStructuredPointsReader : public VTKDataSetReaderBase
|
||||
{
|
||||
public:
|
||||
explicit VTKStructuredPointsReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
explicit VTKM_CONT VTKStructuredPointsReader(const char* fileName);
|
||||
explicit VTKM_CONT VTKStructuredPointsReader(const std::string& fileName);
|
||||
|
||||
private:
|
||||
virtual void Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_POINTS)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
std::string tag;
|
||||
|
||||
// Read structured points specific meta-data
|
||||
vtkm::Id3 dim;
|
||||
vtkm::Vec3f_32 origin, spacing;
|
||||
|
||||
//Two ways the file can describe the dimensions. The proper way is by
|
||||
//using the DIMENSIONS keyword, but VisIt written VTK files spicify data
|
||||
//bounds instead, as a FIELD
|
||||
std::vector<vtkm::Float32> visitBounds;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields(&visitBounds);
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
if (visitBounds.empty())
|
||||
{
|
||||
internal::parseAssert(tag == "DIMENSIONS");
|
||||
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
internal::parseAssert(tag == "SPACING");
|
||||
this->DataFile->Stream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
|
||||
if (!visitBounds.empty())
|
||||
{
|
||||
//now with spacing and physical bounds we can back compute the dimensions
|
||||
dim[0] = static_cast<vtkm::Id>((visitBounds[1] - visitBounds[0]) / spacing[0]);
|
||||
dim[1] = static_cast<vtkm::Id>((visitBounds[3] - visitBounds[2]) / spacing[1]);
|
||||
dim[2] = static_cast<vtkm::Id>((visitBounds[5] - visitBounds[4]) / spacing[2]);
|
||||
}
|
||||
|
||||
this->DataFile->Stream >> tag >> origin[0] >> origin[1] >> origin[2] >> std::ws;
|
||||
internal::parseAssert(tag == "ORIGIN");
|
||||
|
||||
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
|
||||
this->DataSet.AddCoordinateSystem(
|
||||
vtkm::cont::CoordinateSystem("coordinates", dim, origin, spacing));
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
VTKM_CONT void Read() override;
|
||||
};
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
|
88
vtkm/io/VTKUnstructuredGridReader.cxx
Normal file
88
vtkm/io/VTKUnstructuredGridReader.cxx
Normal file
@ -0,0 +1,88 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/io/VTKUnstructuredGridReader.h>
|
||||
|
||||
#include <vtkm/io/internal/VTKDataSetCells.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKUnstructuredGridReader::VTKUnstructuredGridReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
VTKUnstructuredGridReader::VTKUnstructuredGridReader(const std::string& fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
void VTKUnstructuredGridReader::Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_UNSTRUCTURED_GRID)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read the points
|
||||
internal::parseAssert(tag == "POINTS");
|
||||
this->ReadPoints();
|
||||
|
||||
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
|
||||
|
||||
// Read the cellset
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
|
||||
|
||||
this->DataFile->Stream >> tag;
|
||||
internal::parseAssert(tag == "CELLS");
|
||||
|
||||
this->ReadCells(connectivity, numIndices);
|
||||
this->ReadShapes(shapes);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
|
||||
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
|
||||
this->SetCellsPermutation(permutation);
|
||||
|
||||
//DRP
|
||||
if (false) //vtkm::io::internal::IsSingleShape(shapes))
|
||||
{
|
||||
vtkm::cont::CellSetSingleType<> cellSet;
|
||||
cellSet.Fill(
|
||||
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
|
||||
vtkm::cont::CellSetExplicit<> cellSet;
|
||||
cellSet.Fill(numPoints, shapes, connectivity, offsets);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
}
|
||||
}
|
@ -17,77 +17,15 @@ namespace vtkm
|
||||
namespace io
|
||||
{
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
|
||||
|
||||
class VTKUnstructuredGridReader : public VTKDataSetReaderBase
|
||||
class VTKM_IO_EXPORT VTKUnstructuredGridReader : public VTKDataSetReaderBase
|
||||
{
|
||||
public:
|
||||
explicit VTKUnstructuredGridReader(const char* fileName)
|
||||
: VTKDataSetReaderBase(fileName)
|
||||
{
|
||||
}
|
||||
explicit VTKM_CONT VTKUnstructuredGridReader(const char* fileName);
|
||||
explicit VTKM_CONT VTKUnstructuredGridReader(const std::string& fileName);
|
||||
|
||||
private:
|
||||
virtual void Read()
|
||||
{
|
||||
if (this->DataFile->Structure != vtkm::io::internal::DATASET_UNSTRUCTURED_GRID)
|
||||
{
|
||||
throw vtkm::io::ErrorIO("Incorrect DataSet type");
|
||||
}
|
||||
|
||||
//We need to be able to handle VisIt files which dump Field data
|
||||
//at the top of a VTK file
|
||||
std::string tag;
|
||||
this->DataFile->Stream >> tag;
|
||||
if (tag == "FIELD")
|
||||
{
|
||||
this->ReadGlobalFields();
|
||||
this->DataFile->Stream >> tag;
|
||||
}
|
||||
|
||||
// Read the points
|
||||
internal::parseAssert(tag == "POINTS");
|
||||
this->ReadPoints();
|
||||
|
||||
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
|
||||
|
||||
// Read the cellset
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
|
||||
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
|
||||
|
||||
this->DataFile->Stream >> tag;
|
||||
internal::parseAssert(tag == "CELLS");
|
||||
|
||||
this->ReadCells(connectivity, numIndices);
|
||||
this->ReadShapes(shapes);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
|
||||
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
|
||||
this->SetCellsPermutation(permutation);
|
||||
|
||||
//DRP
|
||||
if (false) //vtkm::io::internal::IsSingleShape(shapes))
|
||||
{
|
||||
vtkm::cont::CellSetSingleType<> cellSet;
|
||||
cellSet.Fill(
|
||||
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
|
||||
vtkm::cont::CellSetExplicit<> cellSet;
|
||||
cellSet.Fill(numPoints, shapes, connectivity, offsets);
|
||||
this->DataSet.SetCellSet(cellSet);
|
||||
}
|
||||
|
||||
// Read points and cell attributes
|
||||
this->ReadAttributes();
|
||||
}
|
||||
VTKM_CONT void Read() override;
|
||||
};
|
||||
|
||||
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
|
||||
}
|
||||
} // namespace vtkm::io
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define vtk_m_io_internal_VTKDataSetTypes_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@ -238,4 +239,7 @@ inline void SelectTypeAndCall(DataType dtype,
|
||||
}
|
||||
} // namespace vtkm::io::internal
|
||||
|
||||
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::ColorChannel8)
|
||||
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::DummyBitType)
|
||||
|
||||
#endif // vtk_m_io_internal_VTKDataSetTypes_h
|
||||
|
@ -13,4 +13,6 @@ set(headers
|
||||
VTKDataSetReader.h
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
||||
vtkm_declare_headers(
|
||||
${headers}
|
||||
)
|
||||
|
@ -9,8 +9,20 @@
|
||||
##============================================================================
|
||||
|
||||
set(unit_tests
|
||||
UnitTestBOVDataSetReader.cxx
|
||||
UnitTestPixelTypes.cxx
|
||||
UnitTestVTKDataSetReader.cxx
|
||||
UnitTestVTKDataSetWriter.cxx
|
||||
)
|
||||
|
||||
set(unit_test_libraries vtkm_lodepng vtkm_io)
|
||||
|
||||
if(VTKm_ENABLE_RENDERING)
|
||||
set(unit_tests ${unit_tests}
|
||||
UnitTestImageWriter.cxx
|
||||
)
|
||||
|
||||
vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS)
|
||||
set(unit_test_libraries ${unit_test_libraries} vtkm_rendering)
|
||||
endif()
|
||||
|
||||
vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS LIBRARIES ${unit_test_libraries})
|
||||
|
70
vtkm/io/testing/UnitTestBOVDataSetReader.cxx
Normal file
70
vtkm/io/testing/UnitTestBOVDataSetReader.cxx
Normal file
@ -0,0 +1,70 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <string>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/io/BOVDataSetReader.h>
|
||||
#include <vtkm/io/ErrorIO.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline vtkm::cont::DataSet readBOVDataSet(const char* fname)
|
||||
{
|
||||
vtkm::cont::DataSet ds;
|
||||
vtkm::io::BOVDataSetReader reader(fname);
|
||||
try
|
||||
{
|
||||
ds = reader.ReadDataSet();
|
||||
}
|
||||
catch (vtkm::io::ErrorIO& e)
|
||||
{
|
||||
std::string message("Error reading ");
|
||||
message += fname;
|
||||
message += ", ";
|
||||
message += e.GetMessage();
|
||||
|
||||
VTKM_TEST_FAIL(message.c_str());
|
||||
}
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void TestReadingBOVDataSet()
|
||||
{
|
||||
std::string bovFile = vtkm::cont::testing::Testing::GetTestDataBasePath() + "/uniform/noise.bov";
|
||||
|
||||
auto const& ds = readBOVDataSet(bovFile.data());
|
||||
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 1, "Incorrect number of fields");
|
||||
// See the .bov file: DATA SIZE: 50 50 50
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 50 * 50 * 50, "Incorrect number of points");
|
||||
VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 50 * 50 * 50,
|
||||
"Incorrect number of points (from cell set)");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCells() == 49 * 49 * 49, "Incorrect number of cells");
|
||||
// See the .bov file: VARIABLE: "var"
|
||||
VTKM_TEST_ASSERT(ds.HasField("var"), "Should have field 'var', but does not.");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 1, "There is only one field in noise.bov");
|
||||
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
|
||||
"There is only one coordinate system in noise.bov");
|
||||
|
||||
auto const& field = ds.GetField("var");
|
||||
// I'm pretty sure that all .bov files have their fields associated with points . . .
|
||||
VTKM_TEST_ASSERT(field.GetAssociation() == vtkm::cont::Field::Association::POINTS,
|
||||
"The field should be associated with points.");
|
||||
}
|
||||
|
||||
|
||||
int UnitTestBOVDataSetReader(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(TestReadingBOVDataSet, argc, argv);
|
||||
}
|
165
vtkm/io/testing/UnitTestImageWriter.cxx
Normal file
165
vtkm/io/testing/UnitTestImageWriter.cxx
Normal file
@ -0,0 +1,165 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/io/ImageReader.h>
|
||||
#include <vtkm/io/ImageWriter.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
#include <vtkm/rendering/Canvas.h>
|
||||
#include <vtkm/rendering/Color.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace vtkm::io;
|
||||
using namespace vtkm::rendering;
|
||||
|
||||
template <typename PixelType>
|
||||
void TestFilledImage(vtkm::cont::DataSet& dataSet,
|
||||
const std::string& fieldName,
|
||||
const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
VTKM_TEST_ASSERT(dataSet.HasPointField(fieldName), "Point Field Not Found: " + fieldName);
|
||||
|
||||
auto pointField = dataSet.GetPointField(fieldName);
|
||||
VTKM_TEST_ASSERT(pointField.GetNumberOfValues() == canvas.GetWidth() * canvas.GetHeight(),
|
||||
"wrong image dimensions");
|
||||
VTKM_TEST_ASSERT(pointField.GetData().template IsType<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>(),
|
||||
"wrong ArrayHandle type");
|
||||
auto pixelPortal =
|
||||
pointField.GetData().template Cast<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>().ReadPortal();
|
||||
|
||||
auto colorPortal = canvas.GetColorBuffer().ReadPortal();
|
||||
for (vtkm::Id y = 0; y < canvas.GetHeight(); y++)
|
||||
{
|
||||
std::ostringstream row;
|
||||
row << "[";
|
||||
for (vtkm::Id x = 0; x < canvas.GetWidth(); x++)
|
||||
{
|
||||
auto tuple = colorPortal.Get(y * canvas.GetWidth() + x);
|
||||
auto pixelVec = PixelType(pixelPortal.Get(y * canvas.GetWidth() + x));
|
||||
std::ostringstream data;
|
||||
data << pixelVec << ":" << PixelType(tuple) << std::endl;
|
||||
VTKM_TEST_ASSERT(pixelVec == PixelType(tuple),
|
||||
"Stored pixel did not match canvas value" + data.str());
|
||||
row << pixelVec << ",";
|
||||
}
|
||||
row << "]";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PixelType>
|
||||
void TestCreateImageDataSet(BaseImageReader& reader, const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
auto dataSet = reader.CreateImageDataSet(canvas);
|
||||
TestFilledImage<PixelType>(dataSet, reader.GetPointFieldName(), canvas);
|
||||
}
|
||||
|
||||
template <typename PixelType>
|
||||
void TestReadAndWritePNG(const vtkm::rendering::Canvas& canvas, std::string image)
|
||||
{
|
||||
auto pngReader = PNGReader();
|
||||
auto pngWriter = PNGWriter();
|
||||
vtkm::cont::DataSet dataSet;
|
||||
bool throws = false;
|
||||
try
|
||||
{
|
||||
pngWriter.WriteToFile(image, dataSet);
|
||||
}
|
||||
catch (const vtkm::cont::ErrorBadValue&)
|
||||
{
|
||||
throws = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(throws, "Fill Image did not throw with empty data");
|
||||
|
||||
dataSet = pngReader.CreateImageDataSet(canvas);
|
||||
pngWriter.WriteToFile(image, dataSet);
|
||||
dataSet = pngReader.ReadFromFile(image);
|
||||
pngWriter.WriteToFile(image, dataSet);
|
||||
dataSet = pngReader.ReadFromFile(image);
|
||||
TestFilledImage<PixelType>(dataSet, pngReader.GetPointFieldName(), canvas);
|
||||
}
|
||||
|
||||
template <const vtkm::Id BitDepth>
|
||||
void TestReadAndWritePNM(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
using PixelType = RGBPixel<BitDepth>;
|
||||
PNMWriter ppmWriter((1 << BitDepth) - 1);
|
||||
PNMReader ppmReader((1 << BitDepth) - 1);
|
||||
vtkm::cont::DataSet dataSet;
|
||||
bool throws = false;
|
||||
try
|
||||
{
|
||||
ppmWriter.WriteToFile("ppmTestFile" + std::to_string(BitDepth) + "bit.ppm", dataSet);
|
||||
}
|
||||
catch (const vtkm::cont::ErrorBadValue&)
|
||||
{
|
||||
throws = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(throws, "Fill Image did not throw with empty data");
|
||||
|
||||
dataSet = ppmReader.CreateImageDataSet(canvas);
|
||||
ppmWriter.WriteToFile("ppmTestFile.ppm", dataSet);
|
||||
dataSet = ppmReader.ReadFromFile("ppmTestFile.ppm");
|
||||
ppmWriter.WriteToFile("ppmTestFile2.ppm", dataSet);
|
||||
dataSet = ppmReader.ReadFromFile("ppmTestFile2.ppm");
|
||||
TestFilledImage<PixelType>(dataSet, ppmReader.GetPointFieldName(), canvas);
|
||||
}
|
||||
|
||||
|
||||
void TestBaseImageMethods(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
auto reader = PNGReader();
|
||||
TestCreateImageDataSet<RGBPixel_8>(reader, canvas);
|
||||
TestCreateImageDataSet<RGBPixel_16>(reader, canvas);
|
||||
TestCreateImageDataSet<GreyPixel_8>(reader, canvas);
|
||||
TestCreateImageDataSet<GreyPixel_16>(reader, canvas);
|
||||
}
|
||||
|
||||
void TestPNMImage(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
TestReadAndWritePNM<8>(canvas);
|
||||
TestReadAndWritePNM<16>(canvas);
|
||||
}
|
||||
|
||||
void TestPNGImage(const vtkm::rendering::Canvas& canvas)
|
||||
{
|
||||
TestReadAndWritePNG<RGBPixel_8>(canvas, "pngRGB8Test.png");
|
||||
TestReadAndWritePNG<RGBPixel_16>(canvas, "pngRGB16Test.png");
|
||||
TestReadAndWritePNG<GreyPixel_8>(canvas, "pngGrey8Test.png");
|
||||
TestReadAndWritePNG<GreyPixel_16>(canvas, "pngGrey16Test.png");
|
||||
}
|
||||
|
||||
void TestImage()
|
||||
{
|
||||
vtkm::rendering::Canvas canvas(16, 16);
|
||||
canvas.SetBackgroundColor(vtkm::rendering::Color::red);
|
||||
canvas.Initialize();
|
||||
canvas.Activate();
|
||||
canvas.Clear();
|
||||
// Line from top left to bottom right, ensures correct transposedness
|
||||
canvas.AddLine(-0.9, 0.9, 0.9, -0.9, 2.0f, vtkm::rendering::Color::black);
|
||||
vtkm::Bounds colorBarBounds(-0.8, -0.6, -0.8, 0.8, 0, 0);
|
||||
canvas.AddColorBar(colorBarBounds, vtkm::cont::ColorTable("inferno"), false);
|
||||
canvas.BlendBackground();
|
||||
canvas.SaveAs("baseline.ppm");
|
||||
|
||||
TestBaseImageMethods(canvas);
|
||||
TestPNMImage(canvas);
|
||||
TestPNGImage(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
int UnitTestImageWriter(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(TestImage, argc, argv);
|
||||
}
|
176
vtkm/io/testing/UnitTestPixelTypes.cxx
Normal file
176
vtkm/io/testing/UnitTestPixelTypes.cxx
Normal file
@ -0,0 +1,176 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
#include <vtkm/io/PixelTypes.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace vtkm::io;
|
||||
|
||||
template <typename PixelType>
|
||||
void TestPixelTypeOperations(const vtkm::UInt16& numPixels = 10)
|
||||
{
|
||||
using ValType = typename PixelType::ComponentType;
|
||||
const ValType numBytes = static_cast<ValType>(PixelType::NUM_BYTES);
|
||||
const ValType numChannels = static_cast<ValType>(PixelType::NUM_CHANNELS);
|
||||
|
||||
// Fill in the imageData through FillPixelData
|
||||
std::vector<unsigned char> imageData(numPixels * numBytes * numChannels);
|
||||
std::vector<PixelType> pixelVector(numPixels);
|
||||
for (ValType i = 0; i < numPixels; i++)
|
||||
{
|
||||
ValType pixelVal = 0;
|
||||
for (ValType j = 0, shift = numBytes - 1; j < numBytes; shift--, j++)
|
||||
{
|
||||
pixelVal += (i + j) << (shift * 8);
|
||||
}
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "pixelVal[" << i << "] = " << pixelVal);
|
||||
|
||||
PixelType pixel(pixelVal);
|
||||
pixelVector[i] = pixel;
|
||||
pixel.FillImageAtIndexWithPixel(imageData.data(), i);
|
||||
}
|
||||
|
||||
// Test that the imageData values were set correctly
|
||||
VTKM_TEST_ASSERT(static_cast<vtkm::Id>(imageData.size()) == numPixels * numChannels * numBytes,
|
||||
"Wrong number of elements");
|
||||
for (ValType j = 0; j < numBytes; j++)
|
||||
{
|
||||
for (ValType i = 0; i < numPixels; i++)
|
||||
{
|
||||
for (ValType k = numChannels * i; k < numChannels * i + numChannels; k++)
|
||||
{
|
||||
VTKM_TEST_ASSERT(imageData[k * numBytes + j] == i + j,
|
||||
"Wrong value at index[" + std::to_string(k * numBytes + j) + "]: " +
|
||||
std::to_string(imageData[k * numBytes + j]) + " != " +
|
||||
std::to_string(i + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that a pixel can be retreived from the filled out data vector
|
||||
for (vtkm::Id i = 0; i < numPixels; i++)
|
||||
{
|
||||
VTKM_TEST_ASSERT(pixelVector[static_cast<typename std::vector<PixelType>::size_type>(i)] ==
|
||||
PixelType(imageData.data(), i),
|
||||
"Incorrect pixel value");
|
||||
}
|
||||
}
|
||||
|
||||
void TestDifferentPixelTypes()
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 8 bit RGB");
|
||||
TestPixelTypeOperations<RGBPixel_8>();
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 8 bit Grey");
|
||||
TestPixelTypeOperations<GreyPixel_8>();
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 16 bit RGB");
|
||||
TestPixelTypeOperations<RGBPixel_16>();
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 16 bit Grey");
|
||||
TestPixelTypeOperations<GreyPixel_16>();
|
||||
}
|
||||
|
||||
void TestGreyPixelConstructors()
|
||||
{
|
||||
std::vector<unsigned char> initData{ 1, 2 };
|
||||
|
||||
auto pixel_1 = GreyPixel_8(1);
|
||||
auto pixel_2 = GreyPixel_8(1);
|
||||
auto pixel_3 = GreyPixel_8(2);
|
||||
auto pixel_4 = GreyPixel_8(initData.data(), 0);
|
||||
auto pixel_5 = GreyPixel_8(initData.data(), 1);
|
||||
auto pixel_6 = GreyPixel_16(initData.data(), 0);
|
||||
|
||||
float color = 10.0f / GreyPixel_16::MAX_COLOR_VALUE;
|
||||
auto pixel_7 = GreyPixel_16({ color, color, color, 5 });
|
||||
|
||||
VTKM_TEST_ASSERT(vtkm::UInt16(1) == pixel_1[0], "Type mis-match");
|
||||
VTKM_TEST_ASSERT(vtkm::FloatDefault(0) == pixel_1.Diff(pixel_2), "Incorrect Diff");
|
||||
VTKM_TEST_ASSERT(vtkm::FloatDefault(1) == pixel_1.Diff(pixel_3), "Incorrect Diff");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec4f_32(1.0f / 255, 1.0f / 255, 1.0f / 255, 1) == pixel_1.ToVec4f(),
|
||||
"Incorrect Conversion");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt8, 1>(1) == pixel_4, "Bad 1st value 8 bit construct");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt8, 1>(2) == pixel_5, "Bad 2nd value 8 bit construct");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt16, 1>(258) == pixel_6, "Bad 16 bit construct");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec4f_32(258.0f / 65535, 258.0f / 65535, 258.0f / 65535, 1) ==
|
||||
pixel_6.ToVec4f(),
|
||||
"Incorrect Conversion");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt16, 1>(10) == pixel_7, "Bad Vec4f_32 construction");
|
||||
|
||||
VTKM_TEST_ASSERT(GreyPixel<16>::BIT_DEPTH == 16, "Bad BitDepth");
|
||||
VTKM_TEST_ASSERT(GreyPixel<16>::NUM_BYTES == 2, "Bad NumBytes");
|
||||
VTKM_TEST_ASSERT(GreyPixel<16>::MAX_COLOR_VALUE == 65535, "Bad NumBytes");
|
||||
VTKM_TEST_ASSERT(GreyPixel<16>::NUM_CHANNELS == 1, "Bad NumChannels");
|
||||
VTKM_TEST_ASSERT(GreyPixel<16>::BYTES_PER_PIXEL == 2, "Wrong Pixel Byte distance");
|
||||
|
||||
// Shouldn't compile
|
||||
// auto pixel_4 = RGBPixel_8(1, 1, 1);
|
||||
// pixel_1.Diff(pixel_4);
|
||||
}
|
||||
|
||||
void TestRGBPixelConstructors()
|
||||
{
|
||||
std::vector<unsigned char> initData{ 1, 2, 3, 4, 5, 6 };
|
||||
|
||||
auto pixel_1 = RGBPixel_8(1, 1, 1);
|
||||
auto pixel_2 = RGBPixel_8(1, 1, 1);
|
||||
auto pixel_3 = RGBPixel_8(1);
|
||||
auto pixel_4 = RGBPixel_8(2, 2, 2);
|
||||
auto pixel_5 = RGBPixel_8(initData.data(), 0);
|
||||
auto pixel_6 = RGBPixel_8(initData.data(), 1);
|
||||
auto pixel_7 = RGBPixel_16(initData.data(), 0);
|
||||
|
||||
float color = 10.0f / RGBPixel_16::MAX_COLOR_VALUE;
|
||||
auto pixel_8 = RGBPixel_16({ color, color, color, 5 });
|
||||
|
||||
VTKM_TEST_ASSERT(vtkm::Vec3ui_8(1, 1, 1) == pixel_1, "Type mis-match");
|
||||
VTKM_TEST_ASSERT(vtkm::FloatDefault(0) == pixel_1.Diff(pixel_2), "Incorrect Diff");
|
||||
VTKM_TEST_ASSERT(vtkm::FloatDefault(0) == pixel_1.Diff(pixel_3), "Incorrect Diff");
|
||||
VTKM_TEST_ASSERT(vtkm::FloatDefault(3) == pixel_1.Diff(pixel_4), "Incorrect Diff");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec4f_32(1.0f / 255, 1.0f / 255, 1.0f / 255, 1) == pixel_1.ToVec4f(),
|
||||
"Incorrect Conversion");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec3ui_8(1, 2, 3) == pixel_5, "Bad 1st value 8 bit construct");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec3ui_8(4, 5, 6) == pixel_6, "Bad 2nd value 8 bit construct");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec3ui_16(258, 772, 1286) == pixel_7, "Bad 16 bit construct");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec4f_32(258.0f / 65535, 772.0f / 65535, 1286.0f / 65535, 1) ==
|
||||
pixel_7.ToVec4f(),
|
||||
"Incorrect Conversion");
|
||||
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt16, 3>(10, 10, 10) == pixel_8, "Bad Vec4f_32 construction");
|
||||
|
||||
VTKM_TEST_ASSERT(RGBPixel<16>::BIT_DEPTH == 16, "Bad BitDepth");
|
||||
VTKM_TEST_ASSERT(RGBPixel<16>::NUM_BYTES == 2, "Bad NumBytes");
|
||||
VTKM_TEST_ASSERT(RGBPixel<16>::MAX_COLOR_VALUE == 65535, "Bad NumBytes");
|
||||
VTKM_TEST_ASSERT(RGBPixel<16>::NUM_CHANNELS == 3, "Bad NumChannels");
|
||||
VTKM_TEST_ASSERT(RGBPixel<16>::BYTES_PER_PIXEL == 6, "Wrong Pixel Byte distance");
|
||||
|
||||
// Shouldn't compile
|
||||
// auto pixel_8 = GreyPixel_8(1);
|
||||
// pixel_1.Diff(pixel_8);
|
||||
}
|
||||
|
||||
void TestPixelTypes()
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing RGBPixel");
|
||||
TestRGBPixelConstructors();
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing GreyPixel");
|
||||
TestGreyPixelConstructors();
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing Pixel Types");
|
||||
TestDifferentPixelTypes();
|
||||
}
|
||||
|
||||
int UnitTestPixelTypes(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(TestPixelTypes, argc, argv);
|
||||
}
|
@ -10,6 +10,8 @@
|
||||
|
||||
set(headers
|
||||
VTKDataSetWriter.h
|
||||
)
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
||||
vtkm_declare_headers(
|
||||
${headers}
|
||||
)
|
||||
|
@ -164,15 +164,17 @@ public:
|
||||
typename VisitArrayType,
|
||||
typename ThreadToOutArrayType,
|
||||
typename InputDomainType>
|
||||
VTKM_EXEC vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType> GetThreadIndices(
|
||||
vtkm::Id threadIndex,
|
||||
VTKM_EXEC vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
|
||||
vtkm::exec::arg::CustomScatterOrMaskTag>
|
||||
GetThreadIndices(vtkm::Id threadIndex,
|
||||
const OutToInArrayType& outToIn,
|
||||
const VisitArrayType& visit,
|
||||
const ThreadToOutArrayType& threadToOut,
|
||||
const InputDomainType& connectivity) const
|
||||
{
|
||||
const vtkm::Id outIndex = threadToOut.Get(threadIndex);
|
||||
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>(
|
||||
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
|
||||
vtkm::exec::arg::CustomScatterOrMaskTag>(
|
||||
threadIndex, outToIn.Get(outIndex), visit.Get(outIndex), outIndex, connectivity);
|
||||
}
|
||||
|
||||
@ -199,7 +201,10 @@ public:
|
||||
typename InputDomainType,
|
||||
bool S = IsScatterIdentity,
|
||||
bool M = IsMaskNone>
|
||||
VTKM_EXEC EnableFnWhen<S && M, vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>>
|
||||
VTKM_EXEC EnableFnWhen<
|
||||
S && M,
|
||||
vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
|
||||
vtkm::exec::arg::DefaultScatterAndMaskTag>>
|
||||
GetThreadIndices(vtkm::Id threadIndex1D,
|
||||
const vtkm::Id3& threadIndex3D,
|
||||
const OutToInArrayType& vtkmNotUsed(outToIn),
|
||||
@ -207,7 +212,8 @@ public:
|
||||
const ThreadToOutArrayType& vtkmNotUsed(threadToOut),
|
||||
const InputDomainType& connectivity) const
|
||||
{
|
||||
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>(
|
||||
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
|
||||
vtkm::exec::arg::DefaultScatterAndMaskTag>(
|
||||
threadIndex3D, threadIndex1D, connectivity);
|
||||
}
|
||||
|
||||
@ -219,7 +225,10 @@ public:
|
||||
typename InputDomainType,
|
||||
bool S = IsScatterIdentity,
|
||||
bool M = IsMaskNone>
|
||||
VTKM_EXEC EnableFnWhen<!(S && M), vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>>
|
||||
VTKM_EXEC
|
||||
EnableFnWhen<!(S && M),
|
||||
vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
|
||||
vtkm::exec::arg::CustomScatterOrMaskTag>>
|
||||
GetThreadIndices(vtkm::Id threadIndex1D,
|
||||
const vtkm::Id3& threadIndex3D,
|
||||
const OutToInArrayType& outToIn,
|
||||
@ -228,7 +237,9 @@ public:
|
||||
const InputDomainType& connectivity) const
|
||||
{
|
||||
const vtkm::Id outIndex = threadToOut.Get(threadIndex1D);
|
||||
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>(threadIndex3D,
|
||||
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
|
||||
vtkm::exec::arg::CustomScatterOrMaskTag>(
|
||||
threadIndex3D,
|
||||
threadIndex1D,
|
||||
outToIn.Get(outIndex),
|
||||
visit.Get(outIndex),
|
||||
|
@ -88,8 +88,6 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
//#define DEBUG_PRINT 1
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@ -103,9 +101,10 @@ void DebugPrint(const char* msg, vtkm::cont::ArrayHandle<U>& array)
|
||||
{
|
||||
vtkm::Id count = 20;
|
||||
count = std::min(count, array.GetNumberOfValues());
|
||||
auto portal = array.ReadPortal();
|
||||
std::cout << std::setw(15) << msg << ": ";
|
||||
for (vtkm::Id i = 0; i < count; i++)
|
||||
std::cout << std::setprecision(3) << std::setw(5) << array.ReadPortal().Get(i) << " ";
|
||||
std::cout << std::setprecision(3) << std::setw(5) << portal.Get(i) << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
@ -114,9 +113,10 @@ void DebugPrint(const char* msg, vtkm::cont::ArrayHandleReverse<vtkm::cont::Arra
|
||||
{
|
||||
vtkm::Id count = 20;
|
||||
count = std::min(count, array.GetNumberOfValues());
|
||||
auto portal = array.ReadPortal();
|
||||
std::cout << std::setw(15) << msg << ": ";
|
||||
for (vtkm::Id i = 0; i < count; i++)
|
||||
std::cout << std::setw(5) << array.ReadPortal().Get(i) << " ";
|
||||
std::cout << std::setw(5) << portal.Get(i) << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,10 @@ struct PointGradient : public vtkm::worklet::WorkletVisitPointsWithCells
|
||||
const WholeFieldIn& inputField,
|
||||
GradientOutType& outputGradient) const
|
||||
{
|
||||
using CellThreadIndices = vtkm::exec::arg::ThreadIndicesTopologyMap<CellSetInType>;
|
||||
// Use optimized ThreadIndicesTopologyMap
|
||||
using CellThreadIndices =
|
||||
vtkm::exec::arg::ThreadIndicesTopologyMap<CellSetInType,
|
||||
vtkm::exec::arg::DefaultScatterAndMaskTag>;
|
||||
|
||||
using ValueType = typename WholeFieldIn::ValueType;
|
||||
using CellShapeTag = typename CellSetInType::CellShapeTag;
|
||||
|
@ -191,16 +191,18 @@ void TestCellGradientUniform3DWithVectorField2()
|
||||
{ { 10.025, 10.025, 10.025 }, { 30.075, 30.075, 30.075 }, { 60.175, 60.175, 60.175 } }
|
||||
};
|
||||
|
||||
auto vorticityPortal = extraOutput.Vorticity.ReadPortal();
|
||||
auto divergencePortal = extraOutput.Divergence.ReadPortal();
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
vtkm::Vec<vtkm::Vec3f_64, 3> eg = expected_gradients[i];
|
||||
|
||||
vtkm::Float64 d = extraOutput.Divergence.ReadPortal().Get(i);
|
||||
vtkm::Float64 d = divergencePortal.Get(i);
|
||||
VTKM_TEST_ASSERT(test_equal((eg[0][0] + eg[1][1] + eg[2][2]), d),
|
||||
"Wrong result for Divergence on 3D uniform data");
|
||||
|
||||
vtkm::Vec3f_64 ev(eg[1][2] - eg[2][1], eg[2][0] - eg[0][2], eg[0][1] - eg[1][0]);
|
||||
vtkm::Vec3f_64 v = extraOutput.Vorticity.ReadPortal().Get(i);
|
||||
vtkm::Vec3f_64 v = vorticityPortal.Get(i);
|
||||
VTKM_TEST_ASSERT(test_equal(ev, v), "Wrong result for Vorticity on 3D uniform data");
|
||||
}
|
||||
}
|
||||
@ -220,9 +222,10 @@ void TestCellGradientExplicit()
|
||||
result = gradient.Run(dataSet.GetCellSet(), dataSet.GetCoordinateSystem(), input);
|
||||
|
||||
vtkm::Vec3f_32 expected[2] = { { 10.f, 10.1f, 0.0f }, { 10.f, 10.1f, -0.0f } };
|
||||
auto resultPortal = result.ReadPortal();
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
|
||||
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
|
||||
"Wrong result for CellGradient worklet on 3D explicit data");
|
||||
}
|
||||
}
|
||||
|
@ -36,9 +36,11 @@ bool TestArrayHandle(const vtkm::cont::ArrayHandle<T, Storage>& ah,
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ahPortal = ah.ReadPortal();
|
||||
auto expectedPortal = expected.ReadPortal();
|
||||
for (vtkm::Id i = 0; i < size; ++i)
|
||||
{
|
||||
if (ah.ReadPortal().Get(i) != expected.ReadPortal().Get(i))
|
||||
if (ahPortal.Get(i) != expectedPortal.Get(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user